Allow matching of context items in outline view

Antonio Scandurra created

Change summary

crates/editor/src/multi_buffer.rs |  1 
crates/language/src/buffer.rs     | 17 ---------
crates/language/src/outline.rs    | 28 ++------------
crates/language/src/tests.rs      | 62 +++++++++++++++++++++-----------
4 files changed, 44 insertions(+), 64 deletions(-)

Detailed changes

crates/editor/src/multi_buffer.rs 🔗

@@ -1712,7 +1712,6 @@ impl MultiBufferSnapshot {
                         ..self.anchor_in_excerpt(excerpt_id.clone(), item.range.end),
                     text: item.text,
                     highlight_ranges: item.highlight_ranges,
-                    name_ranges: item.name_ranges,
                 })
                 .collect(),
         ))

crates/language/src/buffer.rs 🔗

@@ -1864,15 +1864,11 @@ impl BufferSnapshot {
                 let item_node = mat.nodes_for_capture_index(item_capture_ix).next()?;
                 let range = item_node.start_byte()..item_node.end_byte();
                 let mut text = String::new();
-                let mut name_ranges = Vec::new();
                 let mut highlight_ranges = Vec::new();
 
                 for capture in mat.captures {
-                    let node_is_name;
                     if capture.index == name_capture_ix {
-                        node_is_name = true;
                     } else if capture.index == context_capture_ix {
-                        node_is_name = false;
                     } else {
                         continue;
                     }
@@ -1881,18 +1877,6 @@ impl BufferSnapshot {
                     if !text.is_empty() {
                         text.push(' ');
                     }
-                    if node_is_name {
-                        let mut start = text.len() as u32;
-                        let end = start + range.len() as u32;
-
-                        // When multiple names are captured, then the matcheable text
-                        // includes the whitespace in between the names.
-                        if !name_ranges.is_empty() {
-                            start -= 1;
-                        }
-
-                        name_ranges.push(start..end);
-                    }
 
                     let mut offset = range.start;
                     chunks.seek(offset);
@@ -1926,7 +1910,6 @@ impl BufferSnapshot {
                     depth: stack.len() - 1,
                     range: self.anchor_after(range.start)..self.anchor_before(range.end),
                     text,
-                    name_ranges,
                     highlight_ranges,
                 })
             })

crates/language/src/outline.rs 🔗

@@ -13,7 +13,6 @@ pub struct OutlineItem<T> {
     pub depth: usize,
     pub range: Range<T>,
     pub text: String,
-    pub name_ranges: Vec<Range<u32>>,
     pub highlight_ranges: Vec<(Range<usize>, HighlightStyle)>,
 }
 
