Add ast_grep tool: structural code search via ast-grep
AST-level pattern matching — find code by structure, not text.
e.g. find all `if let Some($X) = $Y { $$$BODY }` patterns.
Supports C, Rust, Python, JS/TS, Go, and 20+ languages.
Gracefully errors if sg binary isn't installed.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
parent
c53c4f9071
commit
ec7e11db56
5 changed files with 552 additions and 5 deletions
|
|
@ -1 +0,0 @@
|
||||||
{"sessionId":"463c6050-b49f-4509-9d4b-4596af79a90e","pid":61703,"acquiredAt":1775698574304}
|
|
||||||
403
Cargo.lock
generated
403
Cargo.lock
generated
|
|
@ -126,6 +126,56 @@ version = "1.0.102"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ast-grep-core"
|
||||||
|
version = "0.42.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0e4ae49b5c42878311768f4cdd576ef470c6e45c3105d558af928fd04ac8c588"
|
||||||
|
dependencies = [
|
||||||
|
"bit-set 0.10.0",
|
||||||
|
"regex",
|
||||||
|
"thiserror 2.0.18",
|
||||||
|
"tree-sitter",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ast-grep-language"
|
||||||
|
version = "0.42.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fccbced91e848baf5d25278972bfc18b2248c38e411dcfeb65e431a5b530a5c6"
|
||||||
|
dependencies = [
|
||||||
|
"ast-grep-core",
|
||||||
|
"ignore",
|
||||||
|
"serde",
|
||||||
|
"tree-sitter",
|
||||||
|
"tree-sitter-bash",
|
||||||
|
"tree-sitter-c",
|
||||||
|
"tree-sitter-c-sharp",
|
||||||
|
"tree-sitter-cpp",
|
||||||
|
"tree-sitter-css",
|
||||||
|
"tree-sitter-dart",
|
||||||
|
"tree-sitter-elixir",
|
||||||
|
"tree-sitter-go",
|
||||||
|
"tree-sitter-haskell",
|
||||||
|
"tree-sitter-hcl",
|
||||||
|
"tree-sitter-html",
|
||||||
|
"tree-sitter-java",
|
||||||
|
"tree-sitter-javascript",
|
||||||
|
"tree-sitter-json",
|
||||||
|
"tree-sitter-kotlin-sg",
|
||||||
|
"tree-sitter-lua",
|
||||||
|
"tree-sitter-nix",
|
||||||
|
"tree-sitter-php",
|
||||||
|
"tree-sitter-python",
|
||||||
|
"tree-sitter-ruby",
|
||||||
|
"tree-sitter-rust",
|
||||||
|
"tree-sitter-scala",
|
||||||
|
"tree-sitter-solidity",
|
||||||
|
"tree-sitter-swift",
|
||||||
|
"tree-sitter-typescript",
|
||||||
|
"tree-sitter-yaml",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atomic"
|
name = "atomic"
|
||||||
version = "0.6.1"
|
version = "0.6.1"
|
||||||
|
|
@ -196,7 +246,16 @@ version = "0.5.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
|
checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit-vec",
|
"bit-vec 0.6.3",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bit-set"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09ec2f926cc3060f09db9ebc5b52823d85268d24bb917e472c0c4bea35780a7d"
|
||||||
|
dependencies = [
|
||||||
|
"bit-vec 0.9.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -205,6 +264,15 @@ version = "0.6.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bit-vec"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
|
|
@ -238,6 +306,16 @@ dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bstr"
|
||||||
|
version = "1.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.20.2"
|
version = "3.20.2"
|
||||||
|
|
@ -908,7 +986,7 @@ version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2"
|
checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit-set",
|
"bit-set 0.5.3",
|
||||||
"regex",
|
"regex",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -1152,6 +1230,19 @@ version = "0.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
|
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "globset"
|
||||||
|
version = "0.4.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"bstr",
|
||||||
|
"log",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.12.3"
|
version = "0.12.3"
|
||||||
|
|
@ -1302,6 +1393,22 @@ version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ignore"
|
||||||
|
version = "0.4.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-deque",
|
||||||
|
"globset",
|
||||||
|
"log",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"same-file",
|
||||||
|
"walkdir",
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.13.1"
|
version = "2.13.1"
|
||||||
|
|
@ -1983,6 +2090,8 @@ name = "poc-memory"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"ast-grep-core",
|
||||||
|
"ast-grep-language",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"bincode",
|
"bincode",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
|
@ -2028,6 +2137,7 @@ dependencies = [
|
||||||
"tui-markdown",
|
"tui-markdown",
|
||||||
"tui-textarea-2",
|
"tui-textarea-2",
|
||||||
"uuid",
|
"uuid",
|
||||||
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2634,6 +2744,7 @@ version = "1.0.149"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
"itoa",
|
"itoa",
|
||||||
"memchr",
|
"memchr",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
@ -2765,6 +2876,12 @@ version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "streaming-iterator"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b2231b7c3057d5e4ad0156fb3dc807d900806020c5ffa3ee6ff2c8c76fb8520"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
|
|
@ -3105,6 +3222,286 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter"
|
||||||
|
version = "0.26.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "887bd495d0582c5e3e0d8ece2233666169fa56a9644d172fc22ad179ab2d0538"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"regex",
|
||||||
|
"regex-syntax",
|
||||||
|
"serde_json",
|
||||||
|
"streaming-iterator",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-bash"
|
||||||
|
version = "0.25.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e5ec769279cc91b561d3df0d8a5deb26b0ad40d183127f409494d6d8fc53062"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-c"
|
||||||
|
version = "0.24.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a3aad8f0129083a59fe8596157552d2bb7148c492d44c21558d68ca1c722707"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-c-sharp"
|
||||||
|
version = "0.23.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "67f06accca7b45351758663b8215089e643d53bd9a660ce0349314263737fcb0"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-cpp"
|
||||||
|
version = "0.23.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df2196ea9d47b4ab4a31b9297eaa5a5d19a0b121dceb9f118f6790ad0ab94743"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-css"
|
||||||
|
version = "0.25.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a5cbc5e18f29a2c6d6435891f42569525cf95435a3e01c2f1947abcde178686f"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-dart"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bba6bf8675e6fe92ba6da371a5497ee5df2a04d2c503e3599c8ad771f6f1faec"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-elixir"
|
||||||
|
version = "0.3.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "66dd064a762ed95bfc29857fa3cb7403bb1e5cb88112de0f6341b7e47284ba40"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-go"
|
||||||
|
version = "0.25.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c8560a4d2f835cc0d4d2c2e03cbd0dde2f6114b43bc491164238d333e28b16ea"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-haskell"
|
||||||
|
version = "0.23.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "977c51e504548cba13fc27cb5a2edab2124cf6716a1934915d07ab99523b05a4"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-hcl"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a7b2cc3d7121553b84309fab9d11b3ff3d420403eef9ae50f9fd1cd9d9cf012"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-html"
|
||||||
|
version = "0.23.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "261b708e5d92061ede329babaaa427b819329a9d427a1d710abb0f67bbef63ee"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-java"
|
||||||
|
version = "0.23.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0aa6cbcdc8c679b214e616fd3300da67da0e492e066df01bcf5a5921a71e90d6"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-javascript"
|
||||||
|
version = "0.25.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68204f2abc0627a90bdf06e605f5c470aa26fdcb2081ea553a04bdad756693f5"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-json"
|
||||||
|
version = "0.23.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "86a5d6b3ea17e06e7a34aabeadd68f5866c0d0f9359155d432095f8b751865e4"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-kotlin-sg"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a0e175b7530765d1e36ad234a7acaa8b2a3316153f239d724376c7ee5e8d8e98"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-language"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "009994f150cc0cd50ff54917d5bc8bffe8cad10ca10d81c34da2ec421ae61782"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-lua"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8daaf5f4235188a58603c39760d5fa5d4b920d36a299c934adddae757f32a10c"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-nix"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4952a9733f3a98f6683a0ccd1035d84ab7a52f7e84eeed58548d86765ad92de3"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-php"
|
||||||
|
version = "0.24.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d8c17c3ab69052c5eeaa7ff5cd972dd1bc25d1b97ee779fec391ad3b5df5592"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-python"
|
||||||
|
version = "0.25.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6bf85fd39652e740bf60f46f4cda9492c3a9ad75880575bf14960f775cb74a1c"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-ruby"
|
||||||
|
version = "0.23.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "be0484ea4ef6bb9c575b4fdabde7e31340a8d2dbc7d52b321ac83da703249f95"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-rust"
|
||||||
|
version = "0.24.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "439e577dbe07423ec2582ac62c7531120dbfccfa6e5f92406f93dd271a120e45"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-scala"
|
||||||
|
version = "0.25.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "83079f50ea7d03e0faf6be6260ed97538e6df7349ec3cbcbf5771f7b38e3c8b7"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-solidity"
|
||||||
|
version = "1.2.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4eacf8875b70879f0cb670c60b233ad0b68752d9e1474e6c3ef168eea8a90b25"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-swift"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4ef216011c3e3df4fa864736f347cb8d509b1066cf0c8549fb1fd81ac9832e59"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-typescript"
|
||||||
|
version = "0.23.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c5f76ed8d947a75cc446d5fccd8b602ebf0cde64ccf2ffa434d873d7a575eff"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-yaml"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "53c223db85f05e34794f065454843b0668ebc15d240ada63e2b5939f43ce7c97"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "try-lock"
|
name = "try-lock"
|
||||||
version = "0.2.5"
|
version = "0.2.5"
|
||||||
|
|
@ -3489,7 +3886,7 @@ version = "0.1.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,10 @@ memmap2 = "0.9"
|
||||||
peg = "0.8"
|
peg = "0.8"
|
||||||
paste = "1"
|
paste = "1"
|
||||||
|
|
||||||
|
ast-grep-core = "0.42"
|
||||||
|
ast-grep-language = { version = "0.42", features = ["builtin-parser"] }
|
||||||
|
walkdir = "2"
|
||||||
|
|
||||||
redb = "4"
|
redb = "4"
|
||||||
rkyv = { version = "0.7", features = ["validation", "std"] }
|
rkyv = { version = "0.7", features = ["validation", "std"] }
|
||||||
|
|
||||||
|
|
|
||||||
146
src/agent/tools/ast_grep.rs
Normal file
146
src/agent/tools/ast_grep.rs
Normal file
|
|
@ -0,0 +1,146 @@
|
||||||
|
// tools/ast_grep.rs — Structural code search using ast-grep library
|
||||||
|
//
|
||||||
|
// AST-level pattern matching: find code structures, not just text.
|
||||||
|
// Uses ast-grep-core and ast-grep-language directly — no shell subprocess.
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::path::Path;
|
||||||
|
use anyhow::{Context, Result};
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
use ast_grep_core::Pattern;
|
||||||
|
use ast_grep_language::{SupportLang, LanguageExt};
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Args {
|
||||||
|
pattern: String,
|
||||||
|
#[serde(default = "default_path")]
|
||||||
|
path: String,
|
||||||
|
lang: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_path() -> String { ".".into() }
|
||||||
|
|
||||||
|
pub fn tool() -> super::Tool {
|
||||||
|
super::Tool {
|
||||||
|
name: "ast_grep",
|
||||||
|
description: "Structural code search using AST patterns. Finds code by structure, not text — \
|
||||||
|
e.g. find all `if let Some($X) = $Y { $$$BODY }` patterns. \
|
||||||
|
Supports C, Rust, Python, JS/TS, Go, Java, and 20+ languages.",
|
||||||
|
parameters_json: r#"{"type":"object","properties":{"pattern":{"type":"string","description":"AST pattern to search for. Use $X for single node wildcards, $$$X for multiple nodes."},"path":{"type":"string","description":"Directory or file to search in (default: current directory)"},"lang":{"type":"string","description":"Language (e.g. 'rust', 'c', 'python', 'javascript'). Auto-detected from file extension if omitted."}},"required":["pattern"]}"#,
|
||||||
|
handler: Arc::new(|_a, v| Box::pin(async move { ast_grep_search(&v) })),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn detect_lang(path: &Path) -> Option<SupportLang> {
|
||||||
|
let ext = path.extension()?.to_str()?;
|
||||||
|
parse_lang(ext)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_lang(name: &str) -> Option<SupportLang> {
|
||||||
|
// ast-grep-language provides from_extension but we want from name
|
||||||
|
match name.to_lowercase().as_str() {
|
||||||
|
"rust" | "rs" => Some(SupportLang::Rust),
|
||||||
|
"c" => Some(SupportLang::C),
|
||||||
|
"cpp" | "c++" | "cc" | "cxx" => Some(SupportLang::Cpp),
|
||||||
|
"python" | "py" => Some(SupportLang::Python),
|
||||||
|
"javascript" | "js" => Some(SupportLang::JavaScript),
|
||||||
|
"typescript" | "ts" => Some(SupportLang::TypeScript),
|
||||||
|
"go" => Some(SupportLang::Go),
|
||||||
|
"java" => Some(SupportLang::Java),
|
||||||
|
"json" => Some(SupportLang::Json),
|
||||||
|
"html" => Some(SupportLang::Html),
|
||||||
|
"css" => Some(SupportLang::Css),
|
||||||
|
"bash" | "sh" => Some(SupportLang::Bash),
|
||||||
|
"ruby" | "rb" => Some(SupportLang::Ruby),
|
||||||
|
"yaml" | "yml" => Some(SupportLang::Yaml),
|
||||||
|
"lua" => Some(SupportLang::Lua),
|
||||||
|
"kotlin" | "kt" => Some(SupportLang::Kotlin),
|
||||||
|
"swift" => Some(SupportLang::Swift),
|
||||||
|
"scala" => Some(SupportLang::Scala),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_file(
|
||||||
|
path: &Path,
|
||||||
|
lang: SupportLang,
|
||||||
|
pattern: &Pattern,
|
||||||
|
results: &mut Vec<String>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let source = std::fs::read_to_string(path)
|
||||||
|
.with_context(|| format!("reading {}", path.display()))?;
|
||||||
|
let tree = lang.ast_grep(&source);
|
||||||
|
for node_match in tree.root().find_all(pattern) {
|
||||||
|
let start = node_match.start_pos();
|
||||||
|
let line = start.line() + 1;
|
||||||
|
let matched_text = node_match.text();
|
||||||
|
let preview = if matched_text.len() > 200 {
|
||||||
|
format!("{}...", &matched_text[..200])
|
||||||
|
} else {
|
||||||
|
matched_text.to_string()
|
||||||
|
};
|
||||||
|
results.push(format!("{}:{}: {}", path.display(), line, preview));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn walk_and_search(
|
||||||
|
dir: &Path,
|
||||||
|
explicit_lang: Option<SupportLang>,
|
||||||
|
pattern_str: &str,
|
||||||
|
results: &mut Vec<String>,
|
||||||
|
) -> Result<()> {
|
||||||
|
if dir.is_file() {
|
||||||
|
let lang = explicit_lang
|
||||||
|
.or_else(|| detect_lang(dir))
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("cannot detect language for {}", dir.display()))?;
|
||||||
|
let pattern = Pattern::new(pattern_str, lang);
|
||||||
|
return search_file(dir, lang, &pattern, results);
|
||||||
|
}
|
||||||
|
|
||||||
|
for entry in walkdir::WalkDir::new(dir)
|
||||||
|
.into_iter()
|
||||||
|
.filter_entry(|e| {
|
||||||
|
let name = e.file_name().to_str().unwrap_or("");
|
||||||
|
!name.starts_with('.') && name != "target" && name != "node_modules"
|
||||||
|
})
|
||||||
|
{
|
||||||
|
let entry = match entry {
|
||||||
|
Ok(e) => e,
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
if !entry.file_type().is_file() { continue; }
|
||||||
|
|
||||||
|
let path = entry.path();
|
||||||
|
let lang = match explicit_lang.or_else(|| detect_lang(path)) {
|
||||||
|
Some(l) => l,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
let pattern = Pattern::new(pattern_str, lang);
|
||||||
|
let _ = search_file(path, lang, &pattern, results);
|
||||||
|
|
||||||
|
if results.len() >= 100 {
|
||||||
|
results.push("... (truncated at 100 matches)".into());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ast_grep_search(args: &serde_json::Value) -> Result<String> {
|
||||||
|
let a: Args = serde_json::from_value(args.clone())
|
||||||
|
.context("invalid ast_grep arguments")?;
|
||||||
|
|
||||||
|
let explicit_lang = a.lang.as_deref().and_then(parse_lang);
|
||||||
|
let path = Path::new(&a.path);
|
||||||
|
|
||||||
|
let mut results = Vec::new();
|
||||||
|
walk_and_search(path, explicit_lang, &a.pattern, &mut results)?;
|
||||||
|
|
||||||
|
if results.is_empty() {
|
||||||
|
return Ok("No matches found.".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(super::truncate_output(results.join("\n"), 30000))
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
// working_stack) and delegates everything else to thought::dispatch.
|
// working_stack) and delegates everything else to thought::dispatch.
|
||||||
|
|
||||||
// Core tools
|
// Core tools
|
||||||
|
mod ast_grep;
|
||||||
mod bash;
|
mod bash;
|
||||||
pub mod channels;
|
pub mod channels;
|
||||||
mod edit;
|
mod edit;
|
||||||
|
|
@ -160,7 +161,7 @@ pub fn tools() -> Vec<Tool> {
|
||||||
let mut all = vec![
|
let mut all = vec![
|
||||||
read::tool(), write::tool(), edit::tool(),
|
read::tool(), write::tool(), edit::tool(),
|
||||||
grep::tool(), glob::tool(), bash::tool(),
|
grep::tool(), glob::tool(), bash::tool(),
|
||||||
vision::tool(),
|
ast_grep::tool(), vision::tool(),
|
||||||
];
|
];
|
||||||
all.extend(web::tools());
|
all.extend(web::tools());
|
||||||
all.extend(memory::memory_tools());
|
all.extend(memory::memory_tools());
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue