diff --git a/Cargo.lock b/Cargo.lock index e90e2a23b8556e44d9bddaeb245f09e19d943cd6..a94de5439459062bbf63cc8362d6107d59047ed3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2368,9 +2368,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.3" +version = "1.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" +checksum = "755717a7de9ec452bf7f3f1a3099085deabd7f2962b861dae91ecd7a365903d2" dependencies = [ "jobserver", "libc", @@ -3308,18 +3308,18 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.111.2" +version = "0.112.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f823c6662ea77699089ec8b6b4b8a23c1e1a9c6526a6420ede7ac957274a7ab4" +checksum = "69792bd40d21be8059f7c709f44200ded3bbd073df7eb3fa3c282b387c7ffa5b" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.111.2" +version = "0.112.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fcbb4187005097204458a8e4309bb9e737933477e47b4609f81b07a5b4cdd25" +checksum = "38da1eb6f7d8cdfa92f05acfae63c9a1d7a337e49ce7a2d0769c7fa03a2613a5" dependencies = [ "serde", "serde_derive", @@ -3327,9 +3327,9 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.111.2" +version = "0.112.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd1aaf8e88339f4f95afffd60d22033546ec7da4d79e805b85260a16668f78f" +checksum = "709f5567a2bff9f06edf911a7cb5ebb091e4c81701714dc6ab574d08b4a69a0d" dependencies = [ "bumpalo", "cranelift-bforest", @@ -3343,40 +3343,40 @@ dependencies = [ "hashbrown 0.14.5", "log", "regalloc2", - "rustc-hash 1.1.0", + "rustc-hash 2.1.1", "smallvec", "target-lexicon", ] [[package]] name = "cranelift-codegen-meta" -version = "0.111.2" +version = "0.112.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e541b0418bbba3ce82040a445bd9a83bf3e0da604a95178d9e949dc8a7840af" +checksum = "72d39a6b194c069fd091ca1f17b9d86ff1a4627ccad8806095828f61989a691f" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.111.2" +version = "0.112.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc96a709a30be39d53ecf89dbfe4edcc5adba528d4b65f7e58dc867ba70fab" +checksum = "18f81aefad1f80ed4132ae33f40b92779eeb57edeb1e28bb24424a4098c963a2" [[package]] name = "cranelift-control" -version = "0.111.2" +version = "0.112.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c3bfcb035e0a501323896bb7ea3d7a5dd1fac3e92dda458ccd23960fde12c88" +checksum = "6adbaac785ad4683c4f199686f9e15c1471f52ae2f4c013a3be039b4719db754" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.111.2" +version = "0.112.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2f00b4eba51d73a8c343c45cfdeeffa1f74f423bba0e6b8e290e646777c2b81" +checksum = "70b85ed43567e13782cd1b25baf42a8167ee57169a60dfd3d7307c6ca3839da0" dependencies = [ "cranelift-bitset", "serde", @@ -3385,9 +3385,9 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.111.2" +version = "0.112.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52d5e18bf04660bb716dacf45809e2d4c85e7111701e27dbdb75b4634504ad8f" +checksum = "8349f71373bb69c6f73992c6c1606236a66c8134e7a60e04e03fbd64b1aa7dcf" dependencies = [ "cranelift-codegen", "log", @@ -3397,15 +3397,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.111.2" +version = "0.112.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f9901807b6d0fde1205f0e4db9d96dcf7ddfc1894c69eb2ff93c47ebf2439f" +checksum = "464a6b958ce05e0c237c8b25508012b6c644e8c37348213a8c786ba29e28cfdb" [[package]] name = "cranelift-native" -version = "0.111.2" +version = "0.112.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "967d65a4077726a9afc3f4694e037f34b992cbe2b6c48ce519b714a0b0558f97" +checksum = "ffc4acaf6894ee323ff4e9ce786bec09f0ebbe49941e8012f1c1052f1d965034" dependencies = [ "cranelift-codegen", "libc", @@ -3414,9 +3414,9 @@ dependencies = [ [[package]] name = "cranelift-wasm" -version = "0.111.2" +version = "0.112.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4899fd1ef6b1fe1df30f26ef864bd6e45040b8cf9f3cb3905d3e973c25698579" +checksum = "b878860895cca97454ef8d8b12bfda9d0889dd49efee175dba78d54ff8363ec2" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -3424,7 +3424,7 @@ dependencies = [ "itertools 0.12.1", "log", "smallvec", - "wasmparser 0.215.0", + "wasmparser 0.217.1", "wasmtime-types", ] @@ -4060,6 +4060,7 @@ dependencies = [ "http_client", "indoc", "inline_completion", + "inventory", "itertools 0.14.0", "language", "linkify", @@ -4447,8 +4448,8 @@ dependencies = [ "serde_json", "toml 0.8.20", "util", - "wasm-encoder 0.215.0", - "wasmparser 0.215.0", + "wasm-encoder 0.217.1", + "wasmparser 0.217.1", "wit-component", ] @@ -4517,7 +4518,7 @@ dependencies = [ "toml 0.8.20", "url", "util", - "wasmparser 0.215.0", + "wasmparser 0.217.1", "wasmtime", "wasmtime-wasi", ] @@ -5699,15 +5700,6 @@ dependencies = [ "ahash 0.7.8", ] -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash 0.8.11", -] - [[package]] name = "hashbrown" version = "0.14.5" @@ -6912,6 +6904,7 @@ dependencies = [ "similar", "smallvec", "smol", + "streaming-iterator", "strsim", "sum_tree", "task", @@ -7886,7 +7879,9 @@ version = "0.1.0" dependencies = [ "collections", "convert_case 0.7.1", + "log", "pretty_assertions", + "streaming-iterator", "tree-sitter", "tree-sitter-json", ] @@ -10781,13 +10776,13 @@ dependencies = [ [[package]] name = "regalloc2" -version = "0.9.3" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6" +checksum = "12908dbeb234370af84d0579b9f68258a0f67e201412dd9a2814e6f45b2fc0f0" dependencies = [ - "hashbrown 0.13.2", + "hashbrown 0.14.5", "log", - "rustc-hash 1.1.0", + "rustc-hash 2.1.1", "slice-group-by", "smallvec", ] @@ -11858,6 +11853,7 @@ dependencies = [ "settings", "sha2", "smol", + "streaming-iterator", "tempfile", "theme", "tree-sitter", @@ -12037,6 +12033,7 @@ dependencies = [ "futures 0.3.31", "gpui", "indoc", + "inventory", "log", "migrator", "paths", @@ -12049,6 +12046,7 @@ dependencies = [ "serde_json", "serde_json_lenient", "smallvec", + "streaming-iterator", "tree-sitter", "tree-sitter-json", "unindent", @@ -12732,6 +12730,12 @@ dependencies = [ "ui", ] +[[package]] +name = "streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2231b7c3057d5e4ad0156fb3dc807d900806020c5ffa3ee6ff2c8c76fb8520" + [[package]] name = "streaming_diff" version = "0.1.0" @@ -14031,13 +14035,14 @@ dependencies = [ [[package]] name = "tree-sitter" -version = "0.23.2" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0203df02a3b6dd63575cc1d6e609edc2181c9a11867a271b25cfd2abff3ec5ca" +checksum = "a5387dffa7ffc7d2dae12b50c6f7aab8ff79d6210147c6613561fc3d474c6f75" dependencies = [ "cc", "regex", "regex-syntax 0.8.5", + "streaming-iterator", "tree-sitter-language", "wasmtime-c-api-impl", ] @@ -14936,9 +14941,9 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.215.0" +version = "0.217.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb56df3e06b8e6b77e37d2969a50ba51281029a9aeb3855e76b7f49b6418847" +checksum = "10961fd76db420582926af70816dd205019d8152d9e51e1b939125dd1639f854" dependencies = [ "leb128", ] @@ -14985,9 +14990,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.215.0" +version = "0.217.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fbde0881f24199b81cf49b6ff8f9c145ac8eb1b7fc439adb5c099734f7d90e" +checksum = "65a5a0689975b9fd93c02f5400cfd9669858b99607e54e7b892c6080cba598bb" dependencies = [ "ahash 0.8.11", "bitflags 2.8.0", @@ -14999,20 +15004,20 @@ dependencies = [ [[package]] name = "wasmprinter" -version = "0.215.0" +version = "0.217.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8e9a325d85053408209b3d2ce5eaddd0dd6864d1cff7a007147ba073157defc" +checksum = "324c6782d7b81c01625335d252653b26ea68e835ddb4aef4cb1ed3ea40ae3a49" dependencies = [ "anyhow", "termcolor", - "wasmparser 0.215.0", + "wasmparser 0.217.1", ] [[package]] name = "wasmtime" -version = "24.0.2" +version = "25.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e763074ccd6b251c78095fcd27707253b69cef961ea0a2ff76a8d246ddfadd1b" +checksum = "f38dbf42dc56a6fe41ccd77211ea8ec90855de05e52cd00df5a0a3bca87d6147" dependencies = [ "anyhow", "async-trait", @@ -15040,7 +15045,7 @@ dependencies = [ "smallvec", "sptr", "target-lexicon", - "wasmparser 0.215.0", + "wasmparser 0.217.1", "wasmtime-asm-macros", "wasmtime-component-macro", "wasmtime-component-util", @@ -15056,18 +15061,18 @@ dependencies = [ [[package]] name = "wasmtime-asm-macros" -version = "24.0.2" +version = "25.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f45004b6fa5d12dd95b427474e69bde05a6d31d33b39bd56054f9cd68e824283" +checksum = "30e0c7f9983c2d60109a939d9ab0e0df301901085c3608e1c22c27c98390a027" dependencies = [ "cfg-if", ] [[package]] name = "wasmtime-c-api-impl" -version = "24.0.2" +version = "25.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e038dd412700174019867608617127e7cc4f113f764dd10e7488dbf5f47b191" +checksum = "ebfcdb4aa0f68020934099815cf6ef11dbbedaf070ef800b3f0a7f6ec7b7d005" dependencies = [ "anyhow", "log", @@ -15079,9 +15084,9 @@ dependencies = [ [[package]] name = "wasmtime-c-api-macros" -version = "24.0.2" +version = "25.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde0ca2263811d980ab676bcb2a190c990737f58969a908976101ad208149a17" +checksum = "842c213ad4546fb0178735910b96ee7da303e1d745c3f42f4178b0de1da138b6" dependencies = [ "proc-macro2", "quote", @@ -15089,9 +15094,9 @@ dependencies = [ [[package]] name = "wasmtime-component-macro" -version = "24.0.2" +version = "25.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74b72572d389586e429a9830ab68a5b3e2a567962b8a82f4249652ccc68ddab2" +checksum = "0929ffffaca32dd8770b56848c94056036963ca05de25fb47cac644e20262168" dependencies = [ "anyhow", "proc-macro2", @@ -15099,20 +15104,20 @@ dependencies = [ "syn 2.0.90", "wasmtime-component-util", "wasmtime-wit-bindgen", - "wit-parser 0.215.0", + "wit-parser 0.217.1", ] [[package]] name = "wasmtime-component-util" -version = "24.0.2" +version = "25.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3081af782040e8016373e603ee854496c82cdc0f32b13a6bc9700e15f582db" +checksum = "fdc29d2b56629d66d2fd791d1b46471d0016e0d684ed2dc299e870d127082268" [[package]] name = "wasmtime-cranelift" -version = "24.0.2" +version = "25.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42c18ca178eee0947cd53b27d3a101dd2f79afec86fc3ce657545519c6bf011a" +checksum = "f8c8af1197703f4de556a274384adf5db36a146f9892bc9607bad16881e75c80" dependencies = [ "anyhow", "cfg-if", @@ -15125,18 +15130,19 @@ dependencies = [ "gimli 0.29.0", "log", "object", + "smallvec", "target-lexicon", "thiserror 1.0.69", - "wasmparser 0.215.0", + "wasmparser 0.217.1", "wasmtime-environ", "wasmtime-versioned-export-macros", ] [[package]] name = "wasmtime-environ" -version = "24.0.2" +version = "25.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e80da0784d4dd0788479ce390cd4a54a893d24f2937d4046145704777aa7a131" +checksum = "3f1b5af7bac868c5bce3b78a366a10677caacf6e6467c156301297e36ed31f3e" dependencies = [ "anyhow", "cpp_demangle", @@ -15152,8 +15158,8 @@ dependencies = [ "serde", "serde_derive", "target-lexicon", - "wasm-encoder 0.215.0", - "wasmparser 0.215.0", + "wasm-encoder 0.217.1", + "wasmparser 0.217.1", "wasmprinter", "wasmtime-component-util", "wasmtime-types", @@ -15161,9 +15167,9 @@ dependencies = [ [[package]] name = "wasmtime-fiber" -version = "24.0.2" +version = "25.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c3d366194ff87b8aeeb7348bb789d5dd9a9aca18b340b19dcf4ab96966e663" +checksum = "665ccc1bb0f28496e6fa02e94c575ee9ad6e3202c7df8591e5dda78106d5aa4a" dependencies = [ "anyhow", "cc", @@ -15176,9 +15182,9 @@ dependencies = [ [[package]] name = "wasmtime-jit-icache-coherence" -version = "24.0.2" +version = "25.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c543f7ee7b1ec8f2215f88197a40f9fa3452dc98c5902c5c700d8ec9e9ea7021" +checksum = "5d7314e32c624f645ad7d6b9fc3ac89eb7d2b9aa06695d6445cec087958ec27d" dependencies = [ "anyhow", "cfg-if", @@ -15188,29 +15194,29 @@ dependencies = [ [[package]] name = "wasmtime-slab" -version = "24.0.2" +version = "25.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf7ded4156c76cc1cb348e5728096087e2c432714d1b285044c6da6a1e3d01a" +checksum = "f75cba1a8cc327839f493cfc3036c9de3d077d59ab76296bc710ee5f95be5391" [[package]] name = "wasmtime-types" -version = "24.0.2" +version = "25.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92a6f3c2a8704a60ae0278ea2635c986539539ce1b80080b0fe8ea7bc83da81" +checksum = "c6d83a7816947a4974e2380c311eacb1db009b8bad86081dc726b705603c93c7" dependencies = [ "anyhow", "cranelift-entity", "serde", "serde_derive", "smallvec", - "wasmparser 0.215.0", + "wasmparser 0.217.1", ] [[package]] name = "wasmtime-versioned-export-macros" -version = "24.0.2" +version = "25.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6e2f847c118d5b26f0cc01d12a6d72fa450e32c42a4a3ce5d33afb4729ed6a" +checksum = "6879a8e168aef3fe07335343b7fbede12fa494215e83322e173d4018e124a846" dependencies = [ "proc-macro2", "quote", @@ -15219,9 +15225,9 @@ dependencies = [ [[package]] name = "wasmtime-wasi" -version = "24.0.2" +version = "25.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f88f94e393084426f5055d57ce7ae6346ae623783ee6792f411282d6b9e1e5c3" +checksum = "d042ea66b2834fb03b8a6968ef1a99a4b537211b00f7502a4d6a37f4eb2049b2" dependencies = [ "anyhow", "async-trait", @@ -15250,16 +15256,16 @@ dependencies = [ [[package]] name = "wasmtime-winch" -version = "24.0.2" +version = "25.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee3640cd34c67f505e88cef0da11368806204a24c68c35d671a48a59bb37f908" +checksum = "6baca2a919a288df653246069868b4de80f07e9679a8ef9b78ad79fc658ffd12" dependencies = [ "anyhow", "cranelift-codegen", "gimli 0.29.0", "object", "target-lexicon", - "wasmparser 0.215.0", + "wasmparser 0.217.1", "wasmtime-cranelift", "wasmtime-environ", "winch-codegen", @@ -15267,14 +15273,14 @@ dependencies = [ [[package]] name = "wasmtime-wit-bindgen" -version = "24.0.2" +version = "25.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58b085b2d330e5057dddd31f3ca527569b90fcdd35f6d373420c304927a5190" +checksum = "3f571f63ac1d532e986eb3973bbef3a45e4ae83de521a8d573b0fe0594dc9608" dependencies = [ "anyhow", "heck 0.4.1", "indexmap", - "wit-parser 0.215.0", + "wit-parser 0.217.1", ] [[package]] @@ -15493,9 +15499,9 @@ dependencies = [ [[package]] name = "wiggle" -version = "24.0.2" +version = "25.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c72a4c92952216582f55eab27819a1fe8d3c54b292b7b8e5f849b23bfed96e78" +checksum = "4c8fdcd81702e0f46a8ab2ed28a5bf824aabf4a1af1673af496a020aacd0b6f9" dependencies = [ "anyhow", "async-trait", @@ -15508,9 +15514,9 @@ dependencies = [ [[package]] name = "wiggle-generate" -version = "24.0.2" +version = "25.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb744fb938a9fc38207838829b4a43831c1de499e3526eaea71deeff4d9cbb83" +checksum = "14f745361f0a9071aaabd05de1bb2b782d9f0597f30d9c0f20326224902e64d5" dependencies = [ "anyhow", "heck 0.4.1", @@ -15523,9 +15529,9 @@ dependencies = [ [[package]] name = "wiggle-macro" -version = "24.0.2" +version = "25.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cef395fff17bf8f9c1dee6c0e12801a3ba24928139af0ecb5ccb82ff87bf9d2" +checksum = "bfbdae3574621921ed3c13325edc910388487759d10fb330f656cfc69bee38db" dependencies = [ "proc-macro2", "quote", @@ -15566,9 +15572,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "winch-codegen" -version = "0.22.2" +version = "0.23.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46d7fecc199486f048bb2d649dce68bf28712ae1183dd54fd4a0534989517b24" +checksum = "01cd1dc56c5a45d509ff06e7ca8817eaa9ec3240096f07e71915d5d528658e8a" dependencies = [ "anyhow", "cranelift-codegen", @@ -15576,7 +15582,7 @@ dependencies = [ "regalloc2", "smallvec", "target-lexicon", - "wasmparser 0.215.0", + "wasmparser 0.217.1", "wasmtime-cranelift", "wasmtime-environ", ] @@ -16128,9 +16134,9 @@ dependencies = [ [[package]] name = "wit-parser" -version = "0.215.0" +version = "0.217.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "935a97eaffd57c3b413aa510f8f0b550a4a9fe7d59e79cd8b89a83dcb860321f" +checksum = "e5aaf02882453eaeec4fe30f1e4263cfd8b8ea36dd00e1fe7d902d9cb498bccd" dependencies = [ "anyhow", "id-arena", @@ -16141,7 +16147,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.215.0", + "wasmparser 0.217.1", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 147d2c32e138762681b81dee2486eae3fce5a603..e0481d632a900f24bd80b9d73e64fb3e5ad446ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -423,6 +423,7 @@ ignore = "0.4.22" image = "0.25.1" indexmap = { version = "2.7.0", features = ["serde"] } indoc = "2" +inventory = "0.3.19" itertools = "0.14.0" jsonwebtoken = "9.3" jupyter-protocol = { version = "0.6.0" } @@ -502,6 +503,7 @@ simplelog = "0.12.2" smallvec = { version = "1.6", features = ["union"] } smol = "2.0" sqlformat = "0.2" +streaming-iterator = "0.1" strsim = "0.11" strum = { version = "0.26.0", features = ["derive"] } subtle = "2.5.0" @@ -523,7 +525,7 @@ tiny_http = "0.8" toml = "0.8" tokio = { version = "1" } tower-http = "0.4.4" -tree-sitter = { version = "0.23", features = ["wasm"] } +tree-sitter = { version = "0.24", features = ["wasm"] } tree-sitter-bash = "0.23" tree-sitter-c = "0.23" tree-sitter-cpp = "0.23" @@ -552,16 +554,16 @@ unicode-segmentation = "1.10" unicode-script = "0.5.7" url = "2.2" uuid = { version = "1.1.2", features = ["v4", "v5", "v7", "serde"] } -wasmparser = "0.215" -wasm-encoder = "0.215" -wasmtime = { version = "24", default-features = false, features = [ +wasmparser = "0.217" +wasm-encoder = "0.217" +wasmtime = { version = "25", default-features = false, features = [ "async", "demangle", "runtime", "cranelift", "component-model", ] } -wasmtime-wasi = "24" +wasmtime-wasi = "25" which = "6.0.0" wit-component = "0.201" zed_llm_client = "0.4" diff --git a/crates/editor/Cargo.toml b/crates/editor/Cargo.toml index d78dff8d2a1a0585b180d40346469bbee167d831..282c10eb608c7fe64dd01e1bdb944006ce139ff1 100644 --- a/crates/editor/Cargo.toml +++ b/crates/editor/Cargo.toml @@ -49,6 +49,7 @@ gpui.workspace = true http_client.workspace = true indoc.workspace = true inline_completion.workspace = true +inventory.workspace = true itertools.workspace = true language.workspace = true linkify.workspace = true diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 410509139571e74e9caf72d6f156df915af768a0..bdf1fd905686049ac33ab68c28edb202de20ee6d 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -62,10 +62,10 @@ pub use editor_settings::{ CurrentLineHighlight, EditorSettings, ScrollBeyondLastLine, SearchSettings, ShowScrollbar, }; pub use editor_settings_controls::*; +use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap}; pub use element::{ CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition, }; -use element::{LineWithInvisibles, PositionMap}; use futures::{future, FutureExt}; use fuzzy::StringMatchCandidate; @@ -190,6 +190,9 @@ pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250); pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(2); pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1); +pub(crate) const EDIT_PREDICTION_REQUIRES_MODIFIER_KEY_CONTEXT: &str = + "edit_prediction_requires_modifier"; + pub fn render_parsed_markdown( element_id: impl Into, parsed: &language::ParsedMarkdown, @@ -1528,7 +1531,7 @@ impl Editor { key_context.add("edit_prediction"); if showing_completions || self.edit_prediction_requires_modifier(cx) { - key_context.add("edit_prediction_requires_modifier"); + key_context.add(EDIT_PREDICTION_REQUIRES_MODIFIER_KEY_CONTEXT); } } @@ -5092,19 +5095,38 @@ impl Editor { has_completion && self.edit_prediction_requires_modifier(cx) } - fn update_inline_completion_preview( + fn handle_modifiers_changed( &mut self, - modifiers: &Modifiers, + modifiers: Modifiers, + position_map: &PositionMap, window: &mut Window, cx: &mut Context, ) { if !self.show_edit_predictions_in_menu(cx) { + let accept_binding = + AcceptEditPredictionBinding::resolve(self.focus_handle(cx), window); + if let Some(accept_keystroke) = accept_binding.keystroke() { + let was_previewing_inline_completion = self.previewing_inline_completion; + self.previewing_inline_completion = modifiers == accept_keystroke.modifiers + && accept_keystroke.modifiers.modified(); + if self.previewing_inline_completion != was_previewing_inline_completion { + self.update_visible_inline_completion(window, cx); + } + } + } + + let mouse_position = window.mouse_position(); + if !position_map.text_hitbox.is_hovered(window) { return; } - self.previewing_inline_completion = modifiers.alt; - self.update_visible_inline_completion(window, cx); - cx.notify(); + self.update_hovered_link( + position_map.point_for_position(mouse_position), + &position_map.snapshot, + modifiers, + window, + cx, + ) } fn update_visible_inline_completion( diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 68bd0514dd9bac55c7032a25d46067dd191b83ba..6cf4526f3c22a673019dc2d24deda1ad79132195 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -9711,7 +9711,7 @@ async fn test_toggle_block_comment(cx: &mut gpui::TestAppContext) { &r#" // ˇvar x = new Y(); - // ˇ + "# .unindent(), ); diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index fe829e2ad6fb11a8af93f9c5be1f98658cd8eef0..784c1d51785458e68551137ae77fd71a8a2b7a2e 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -15,13 +15,14 @@ use crate::{ items::BufferSearchHighlights, mouse_context_menu::{self, MenuPosition, MouseContextMenu}, scroll::{axis_pair, scroll_amount::ScrollAmount, AxisPair}, - BlockId, ChunkReplacement, CursorShape, CustomBlockId, DisplayPoint, DisplayRow, - DocumentHighlightRead, DocumentHighlightWrite, EditDisplayMode, Editor, EditorMode, + AcceptEditPrediction, BlockId, ChunkReplacement, CursorShape, CustomBlockId, DisplayPoint, + DisplayRow, DocumentHighlightRead, DocumentHighlightWrite, EditDisplayMode, Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle, ExpandExcerpts, FocusedBlock, GoToHunk, GoToPrevHunk, GutterDimensions, HalfPageDown, HalfPageUp, HandleInput, HoveredCursor, InlineCompletion, JumpData, LineDown, LineUp, OpenExcerpts, PageDown, PageUp, Point, RevertSelectedHunks, RowExt, RowRangeExt, SelectPhase, Selection, SoftWrap, - StickyHeaderExcerpt, ToPoint, ToggleFold, CURSORS_VISIBLE_FOR, FILE_HEADER_HEIGHT, + StickyHeaderExcerpt, ToPoint, ToggleFold, CURSORS_VISIBLE_FOR, + EDIT_PREDICTION_REQUIRES_MODIFIER_KEY_CONTEXT, FILE_HEADER_HEIGHT, GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED, MAX_LINE_LEN, MULTI_BUFFER_EXCERPT_HEADER_HEIGHT, }; use client::ParticipantIndex; @@ -34,11 +35,11 @@ use gpui::{ relative, size, svg, transparent_black, Action, AnyElement, App, AvailableSpace, Axis, Bounds, ClickEvent, ClipboardItem, ContentMask, Context, Corner, Corners, CursorStyle, DispatchPhase, Edges, Element, ElementInputHandler, Entity, FocusHandle, Focusable as _, FontId, - GlobalElementId, Hitbox, Hsla, InteractiveElement, IntoElement, Keystroke, Length, - ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad, - ParentElement, Pixels, ScrollDelta, ScrollWheelEvent, ShapedLine, SharedString, Size, - StatefulInteractiveElement, Style, Styled, Subscription, TextRun, TextStyleRefinement, - WeakEntity, Window, + GlobalElementId, Hitbox, Hsla, InteractiveElement, IntoElement, KeyBindingContextPredicate, + Keystroke, Length, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, + MouseUpEvent, PaintQuad, ParentElement, Pixels, ScrollDelta, ScrollWheelEvent, ShapedLine, + SharedString, Size, StatefulInteractiveElement, Style, Styled, Subscription, TextRun, + TextStyleRefinement, WeakEntity, Window, }; use itertools::Itertools; use language::{ @@ -54,7 +55,7 @@ use multi_buffer::{ RowInfo, ToOffset, }; use project::project_settings::{GitGutterSetting, ProjectSettings}; -use settings::Settings; +use settings::{KeyBindingValidator, KeyBindingValidatorRegistration, Settings}; use smallvec::{smallvec, SmallVec}; use std::{ any::TypeId, @@ -74,7 +75,7 @@ use ui::{ POPOVER_Y_PADDING, }; use unicode_segmentation::UnicodeSegmentation; -use util::{RangeExt, ResultExt}; +use util::{markdown::MarkdownString, RangeExt, ResultExt}; use workspace::{item::Item, notifications::NotifyTaskExt, Workspace}; const INLINE_BLAME_PADDING_EM_WIDTHS: f32 = 7.; @@ -511,35 +512,12 @@ impl EditorElement { if editor.hover_state.focused(window, cx) { return; } - Self::modifiers_changed(editor, event, &position_map, window, cx) + editor.handle_modifiers_changed(event.modifiers, &position_map, window, cx); }) } }); } - fn modifiers_changed( - editor: &mut Editor, - event: &ModifiersChangedEvent, - position_map: &PositionMap, - window: &mut Window, - cx: &mut Context, - ) { - editor.update_inline_completion_preview(&event.modifiers, window, cx); - - let mouse_position = window.mouse_position(); - if !position_map.text_hitbox.is_hovered(window) { - return; - } - - editor.update_hovered_link( - position_map.point_for_position(mouse_position), - &position_map.snapshot, - event.modifiers, - window, - cx, - ) - } - fn mouse_left_down( editor: &mut Editor, event: &MouseDownEvent, @@ -3190,49 +3168,8 @@ impl EditorElement { ); let edit_prediction = if edit_prediction_popover_visible { - let accept_keystroke: Option; - - // TODO: load modifier from keymap. - // `bindings_for_action_in` returns `None` in Linux, and is intermittent on macOS - #[cfg(target_os = "macos")] - { - // let bindings = window.bindings_for_action_in( - // &crate::AcceptEditPrediction, - // &self.editor.focus_handle(cx), - // ); - - // let last_binding = bindings.last(); - - // accept_keystroke = if let Some(binding) = last_binding { - // match &binding.keystrokes() { - // // TODO: no need to clone once this logic works on linux. - // [keystroke] => Some(keystroke.clone()), - // _ => None, - // } - // } else { - // None - // }; - accept_keystroke = Some(Keystroke { - modifiers: gpui::Modifiers { - alt: true, - ..Default::default() - }, - key: "tab".to_string(), - key_char: None, - }); - } - - #[cfg(not(target_os = "macos"))] - { - accept_keystroke = Some(Keystroke { - modifiers: gpui::Modifiers { - alt: true, - ..Default::default() - }, - key: "enter".to_string(), - key_char: None, - }); - } + let accept_binding = + AcceptEditPredictionBinding::resolve(self.editor.focus_handle(cx), window); self.editor.update(cx, move |editor, cx| { let mut element = editor.render_edit_prediction_cursor_popover( @@ -3240,7 +3177,7 @@ impl EditorElement { max_width, cursor_point, style, - accept_keystroke.as_ref()?, + accept_binding.keystroke()?, window, cx, )?; @@ -5739,48 +5676,12 @@ fn inline_completion_accept_indicator( label: impl Into, icon: Option, previewing: bool, - focus_handle: FocusHandle, + editor_focus_handle: FocusHandle, window: &Window, cx: &App, ) -> Option { - let use_hardcoded_linux_bindings; - - #[cfg(target_os = "macos")] - { - use_hardcoded_linux_bindings = false; - } - - #[cfg(not(target_os = "macos"))] - { - use_hardcoded_linux_bindings = true; - } - - let accept_keystroke = if use_hardcoded_linux_bindings { - if previewing { - Keystroke { - modifiers: Default::default(), - key: "enter".to_string(), - key_char: None, - } - } else { - Keystroke { - modifiers: Default::default(), - key: "tab".to_string(), - key_char: None, - } - } - } else { - let bindings = window.bindings_for_action_in(&crate::AcceptEditPrediction, &focus_handle); - if let Some(keystroke) = bindings - .last() - .and_then(|binding| binding.keystrokes().first()) - { - // TODO: clone unnecessary once `use_hardcoded_linux_bindings` is removed. - keystroke.clone() - } else { - return None; - } - }; + let accept_binding = AcceptEditPredictionBinding::resolve(editor_focus_handle, window); + let accept_keystroke = accept_binding.keystroke()?; let accept_key = h_flex() .px_0p5() @@ -5828,6 +5729,69 @@ fn inline_completion_accept_indicator( ) } +pub struct AcceptEditPredictionBinding(Option); + +impl AcceptEditPredictionBinding { + pub fn resolve(editor_focus_handle: FocusHandle, window: &Window) -> Self { + AcceptEditPredictionBinding( + window + .bindings_for_action_in(&AcceptEditPrediction, &editor_focus_handle) + .into_iter() + .next(), + ) + } + + pub fn keystroke(&self) -> Option<&Keystroke> { + if let Some(binding) = self.0.as_ref() { + match &binding.keystrokes() { + [keystroke] => Some(keystroke), + _ => None, + } + } else { + None + } + } +} + +struct AcceptEditPredictionsBindingValidator; + +inventory::submit! { KeyBindingValidatorRegistration(|| Box::new(AcceptEditPredictionsBindingValidator)) } + +impl KeyBindingValidator for AcceptEditPredictionsBindingValidator { + fn action_type_id(&self) -> TypeId { + TypeId::of::() + } + + fn validate(&self, binding: &gpui::KeyBinding) -> Result<(), MarkdownString> { + use KeyBindingContextPredicate::*; + + if binding.keystrokes().len() == 1 && binding.keystrokes()[0].modifiers.modified() { + return Ok(()); + } + let required_predicate = + Not(Identifier(EDIT_PREDICTION_REQUIRES_MODIFIER_KEY_CONTEXT.into()).into()); + match binding.predicate() { + Some(predicate) if required_predicate.is_superset(&predicate) => { + return Ok(()); + } + _ => {} + } + Err(MarkdownString(format!( + "{} can only be bound to a single keystroke with modifiers, so \ + that holding down these modifiers can be used to preview \ + completions inline when the completions menu is open.\n\n\ + This restriction does not apply when the context requires {}, \ + since these bindings will not be used when the completions menu \ + is open.", + MarkdownString::inline_code(AcceptEditPrediction.name()), + MarkdownString::inline_code(&format!( + "!{}", + EDIT_PREDICTION_REQUIRES_MODIFIER_KEY_CONTEXT + )), + ))) + } +} + #[allow(clippy::too_many_arguments)] fn prepaint_gutter_button( button: IconButton, diff --git a/crates/extension_host/src/wasm_host/wit/since_v0_0_1.rs b/crates/extension_host/src/wasm_host/wit/since_v0_0_1.rs index 1f0891b4105f9ccf2dae45d04c6d75debfb818f0..1ce43ca2030a5cdc8c9cb17a5adbbf37573d3784 100644 --- a/crates/extension_host/src/wasm_host/wit/since_v0_0_1.rs +++ b/crates/extension_host/src/wasm_host/wit/since_v0_0_1.rs @@ -84,7 +84,7 @@ impl HostWorktree for WasmState { latest::HostWorktree::which(self, delegate, binary_name).await } - fn drop(&mut self, _worktree: Resource) -> Result<()> { + async fn drop(&mut self, _worktree: Resource) -> Result<()> { Ok(()) } } diff --git a/crates/extension_host/src/wasm_host/wit/since_v0_0_4.rs b/crates/extension_host/src/wasm_host/wit/since_v0_0_4.rs index b88a444f01c379d288ef0fda3c7441a343b278f1..315f69fc278829de07658844c0a16eff2471cb59 100644 --- a/crates/extension_host/src/wasm_host/wit/since_v0_0_4.rs +++ b/crates/extension_host/src/wasm_host/wit/since_v0_0_4.rs @@ -92,7 +92,7 @@ impl HostWorktree for WasmState { latest::HostWorktree::which(self, delegate, binary_name).await } - fn drop(&mut self, _worktree: Resource) -> Result<()> { + async fn drop(&mut self, _worktree: Resource) -> Result<()> { // We only ever hand out borrows of worktrees. Ok(()) } diff --git a/crates/extension_host/src/wasm_host/wit/since_v0_0_6.rs b/crates/extension_host/src/wasm_host/wit/since_v0_0_6.rs index 68681936a472014682a1d1d1ebda6c4411beb897..98ecdf40ec3b2d5820863d05e94bfc03fc28c88b 100644 --- a/crates/extension_host/src/wasm_host/wit/since_v0_0_6.rs +++ b/crates/extension_host/src/wasm_host/wit/since_v0_0_6.rs @@ -147,7 +147,7 @@ impl HostWorktree for WasmState { latest::HostWorktree::which(self, delegate, binary_name).await } - fn drop(&mut self, _worktree: Resource) -> Result<()> { + async fn drop(&mut self, _worktree: Resource) -> Result<()> { // We only ever hand out borrows of worktrees. Ok(()) } diff --git a/crates/extension_host/src/wasm_host/wit/since_v0_1_0.rs b/crates/extension_host/src/wasm_host/wit/since_v0_1_0.rs index c1c07a2b09be5f785a9cb0dfb8d781302716e311..058a86ab361b8124e78ef6c8860fad28f39c3cc2 100644 --- a/crates/extension_host/src/wasm_host/wit/since_v0_1_0.rs +++ b/crates/extension_host/src/wasm_host/wit/since_v0_1_0.rs @@ -240,7 +240,7 @@ impl HostKeyValueStore for WasmState { kv_store.insert(key, value).await.to_wasmtime_result() } - fn drop(&mut self, _worktree: Resource) -> Result<()> { + async fn drop(&mut self, _worktree: Resource) -> Result<()> { // We only ever hand out borrows of key-value stores. Ok(()) } @@ -282,7 +282,7 @@ impl HostWorktree for WasmState { latest::HostWorktree::which(self, delegate, binary_name).await } - fn drop(&mut self, _worktree: Resource) -> Result<()> { + async fn drop(&mut self, _worktree: Resource) -> Result<()> { // We only ever hand out borrows of worktrees. Ok(()) } @@ -350,7 +350,7 @@ impl http_client::HostHttpResponseStream for WasmState { .to_wasmtime_result() } - fn drop(&mut self, _resource: Resource) -> Result<()> { + async fn drop(&mut self, _resource: Resource) -> Result<()> { Ok(()) } } diff --git a/crates/extension_host/src/wasm_host/wit/since_v0_2_0.rs b/crates/extension_host/src/wasm_host/wit/since_v0_2_0.rs index b722d7b235218861759451ecae005852ac4d2d82..f9bebf0c01e4c4df744de2f1e665f9a13370787f 100644 --- a/crates/extension_host/src/wasm_host/wit/since_v0_2_0.rs +++ b/crates/extension_host/src/wasm_host/wit/since_v0_2_0.rs @@ -259,7 +259,7 @@ impl HostKeyValueStore for WasmState { kv_store.insert(key, value).await.to_wasmtime_result() } - fn drop(&mut self, _worktree: Resource) -> Result<()> { + async fn drop(&mut self, _worktree: Resource) -> Result<()> { // We only ever hand out borrows of key-value stores. Ok(()) } @@ -275,7 +275,7 @@ impl HostProject for WasmState { Ok(project.worktree_ids()) } - fn drop(&mut self, _project: Resource) -> Result<()> { + async fn drop(&mut self, _project: Resource) -> Result<()> { // We only ever hand out borrows of projects. Ok(()) } @@ -325,7 +325,7 @@ impl HostWorktree for WasmState { Ok(delegate.which(binary_name).await) } - fn drop(&mut self, _worktree: Resource) -> Result<()> { + async fn drop(&mut self, _worktree: Resource) -> Result<()> { // We only ever hand out borrows of worktrees. Ok(()) } @@ -393,7 +393,7 @@ impl http_client::HostHttpResponseStream for WasmState { .to_wasmtime_result() } - fn drop(&mut self, _resource: Resource) -> Result<()> { + async fn drop(&mut self, _resource: Resource) -> Result<()> { Ok(()) } } diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 05a5b28e764dc56486858f87ee87bdced7b3a53d..5c692860c96bbcec002074b2d4bf2054f128dc57 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -79,7 +79,7 @@ futures.workspace = true gpui_macros.workspace = true http_client = { optional = true, workspace = true } image = "0.25.1" -inventory = "0.3.19" +inventory.workspace = true itertools.workspace = true log.workspace = true num_cpus = "1.13" diff --git a/crates/language/Cargo.toml b/crates/language/Cargo.toml index cd0fceea0c697dd4dc07b31f3c7910ee92f5158c..c38eea518f0c0ac380a8bb037725eb5efa50c015 100644 --- a/crates/language/Cargo.toml +++ b/crates/language/Cargo.toml @@ -53,6 +53,7 @@ settings.workspace = true similar.workspace = true smallvec.workspace = true smol.workspace = true +streaming-iterator.workspace = true strsim.workspace = true sum_tree.workspace = true task.workspace = true diff --git a/crates/language/src/outline.rs b/crates/language/src/outline.rs index 7f62f221a6af3ab4bcd2b2ae3493d6d494c7ce13..2b700fd69c290c08f1ae4c90d5238f92f5c04d0b 100644 --- a/crates/language/src/outline.rs +++ b/crates/language/src/outline.rs @@ -146,7 +146,9 @@ impl Outline { } } else { let mut name_ranges = outline_match.name_ranges.iter(); - let mut name_range = name_ranges.next().unwrap(); + let Some(mut name_range) = name_ranges.next() else { + continue; + }; let mut preceding_ranges_len = 0; for position in &mut string_match.positions { while *position >= preceding_ranges_len + name_range.len() { @@ -194,6 +196,40 @@ impl Outline { #[cfg(test)] mod tests { use super::*; + use gpui::TestAppContext; + + #[gpui::test] + async fn test_entries_with_no_names(cx: &mut TestAppContext) { + let outline = Outline::new(vec![ + OutlineItem { + depth: 0, + range: Point::new(0, 0)..Point::new(5, 0), + text: "class Foo".to_string(), + highlight_ranges: vec![], + name_ranges: vec![6..9], + body_range: None, + annotation_range: None, + }, + OutlineItem { + depth: 0, + range: Point::new(2, 0)..Point::new(2, 7), + text: "private".to_string(), + highlight_ranges: vec![], + name_ranges: vec![], + body_range: None, + annotation_range: None, + }, + ]); + assert_eq!( + outline + .search(" ", cx.executor()) + .await + .into_iter() + .map(|mat| mat.string) + .collect::>(), + vec!["class Foo".to_string()] + ); + } #[test] fn test_find_most_similar_with_low_similarity() { diff --git a/crates/language/src/syntax_map.rs b/crates/language/src/syntax_map.rs index 2a0c7eaa1cab51bb62dc3102bd7d31755d255fd5..7369501a06f1ebb5da093fd4309fc26e43fd60c9 100644 --- a/crates/language/src/syntax_map.rs +++ b/crates/language/src/syntax_map.rs @@ -14,6 +14,7 @@ use std::{ ops::{Deref, DerefMut, Range}, sync::Arc, }; +use streaming_iterator::StreamingIterator; use sum_tree::{Bias, SeekTarget, SumTree}; use text::{Anchor, BufferSnapshot, OffsetRangeExt, Point, Rope, ToOffset, ToPoint}; use tree_sitter::{Node, Query, QueryCapture, QueryCaptures, QueryCursor, QueryMatches, Tree}; @@ -1143,7 +1144,7 @@ impl<'a> SyntaxMapMatches<'a> { impl<'a> SyntaxMapCapturesLayer<'a> { fn advance(&mut self) { - self.next_capture = self.captures.next().map(|(mat, ix)| mat.captures[ix]); + self.next_capture = self.captures.next().map(|(mat, ix)| mat.captures[*ix]); } fn sort_key(&self) -> (usize, Reverse, usize) { @@ -1280,7 +1281,8 @@ fn get_injections( for query_range in changed_ranges { query_cursor.set_byte_range(query_range.start.saturating_sub(1)..query_range.end + 1); - for mat in query_cursor.matches(&config.query, node, TextProvider(text.as_rope())) { + let mut matches = query_cursor.matches(&config.query, node, TextProvider(text.as_rope())); + while let Some(mat) = matches.next() { let content_ranges = mat .nodes_for_capture_index(config.content_capture_ix) .map(|node| node.range()) @@ -1554,7 +1556,8 @@ impl<'a> SyntaxLayer<'a> { query_cursor.set_byte_range(offset.saturating_sub(1)..offset.saturating_add(1)); let mut smallest_match: Option<(u32, Range)> = None; - for mat in query_cursor.matches(&config.query, self.node(), text) { + let mut matches = query_cursor.matches(&config.query, self.node(), text); + while let Some(mat) = matches.next() { for capture in mat.captures { let Some(override_entry) = config.values.get(&capture.index) else { continue; diff --git a/crates/migrator/Cargo.toml b/crates/migrator/Cargo.toml index 7a65db5b9959941c5c916e67a67379ae7df58f9c..865f4278fe5b94def083f25c09b1b32cd5fa6f03 100644 --- a/crates/migrator/Cargo.toml +++ b/crates/migrator/Cargo.toml @@ -15,6 +15,8 @@ doctest = false [dependencies] collections.workspace = true convert_case.workspace = true +log.workspace = true +streaming-iterator.workspace = true tree-sitter-json.workspace = true tree-sitter.workspace = true diff --git a/crates/migrator/src/migrator.rs b/crates/migrator/src/migrator.rs index 0d02a45fb890aaf787b4d750caa6a15c2b3f67fc..72016ecdfeead3ce63da034b75108fbde1107c3c 100644 --- a/crates/migrator/src/migrator.rs +++ b/crates/migrator/src/migrator.rs @@ -1,6 +1,7 @@ use collections::HashMap; use convert_case::{Case, Casing}; use std::{cmp::Reverse, ops::Range, sync::LazyLock}; +use streaming_iterator::StreamingIterator; use tree_sitter::{Query, QueryMatch}; fn migrate(text: &str, patterns: MigrationPatterns, query: &Query) -> Option { @@ -11,10 +12,10 @@ fn migrate(text: &str, patterns: MigrationPatterns, query: &Query) -> Option Option TypeId; + fn validate(&self, binding: &KeyBinding) -> Result<(), MarkdownString>; +} + +pub struct KeyBindingValidatorRegistration(pub fn() -> Box); + +inventory::collect!(KeyBindingValidatorRegistration); + +pub(crate) static KEY_BINDING_VALIDATORS: LazyLock>> = + LazyLock::new(|| { + let mut validators = BTreeMap::new(); + for validator_registration in inventory::iter:: { + let validator = validator_registration.0(); + validators.insert(validator.action_type_id(), validator); + } + validators + }); + // Note that the doc comments on these are shown by json-language-server when editing the keymap, so // they should be considered user-facing documentation. Documentation is not handled well with // schemars-0.8 - when there are newlines, it is rendered as plaintext (see @@ -255,9 +273,16 @@ impl KeymapFile { key_bindings.push(key_binding); } Err(err) => { + let mut lines = err.lines(); + let mut indented_err = lines.next().unwrap().to_string(); + for line in lines { + indented_err.push_str(" "); + indented_err.push_str(line); + indented_err.push_str("\n"); + } write!( section_errors, - "\n\n - In binding {}, {err}", + "\n\n- In binding {}, {indented_err}", inline_code_string(keystrokes), ) .unwrap(); @@ -367,13 +392,24 @@ impl KeymapFile { }, }; - match KeyBinding::load(keystrokes, action, context, key_equivalents) { - Ok(binding) => Ok(binding), - Err(InvalidKeystrokeError { keystroke }) => Err(format!( - "invalid keystroke {}. {}", - inline_code_string(&keystroke), - KEYSTROKE_PARSE_EXPECTED_MESSAGE - )), + let key_binding = match KeyBinding::load(keystrokes, action, context, key_equivalents) { + Ok(key_binding) => key_binding, + Err(InvalidKeystrokeError { keystroke }) => { + return Err(format!( + "invalid keystroke {}. {}", + inline_code_string(&keystroke), + KEYSTROKE_PARSE_EXPECTED_MESSAGE + )) + } + }; + + if let Some(validator) = KEY_BINDING_VALIDATORS.get(&key_binding.action().type_id()) { + match validator.validate(&key_binding) { + Ok(()) => Ok(key_binding), + Err(error) => Err(error.0), + } + } else { + Ok(key_binding) } } diff --git a/crates/settings/src/settings.rs b/crates/settings/src/settings.rs index aa3176c69a3abef960ec2d2792ae5dbfb71bd8ab..cfec7f2d168f9b764801c7cb14b5c1e294f4e9bd 100644 --- a/crates/settings/src/settings.rs +++ b/crates/settings/src/settings.rs @@ -13,7 +13,9 @@ use util::asset_str; pub use editable_setting_control::*; pub use json_schema::*; pub use key_equivalents::*; -pub use keymap_file::{KeymapFile, KeymapFileLoadResult}; +pub use keymap_file::{ + KeyBindingValidator, KeyBindingValidatorRegistration, KeymapFile, KeymapFileLoadResult, +}; pub use settings_file::*; pub use settings_store::{ parse_json_with_comments, InvalidSettingsError, LocalSettingsKind, Settings, SettingsLocation, diff --git a/crates/settings/src/settings_store.rs b/crates/settings/src/settings_store.rs index 6f69909b934432155f28d2ad696aa7464b87d516..de51986916b922b83296a6bd5ecb7fa90bf939ad 100644 --- a/crates/settings/src/settings_store.rs +++ b/crates/settings/src/settings_store.rs @@ -17,6 +17,7 @@ use std::{ str::{self, FromStr}, sync::{Arc, LazyLock}, }; +use streaming_iterator::StreamingIterator; use tree_sitter::Query; use util::RangeExt; @@ -1262,8 +1263,8 @@ fn replace_value_in_json_text( let mut last_value_range = 0..0; let mut first_key_start = None; let mut existing_value_range = 0..text.len(); - let matches = cursor.matches(&PAIR_QUERY, syntax_tree.root_node(), text.as_bytes()); - for mat in matches { + let mut matches = cursor.matches(&PAIR_QUERY, syntax_tree.root_node(), text.as_bytes()); + while let Some(mat) = matches.next() { if mat.captures.len() != 2 { continue; } diff --git a/crates/ui/src/components/context_menu.rs b/crates/ui/src/components/context_menu.rs index b827a576673f7ffefc4421c7791237fcce13679f..2ebaa551052ffecdea235d179d94f47c742c2a67 100644 --- a/crates/ui/src/components/context_menu.rs +++ b/crates/ui/src/components/context_menu.rs @@ -671,18 +671,16 @@ impl Render for ContextMenu { .when_some( *toggle, |list_item, (position, toggled)| { - let contents = if toggled { + let contents = div().flex_none().child( Icon::new(IconName::Check) .color(Color::Accent) .size(*icon_size) ) - } else { - div().flex_none().child( - Icon::new(IconName::Check) - .size(*icon_size) - ).invisible() - }; + .when(!toggled, |contents| + contents.invisible() + ); + match position { IconPosition::Start => { list_item