@@ -22,16 +21,9 @@ impl<T> Outline<T> {
         Self {
             candidates: items
                 .iter()
-                .map(|item| {
-                    let text = item
-                        .name_ranges
-                        .iter()
-                        .map(|range| &item.text[range.start as usize..range.end as usize])
-                        .collect::<String>();
-                    StringMatchCandidate {
-                        char_bag: text.as_str().into(),
-                        string: text,
-                    }
+                .map(|item| StringMatchCandidate {
+                    char_bag: item.text.as_str().into(),
+                    string: item.text.clone(),
                 })
                 .collect(),
             items,
@@ -53,20 +45,8 @@ impl<T> Outline<T> {
         let mut tree_matches = Vec::new();
 
         let mut prev_item_ix = 0;
-        for mut string_match in matches {
+        for string_match in matches {
             let outline_match = &self.items[string_match.candidate_index];
-
-            let mut name_ranges = outline_match.name_ranges.iter();
-            let mut name_range = name_ranges.next().unwrap();
-            let mut preceding_ranges_len = 0;
-            for position in &mut string_match.positions {
-                while *position >= preceding_ranges_len + name_range.len() as usize {
-                    preceding_ranges_len += name_range.len();
-                    name_range = name_ranges.next().unwrap();
-                }
-                *position = name_range.start as usize + (*position - preceding_ranges_len);
-            }
-
             let insertion_ix = tree_matches.len();
             let mut cur_depth = outline_match.depth;
             for (ix, item) in self.items[prev_item_ix..string_match.candidate_index]

crates/language/src/tests.rs 🔗

@@ -302,6 +302,9 @@ async fn test_outline(mut cx: gpui::TestAppContext) {
                 (function_item
                     "fn" @context
                     name: (_) @name) @item
+                (mod_item
+                    "mod" @context
+                    name: (_) @name) @item
                 "#,
             )
             .unwrap(),
@@ -313,15 +316,19 @@ async fn test_outline(mut cx: gpui::TestAppContext) {
             age: usize,
         }
 
-        enum LoginState {
-            LoggedOut,
-            LoggingOn,
-            LoggedIn {
-                person: Person,
-                time: Instant,
+        mod module {
+            enum LoginState {
+                LoggedOut,
+                LoggingOn,
+                LoggedIn {
+                    person: Person,
+                    time: Instant,
+                }
             }
         }
 
+        impl Eq for Person {}
+
         impl Drop for Person {
             fn drop(&mut self) {
                 println!("bye");
@@ -339,39 +346,50 @@ async fn test_outline(mut cx: gpui::TestAppContext) {
         outline
             .items
             .iter()
-            .map(|item| (item.text.as_str(), item.name_ranges.as_ref(), item.depth))
+            .map(|item| (item.text.as_str(), item.depth))
             .collect::<Vec<_>>(),
         &[
-            ("struct Person", [7..13].as_slice(), 0),
-            ("name", &[0..4], 1),
-            ("age", &[0..3], 1),
-            ("enum LoginState", &[5..15], 0),
-            ("LoggedOut", &[0..9], 1),
-            ("LoggingOn", &[0..9], 1),
-            ("LoggedIn", &[0..8], 1),
-            ("person", &[0..6], 2),
-            ("time", &[0..4], 2),
-            ("impl Drop for Person", &[5..9, 13..20], 0),
-            ("fn drop", &[3..7], 1),
+            ("struct Person", 0),
+            ("name", 1),
+            ("age", 1),
+            ("mod module", 0),
+            ("enum LoginState", 1),
+            ("LoggedOut", 2),
+            ("LoggingOn", 2),
+            ("LoggedIn", 2),
+            ("person", 3),
+            ("time", 3),
+            ("impl Eq for Person", 0),
+            ("impl Drop for Person", 0),
+            ("fn drop", 1),
         ]
     );
 
     assert_eq!(
         search(&outline, "oon", &cx).await,
         &[
-            ("enum LoginState", vec![]),  // included as the parent of a match
-            ("LoggingOn", vec![1, 7, 8]), // matches
-            ("impl Drop for Person", vec![7, 18, 19]), // matches in two disjoint names
+            ("mod module", vec![]),                  // included as the parent of a match
+            ("enum LoginState", vec![]),             // included as the parent of a match
+            ("LoggingOn", vec![1, 7, 8]),            // matches
+            ("impl Eq for Person", vec![9, 16, 17]), // matches part of the context
+            ("impl Drop for Person", vec![11, 18, 19]), // matches in two disjoint names
         ]
     );
     assert_eq!(
         search(&outline, "dp p", &cx).await,
-        &[("impl Drop for Person", vec![5, 8, 13, 14])]
+        &[("impl Drop for Person", vec![5, 8, 9, 14])]
     );
     assert_eq!(
         search(&outline, "dpn", &cx).await,
         &[("impl Drop for Person", vec![5, 8, 19])]
     );
+    assert_eq!(
+        search(&outline, "impl", &cx).await,
+        &[
+            ("impl Eq for Person", vec![0, 1, 2, 3]),
+            ("impl Drop for Person", vec![0, 1, 2, 3])
+        ]
+    );
 
     async fn search<'a>(
         outline: &'a Outline<Anchor>,