From bfec9e1ec265ced959d5a013b61991e608e33c41 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 22 Apr 2022 13:49:03 -0700 Subject: [PATCH] Fix missing TypeScript outline entries and breadcrumbs --- crates/language/Cargo.toml | 4 +- crates/language/src/buffer.rs | 13 +++-- crates/zed/src/languages.rs | 2 +- crates/zed/src/languages/typescript.rs | 51 +++++++++++++++++++ .../zed/src/languages/typescript/outline.scm | 10 ++++ 5 files changed, 72 insertions(+), 8 deletions(-) diff --git a/crates/language/Cargo.toml b/crates/language/Cargo.toml index 275581f807..fd901fd769 100644 --- a/crates/language/Cargo.toml +++ b/crates/language/Cargo.toml @@ -57,6 +57,6 @@ util = { path = "../util", features = ["test-support"] } ctor = "0.1" env_logger = "0.8" rand = "0.8.3" -tree-sitter-json = "0.19.0" -tree-sitter-rust = "0.20.0" +tree-sitter-json = "*" +tree-sitter-rust = "*" unindent = "0.1.7" diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 95aa27b6d2..30c428ce50 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -1730,7 +1730,7 @@ impl BufferSnapshot { .and_then(|language| language.grammar.as_ref())?; let mut cursor = QueryCursorHandle::new(); - cursor.set_byte_range(range); + cursor.set_byte_range(range.clone()); let matches = cursor.matches( &grammar.outline_query, tree.root_node(), @@ -1750,7 +1750,10 @@ impl BufferSnapshot { let items = matches .filter_map(|mat| { let item_node = mat.nodes_for_capture_index(item_capture_ix).next()?; - let range = item_node.start_byte()..item_node.end_byte(); + let item_range = item_node.start_byte()..item_node.end_byte(); + if item_range.end < range.start || item_range.start > range.end { + return None; + } let mut text = String::new(); let mut name_ranges = Vec::new(); let mut highlight_ranges = Vec::new(); @@ -1808,15 +1811,15 @@ impl BufferSnapshot { } while stack.last().map_or(false, |prev_range| { - !prev_range.contains(&range.start) || !prev_range.contains(&range.end) + !prev_range.contains(&item_range.start) || !prev_range.contains(&item_range.end) }) { stack.pop(); } - stack.push(range.clone()); + stack.push(item_range.clone()); Some(OutlineItem { depth: stack.len() - 1, - range: self.anchor_after(range.start)..self.anchor_before(range.end), + range: self.anchor_after(item_range.start)..self.anchor_before(item_range.end), text, highlight_ranges, name_ranges, diff --git a/crates/zed/src/languages.rs b/crates/zed/src/languages.rs index d0d6de989a..36900e3e71 100644 --- a/crates/zed/src/languages.rs +++ b/crates/zed/src/languages.rs @@ -63,7 +63,7 @@ pub fn build_language_registry(login_shell_env_loaded: Task<()>) -> LanguageRegi languages } -fn language( +pub(crate) fn language( name: &str, grammar: tree_sitter::Language, lsp_adapter: Option>, diff --git a/crates/zed/src/languages/typescript.rs b/crates/zed/src/languages/typescript.rs index aca8cdef52..79c74c521d 100644 --- a/crates/zed/src/languages/typescript.rs +++ b/crates/zed/src/languages/typescript.rs @@ -144,3 +144,54 @@ impl LspAdapter for TypeScriptLspAdapter { })) } } + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use gpui::MutableAppContext; + use unindent::Unindent; + + #[gpui::test] + fn test_outline(cx: &mut MutableAppContext) { + let language = crate::languages::language( + "typescript", + tree_sitter_typescript::language_typescript(), + None, + ); + + let text = r#" + function a() { + // local variables are omitted + let a1 = 1; + // all functions are included + async function a2() {} + } + // top-level variables are included + let b: C + function getB() {} + // exported variables are included + export const d = e; + "# + .unindent(); + + let buffer = cx.add_model(|cx| { + language::Buffer::new(0, text, cx).with_language(Arc::new(language), cx) + }); + let outline = buffer.read(cx).snapshot().outline(None).unwrap(); + assert_eq!( + outline + .items + .iter() + .map(|item| (item.text.as_str(), item.depth)) + .collect::>(), + &[ + ("function a ( )", 0), + ("async function a2 ( )", 1), + ("let b", 0), + ("function getB ( )", 0), + ("const d", 0), + ] + ); + } +} diff --git a/crates/zed/src/languages/typescript/outline.scm b/crates/zed/src/languages/typescript/outline.scm index f8691fa41d..68d297653e 100644 --- a/crates/zed/src/languages/typescript/outline.scm +++ b/crates/zed/src/languages/typescript/outline.scm @@ -6,6 +6,10 @@ "enum" @context name: (_) @name) @item +(type_alias_declaration + "type" @context + name: (_) @name) @item + (function_declaration "async"? @context "function" @context @@ -18,6 +22,12 @@ "interface" @context name: (_) @name) @item +(export_statement + (lexical_declaration + ["let" "const"] @context + (variable_declarator + name: (_) @name) @item)) + (program (lexical_declaration ["let" "const"] @context