Allow searching of outline items

Antonio Scandurra created

Change summary

Cargo.lock                    |  2 +
crates/outline/Cargo.toml     |  1 
crates/outline/src/outline.rs | 51 ++++++++++++++++++++++++++----------
3 files changed, 40 insertions(+), 14 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -2602,6 +2602,7 @@ dependencies = [
  "ctor",
  "env_logger",
  "futures",
+ "fuzzy",
  "gpui",
  "lazy_static",
  "log",
@@ -3126,6 +3127,7 @@ name = "outline"
 version = "0.1.0"
 dependencies = [
  "editor",
+ "fuzzy",
  "gpui",
  "language",
  "postage",

crates/outline/Cargo.toml 🔗

@@ -8,6 +8,7 @@ path = "src/outline.rs"
 
 [dependencies]
 editor = { path = "../editor" }
+fuzzy = { path = "../fuzzy" }
 gpui = { path = "../gpui" }
 language = { path = "../language" }
 text = { path = "../text" }

crates/outline/src/outline.rs 🔗

@@ -1,12 +1,12 @@
-use editor::{display_map::ToDisplayPoint, Autoscroll, Editor, EditorSettings};
+use editor::{Editor, EditorSettings};
+use fuzzy::StringMatch;
 use gpui::{
-    action, elements::*, geometry::vector::Vector2F, keymap::Binding, Axis, Entity,
-    MutableAppContext, RenderContext, View, ViewContext, ViewHandle, WeakViewHandle,
+    action, elements::*, keymap::Binding, Axis, Entity, MutableAppContext, RenderContext, View,
+    ViewContext, ViewHandle, WeakViewHandle,
 };
-use language::{Outline, OutlineItem};
+use language::Outline;
 use postage::watch;
 use std::{cmp, sync::Arc};
-use text::{Bias, Point, Selection};
 use workspace::{Settings, Workspace};
 
 action!(Toggle);
@@ -25,7 +25,7 @@ pub fn init(cx: &mut MutableAppContext) {
 struct OutlineView {
     handle: WeakViewHandle<Self>,
     outline: Outline,
-    matches: Vec<OutlineItem>,
+    matches: Vec<StringMatch>,
     query_editor: ViewHandle<Editor>,
     list_state: UniformListState,
     settings: watch::Receiver<Settings>,
@@ -40,7 +40,7 @@ impl View for OutlineView {
         "OutlineView"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<'_, Self>) -> ElementBox {
+    fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox {
         let settings = self.settings.borrow();
 
         Align::new(
@@ -95,14 +95,16 @@ impl OutlineView {
         });
         cx.subscribe(&query_editor, Self::on_query_editor_event)
             .detach();
-        Self {
+        let mut this = Self {
             handle: cx.weak_handle(),
-            matches: outline.0.clone(),
+            matches: Default::default(),
             outline,
             query_editor,
             list_state: Default::default(),
             settings,
-        }
+        };
+        this.update_matches(cx);
+        this
     }
 
     fn toggle(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext<Workspace>) {
@@ -129,13 +131,32 @@ impl OutlineView {
         cx: &mut ViewContext<Self>,
     ) {
         match event {
-            editor::Event::Edited => {
-                let query = self.query_editor.update(cx, |buffer, cx| buffer.text(cx));
-            }
+            editor::Event::Edited => self.update_matches(cx),
             _ => {}
         }
     }
 
+    fn update_matches(&mut self, cx: &mut ViewContext<Self>) {
+        let query = self.query_editor.update(cx, |buffer, cx| buffer.text(cx));
+        if query.is_empty() {
+            self.matches = self
+                .outline
+                .items
+                .iter()
+                .enumerate()
+                .map(|(index, _)| StringMatch {
+                    candidate_index: index,
+                    score: Default::default(),
+                    positions: Default::default(),
+                    string: Default::default(),
+                })
+                .collect();
+        } else {
+            self.matches = self.outline.search(&query, cx);
+        }
+        cx.notify();
+    }
+
     fn render_matches(&self) -> ElementBox {
         if self.matches.is_empty() {
             let settings = self.settings.borrow();
@@ -172,7 +193,7 @@ impl OutlineView {
             .named("matches")
     }
 
-    fn render_match(&self, outline_match: &OutlineItem, index: usize) -> ElementBox {
+    fn render_match(&self, string_match: &StringMatch, index: usize) -> ElementBox {
         // TODO: maintain selected index.
         let selected_index = 0;
         let settings = self.settings.borrow();
@@ -181,8 +202,10 @@ impl OutlineView {
         } else {
             &settings.theme.selector.item
         };
+        let outline_match = &self.outline.items[string_match.candidate_index];
 
         Label::new(outline_match.text.clone(), style.label.clone())
+            .with_highlights(string_match.positions.clone())
             .contained()
             .with_padding_left(20. * outline_match.depth as f32)
             .contained()