From d9909c691d4007d33bac180e07054fe3d8c63557 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 10 Feb 2025 10:50:26 -0800 Subject: [PATCH 1/5] Fix panic when outline items have no name (#24574) Closes #23787 Release Notes: - Fixed a crash when searching the outline view in certain Ruby files. --- crates/language/src/outline.rs | 38 +++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) 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() { From 72e1947025449448dc508fc3dbd4092355b0d522 Mon Sep 17 00:00:00 2001 From: Liam Murphy Date: Tue, 11 Feb 2025 05:52:27 +1100 Subject: [PATCH 2/5] Update tree-sitter to 0.24 (#24492) I didn't update it to 0.25 because its Wasm support seems to be partially broken due to https://github.com/tree-sitter/tree-sitter/pull/3938: it didn't introduce a check that the Wasm module's ABI is new enough to include supertype info while parsing it, and so in the case where it isn't it ends up interpreting random bytes as the number of supertypes, causing out-of-bounds memory accesses. Closes #24489 Release Notes: - Fixed a rare crash during syntax highlighting --- Cargo.lock | 209 +++++++++--------- Cargo.toml | 11 +- crates/editor/src/editor_tests.rs | 2 +- .../src/wasm_host/wit/since_v0_0_1.rs | 2 +- .../src/wasm_host/wit/since_v0_0_4.rs | 2 +- .../src/wasm_host/wit/since_v0_0_6.rs | 2 +- .../src/wasm_host/wit/since_v0_1_0.rs | 6 +- .../src/wasm_host/wit/since_v0_2_0.rs | 8 +- crates/language/Cargo.toml | 1 + crates/language/src/syntax_map.rs | 9 +- crates/migrator/Cargo.toml | 1 + crates/migrator/src/migrator.rs | 5 +- crates/semantic_index/Cargo.toml | 1 + crates/semantic_index/src/chunking.rs | 3 +- crates/settings/Cargo.toml | 1 + crates/settings/src/settings_store.rs | 5 +- 16 files changed, 141 insertions(+), 127 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 40f302224a5bbfbb11dfbf121532be066f7c45fc..c5b0bd3c77e9895d699e77c92d813d578930cbd0 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", ] @@ -4447,8 +4447,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 +4517,7 @@ dependencies = [ "toml 0.8.20", "url", "util", - "wasmparser 0.215.0", + "wasmparser 0.217.1", "wasmtime", "wasmtime-wasi", ] @@ -5699,15 +5699,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 +6903,7 @@ dependencies = [ "similar", "smallvec", "smol", + "streaming-iterator", "strsim", "sum_tree", "task", @@ -7887,6 +7879,7 @@ dependencies = [ "collections", "convert_case 0.7.1", "pretty_assertions", + "streaming-iterator", "tree-sitter", "tree-sitter-json", ] @@ -10781,13 +10774,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 +11851,7 @@ dependencies = [ "settings", "sha2", "smol", + "streaming-iterator", "tempfile", "theme", "tree-sitter", @@ -12049,6 +12043,7 @@ dependencies = [ "serde_json", "serde_json_lenient", "smallvec", + "streaming-iterator", "tree-sitter", "tree-sitter-json", "unindent", @@ -12732,6 +12727,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 +14032,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 +14938,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 +14987,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 +15001,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 +15042,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 +15058,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 +15081,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 +15091,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 +15101,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 +15127,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 +15155,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 +15164,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 +15179,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 +15191,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 +15222,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 +15253,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 +15270,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 +15496,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 +15511,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 +15526,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 +15569,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 +15579,7 @@ dependencies = [ "regalloc2", "smallvec", "target-lexicon", - "wasmparser 0.215.0", + "wasmparser 0.217.1", "wasmtime-cranelift", "wasmtime-environ", ] @@ -16128,9 +16131,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 +16144,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..b46372c8ce46274da02bdf22256649eabc493153 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -502,6 +502,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 +524,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 +553,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/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/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/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/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..11126016a6a1d41830a6ad046d2ff446b9d5c172 100644 --- a/crates/migrator/Cargo.toml +++ b/crates/migrator/Cargo.toml @@ -15,6 +15,7 @@ doctest = false [dependencies] collections.workspace = true convert_case.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..e50b7020173512d7f5f7eb338ecece77ad632f4e 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 Date: Mon, 10 Feb 2025 20:47:09 +0100 Subject: [PATCH 3/5] context_menu: Use `when` instead of if-block (#24566) See https://github.com/zed-industries/zed/pull/24562#issuecomment-2648343416 . Should have just added that to my original comment btw - sorry! CC @danilo-leal Release Notes: - N/A --- crates/ui/src/components/context_menu.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) 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 From 43afa68dab929d0d0e99eb97204d24a7ca5cd397 Mon Sep 17 00:00:00 2001 From: Michael Sloan Date: Mon, 10 Feb 2025 13:01:10 -0700 Subject: [PATCH 4/5] Make migration notification not display if some bug causes no changes (#24578) When working on #24442, I did a project wide replacement of `AcceptInlineCompletion` with `AcceptEditPrediction`, as I was updating the branch to mmain and that rename had happened. This also replaced it in the migrator, causing the migration notification to always pop up on keymap changes. Checking if the migration actually changes the text makes it behave better if this variety of bug happens in the future. Release Notes: - N/A --- Cargo.lock | 1 + crates/migrator/Cargo.toml | 1 + crates/migrator/src/migrator.rs | 16 ++++++++++++---- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c5b0bd3c77e9895d699e77c92d813d578930cbd0..4c9bf2c525cd50e00f700d1fa6eb979496f1c1d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7878,6 +7878,7 @@ version = "0.1.0" dependencies = [ "collections", "convert_case 0.7.1", + "log", "pretty_assertions", "streaming-iterator", "tree-sitter", diff --git a/crates/migrator/Cargo.toml b/crates/migrator/Cargo.toml index 11126016a6a1d41830a6ad046d2ff446b9d5c172..865f4278fe5b94def083f25c09b1b32cd5fa6f03 100644 --- a/crates/migrator/Cargo.toml +++ b/crates/migrator/Cargo.toml @@ -15,6 +15,7 @@ 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 e50b7020173512d7f5f7eb338ecece77ad632f4e..72016ecdfeead3ce63da034b75108fbde1107c3c 100644 --- a/crates/migrator/src/migrator.rs +++ b/crates/migrator/src/migrator.rs @@ -29,11 +29,19 @@ fn migrate(text: &str, patterns: MigrationPatterns, query: &Query) -> Option Date: Mon, 10 Feb 2025 13:01:42 -0700 Subject: [PATCH 5/5] Fix display of bindings for `editor::AcceptInlineCompletion` + add validation + use modifiers from keymap (#24442) Release Notes: - N/A --- Cargo.lock | 2 + Cargo.toml | 1 + crates/editor/Cargo.toml | 1 + crates/editor/src/editor.rs | 36 +++++- crates/editor/src/element.rs | 198 ++++++++++++----------------- crates/gpui/Cargo.toml | 2 +- crates/settings/Cargo.toml | 1 + crates/settings/src/keymap_file.rs | 58 +++++++-- crates/settings/src/settings.rs | 4 +- 9 files changed, 166 insertions(+), 137 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4c9bf2c525cd50e00f700d1fa6eb979496f1c1d4..c114e0ee526c1fa338cb57460daac4395f7a25c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4060,6 +4060,7 @@ dependencies = [ "http_client", "indoc", "inline_completion", + "inventory", "itertools 0.14.0", "language", "linkify", @@ -12032,6 +12033,7 @@ dependencies = [ "futures 0.3.31", "gpui", "indoc", + "inventory", "log", "migrator", "paths", diff --git a/Cargo.toml b/Cargo.toml index b46372c8ce46274da02bdf22256649eabc493153..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" } 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/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/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/settings/Cargo.toml b/crates/settings/Cargo.toml index bfac8236e5da4adf251743618f8197f1b64d8b92..a851b431f7c0eb259bc13d51164abf7c11e3bbb3 100644 --- a/crates/settings/Cargo.toml +++ b/crates/settings/Cargo.toml @@ -22,6 +22,7 @@ ec4rs.workspace = true fs.workspace = true futures.workspace = true gpui.workspace = true +inventory.workspace = true log.workspace = true paths.workspace = true release_channel.workspace = true diff --git a/crates/settings/src/keymap_file.rs b/crates/settings/src/keymap_file.rs index fb967bde3f57b5d730108d72c2e84190b4777363..f4de45270a14aac9485cd768798bd098a9e7f563 100644 --- a/crates/settings/src/keymap_file.rs +++ b/crates/settings/src/keymap_file.rs @@ -1,5 +1,5 @@ use anyhow::{anyhow, Context as _, Result}; -use collections::{HashMap, IndexMap}; +use collections::{BTreeMap, HashMap, IndexMap}; use fs::Fs; use gpui::{ Action, ActionBuildError, App, InvalidKeystrokeError, KeyBinding, KeyBindingContextPredicate, @@ -13,12 +13,30 @@ use schemars::{ }; use serde::{Deserialize, Serialize}; use serde_json::Value; -use std::rc::Rc; -use std::{fmt::Write, sync::Arc}; +use std::{any::TypeId, fmt::Write, rc::Rc, sync::Arc, sync::LazyLock}; use util::{asset_str, markdown::MarkdownString}; use crate::{settings_store::parse_json_with_comments, SettingsAssets}; +pub trait KeyBindingValidator: Send + Sync { + fn action_type_id(&self) -> 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,