From 6737ee14958dacdaea5d5ec3015ae5798847574d Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 6 Jun 2023 16:04:27 -0700 Subject: [PATCH 1/4] Avoid panic when failing to load a language's queries --- crates/language/src/language.rs | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 19ae94857405e9e9aaa6d27beb7a7742e825bf86..32d74c9aefea637572643974b4b0439ba392902d 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -771,6 +771,7 @@ impl LanguageRegistry { } } Err(err) => { + log::error!("failed to load language {name} - {err}"); let mut state = this.state.write(); state.mark_language_loaded(id); if let Some(mut txs) = state.loading_languages.remove(&id) { @@ -1059,34 +1060,22 @@ impl Language { pub fn with_queries(mut self, queries: LanguageQueries) -> Result { if let Some(query) = queries.highlights { - self = self - .with_highlights_query(query.as_ref()) - .expect("failed to evaluate highlights query"); + self = self.with_highlights_query(query.as_ref())?; } if let Some(query) = queries.brackets { - self = self - .with_brackets_query(query.as_ref()) - .expect("failed to load brackets query"); + self = self.with_brackets_query(query.as_ref())?; } if let Some(query) = queries.indents { - self = self - .with_indents_query(query.as_ref()) - .expect("failed to load indents query"); + self = self.with_indents_query(query.as_ref())?; } if let Some(query) = queries.outline { - self = self - .with_outline_query(query.as_ref()) - .expect("failed to load outline query"); + self = self.with_outline_query(query.as_ref())?; } if let Some(query) = queries.injections { - self = self - .with_injection_query(query.as_ref()) - .expect("failed to load injection query"); + self = self.with_injection_query(query.as_ref())?; } if let Some(query) = queries.overrides { - self = self - .with_override_query(query.as_ref()) - .expect("failed to load override query"); + self = self.with_override_query(query.as_ref())?; } Ok(self) } From 8dc679e74e8a1d30b2ad1173d3abfbc8a688ddc9 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 6 Jun 2023 16:04:46 -0700 Subject: [PATCH 2/4] Upgrade tree-sitter-elixir --- Cargo.lock | 4 ++-- crates/zed/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a1ba2a4998f34bea26b14d28e909341fb6efc972..6dbfa27309c32a5b952bc0322db1e2116fc26d99 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7342,8 +7342,8 @@ dependencies = [ [[package]] name = "tree-sitter-elixir" -version = "0.19.0" -source = "git+https://github.com/elixir-lang/tree-sitter-elixir?rev=05e3631c6a0701c1fa518b0fee7be95a2ceef5e2#05e3631c6a0701c1fa518b0fee7be95a2ceef5e2" +version = "0.1.0" +source = "git+https://github.com/elixir-lang/tree-sitter-elixir?rev=4ba9dab6e2602960d95b2b625f3386c27e08084e#4ba9dab6e2602960d95b2b625f3386c27e08084e" dependencies = [ "cc", "tree-sitter", diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 8add2e71c1135805517ec15d25e3c4448b5d630c..54919445cb2a3326000d2acb8b9ae99021bd206e 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -106,7 +106,7 @@ tree-sitter = "0.20" tree-sitter-c = "0.20.1" tree-sitter-cpp = "0.20.0" tree-sitter-css = { git = "https://github.com/tree-sitter/tree-sitter-css", rev = "769203d0f9abe1a9a691ac2b9fe4bb4397a73c51" } -tree-sitter-elixir = { git = "https://github.com/elixir-lang/tree-sitter-elixir", rev = "05e3631c6a0701c1fa518b0fee7be95a2ceef5e2" } +tree-sitter-elixir = { git = "https://github.com/elixir-lang/tree-sitter-elixir", rev = "4ba9dab6e2602960d95b2b625f3386c27e08084e" } tree-sitter-embedded-template = "0.20.0" tree-sitter-go = { git = "https://github.com/tree-sitter/tree-sitter-go", rev = "aeb2f33b366fd78d5789ff104956ce23508b85db" } tree-sitter-json = { git = "https://github.com/tree-sitter/tree-sitter-json", rev = "40a81c01a40ac48744e0c8ccabbaba1920441199" } From 7aeaa846579a1588747e748e3b65e922e6af4597 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 6 Jun 2023 15:12:07 -0700 Subject: [PATCH 3/4] Fix the order of some patterns in elixir highlight query --- .../zed/src/languages/elixir/highlights.scm | 47 ++++++++----------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/crates/zed/src/languages/elixir/highlights.scm b/crates/zed/src/languages/elixir/highlights.scm index 5c256f341cd5a2e4e045ec4cc3610eabeac3a88a..deea51c436386eb36b1ed41d61cb5d21a787ad20 100644 --- a/crates/zed/src/languages/elixir/highlights.scm +++ b/crates/zed/src/languages/elixir/highlights.scm @@ -1,20 +1,5 @@ ["when" "and" "or" "not" "in" "not in" "fn" "do" "end" "catch" "rescue" "after" "else"] @keyword -(unary_operator - operator: "@" @comment.doc - operand: (call - target: (identifier) @comment.doc.__attribute__ - (arguments - [ - (string) @comment.doc - (charlist) @comment.doc - (sigil - quoted_start: _ @comment.doc - quoted_end: _ @comment.doc) @comment.doc - (boolean) @comment.doc - ])) - (#match? @comment.doc.__attribute__ "^(moduledoc|typedoc|doc)$")) - (unary_operator operator: "&" operand: (integer) @operator) @@ -84,6 +69,11 @@ quoted_start: _ @string.special quoted_end: _ @string.special) @string.special +( + (identifier) @comment.unused + (#match? @comment.unused "^_") +) + (call target: [ (identifier) @function @@ -99,17 +89,12 @@ (binary_operator left: (identifier) @function operator: "when") + (binary_operator + operator: "|>" + right: (identifier)) ]) (#match? @keyword "^(def|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defp)$")) -(call - target: (identifier) @keyword - (arguments - (binary_operator - operator: "|>" - right: (identifier))) - (#match? @keyword "^(def|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defp)$")) - (binary_operator operator: "|>" right: (identifier) @function) @@ -127,10 +112,18 @@ (#match? @constant.builtin "^(__MODULE__|__DIR__|__ENV__|__CALLER__|__STACKTRACE__)$") ) -( - (identifier) @comment.unused - (#match? @comment.unused "^_") -) +(unary_operator + operator: "@" @comment.doc + operand: (call + target: (identifier) @__attribute__ @comment.doc + (arguments + [ + (string) + (charlist) + (sigil) + (boolean) + ] @comment.doc)) + (#match? @__attribute__ "^(moduledoc|typedoc|doc)$")) (comment) @comment From 4b9a3c66e6e51716d3b16912ad6a60c9724674e2 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 6 Jun 2023 16:06:01 -0700 Subject: [PATCH 4/4] Show function parameters in elixir outline view Introduce a new capture in the outline query called 'context.extra', which causes text to appear in the outline, but not in the breadcrumbs. --- crates/language/src/buffer.rs | 13 ++++-- crates/language/src/buffer_tests.rs | 46 +++++++++++++++++++++ crates/language/src/language.rs | 4 ++ crates/zed/src/languages/elixir/indents.scm | 4 +- crates/zed/src/languages/elixir/outline.scm | 14 ++++++- crates/zed/src/languages/typescript.rs | 6 +-- 6 files changed, 76 insertions(+), 11 deletions(-) diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 7acb36a92f8f87ed7f0d18b093a5cefe7068f6b1..e09ee48da630989774abdbf0bdffd386afa44a1b 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -2253,7 +2253,7 @@ impl BufferSnapshot { } pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option> { - self.outline_items_containing(0..self.len(), theme) + self.outline_items_containing(0..self.len(), true, theme) .map(Outline::new) } @@ -2265,6 +2265,7 @@ impl BufferSnapshot { let position = position.to_offset(self); let mut items = self.outline_items_containing( position.saturating_sub(1)..self.len().min(position + 1), + false, theme, )?; let mut prev_depth = None; @@ -2279,6 +2280,7 @@ impl BufferSnapshot { fn outline_items_containing( &self, range: Range, + include_extra_context: bool, theme: Option<&SyntaxTheme>, ) -> Option>> { let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| { @@ -2313,7 +2315,10 @@ impl BufferSnapshot { let node_is_name; if capture.index == config.name_capture_ix { node_is_name = true; - } else if Some(capture.index) == config.context_capture_ix { + } else if Some(capture.index) == config.context_capture_ix + || (Some(capture.index) == config.extra_context_capture_ix + && include_extra_context) + { node_is_name = false; } else { continue; @@ -2340,10 +2345,12 @@ impl BufferSnapshot { buffer_ranges.first().unwrap().0.start..buffer_ranges.last().unwrap().0.end, true, ); + let mut last_buffer_range_end = 0; for (buffer_range, is_name) in buffer_ranges { - if !text.is_empty() { + if !text.is_empty() && buffer_range.start > last_buffer_range_end { text.push(' '); } + last_buffer_range_end = buffer_range.end; if is_name { let mut start = text.len(); let end = start + buffer_range.len(); diff --git a/crates/language/src/buffer_tests.rs b/crates/language/src/buffer_tests.rs index be573aa8956e3dc28e7074d17f85160fe5f2d1e9..9f44de40ac1f4010f7e335277c38e594650f0140 100644 --- a/crates/language/src/buffer_tests.rs +++ b/crates/language/src/buffer_tests.rs @@ -592,6 +592,52 @@ async fn test_outline_nodes_with_newlines(cx: &mut gpui::TestAppContext) { ); } +#[gpui::test] +async fn test_outline_with_extra_context(cx: &mut gpui::TestAppContext) { + let language = javascript_lang() + .with_outline_query( + r#" + (function_declaration + "function" @context + name: (_) @name + parameters: (formal_parameters + "(" @context.extra + ")" @context.extra)) @item + "#, + ) + .unwrap(); + + let text = r#" + function a() {} + function b(c) {} + "# + .unindent(); + + let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(language), cx)); + let snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot()); + + // extra context nodes are included in the outline. + let outline = snapshot.outline(None).unwrap(); + assert_eq!( + outline + .items + .iter() + .map(|item| (item.text.as_str(), item.depth)) + .collect::>(), + &[("function a()", 0), ("function b( )", 0),] + ); + + // extra context nodes do not appear in breadcrumbs. + let symbols = snapshot.symbols_containing(3, None).unwrap(); + assert_eq!( + symbols + .iter() + .map(|item| (item.text.as_str(), item.depth)) + .collect::>(), + &[("function a", 0)] + ); +} + #[gpui::test] async fn test_symbols_containing(cx: &mut gpui::TestAppContext) { let text = r#" diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 32d74c9aefea637572643974b4b0439ba392902d..0ff1d973d3ff47d7e67a82a7639ddcac810702eb 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -455,6 +455,7 @@ struct OutlineConfig { item_capture_ix: u32, name_capture_ix: u32, context_capture_ix: Option, + extra_context_capture_ix: Option, } struct InjectionConfig { @@ -1091,12 +1092,14 @@ impl Language { let mut item_capture_ix = None; let mut name_capture_ix = None; let mut context_capture_ix = None; + let mut extra_context_capture_ix = None; get_capture_indices( &query, &mut [ ("item", &mut item_capture_ix), ("name", &mut name_capture_ix), ("context", &mut context_capture_ix), + ("context.extra", &mut extra_context_capture_ix), ], ); if let Some((item_capture_ix, name_capture_ix)) = item_capture_ix.zip(name_capture_ix) { @@ -1105,6 +1108,7 @@ impl Language { item_capture_ix, name_capture_ix, context_capture_ix, + extra_context_capture_ix, }); } Ok(self) diff --git a/crates/zed/src/languages/elixir/indents.scm b/crates/zed/src/languages/elixir/indents.scm index e4139841fc2d2d0ec0bc03f6f76786b76621f77e..ab6fc4da67c95aa1ba8fabdbc10d53b5d7c5e40e 100644 --- a/crates/zed/src/languages/elixir/indents.scm +++ b/crates/zed/src/languages/elixir/indents.scm @@ -1,6 +1,4 @@ -[ - (call) -] @indent +(call) @indent (_ "[" "]" @end) @indent (_ "{" "}" @end) @indent diff --git a/crates/zed/src/languages/elixir/outline.scm b/crates/zed/src/languages/elixir/outline.scm index 985c8ffdca68ab420470a2eaa4f71ab658a9ec30..a3311fb6d4640aa4ff5469c638022c1fde02e912 100644 --- a/crates/zed/src/languages/elixir/outline.scm +++ b/crates/zed/src/languages/elixir/outline.scm @@ -8,9 +8,19 @@ (arguments [ (identifier) @name - (call target: (identifier) @name) + (call + target: (identifier) @name + (arguments + "(" @context.extra + _* @context.extra + ")" @context.extra)) (binary_operator - left: (call target: (identifier) @name) + left: (call + target: (identifier) @name + (arguments + "(" @context.extra + _* @context.extra + ")" @context.extra)) operator: "when") ]) (#match? @context "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @item diff --git a/crates/zed/src/languages/typescript.rs b/crates/zed/src/languages/typescript.rs index a25d7d02ea550b84a88482be86d3501ecea8032d..7d2d580857780a714496a5f8c2c850de36986d26 100644 --- a/crates/zed/src/languages/typescript.rs +++ b/crates/zed/src/languages/typescript.rs @@ -327,10 +327,10 @@ mod tests { .map(|item| (item.text.as_str(), item.depth)) .collect::>(), &[ - ("function a ( )", 0), - ("async function a2 ( )", 1), + ("function a()", 0), + ("async function a2()", 1), ("let b", 0), - ("function getB ( )", 0), + ("function getB()", 0), ("const d", 0), ] );