Associate `StringMatchCandidate` with an id

Antonio Scandurra and Nathan Sobo created

Co-Authored-By: Nathan Sobo <nathan@zed.dev>

Change summary

crates/fuzzy/src/fuzzy.rs                   | 22 +++++++++-------------
crates/language/src/outline.rs              | 16 +++++++++-------
crates/language/src/tests.rs                |  7 +------
crates/outline/src/outline.rs               |  6 +++---
crates/theme_selector/src/theme_selector.rs |  6 ++++--
5 files changed, 26 insertions(+), 31 deletions(-)

Detailed changes

crates/fuzzy/src/fuzzy.rs 🔗

@@ -55,6 +55,7 @@ pub struct PathMatch {
 
 #[derive(Clone, Debug)]
 pub struct StringMatchCandidate {
+    pub id: usize,
     pub string: String,
     pub char_bag: CharBag,
 }
@@ -109,7 +110,7 @@ impl<'a> MatchCandidate for &'a StringMatchCandidate {
 
 #[derive(Clone, Debug)]
 pub struct StringMatch {
-    pub candidate_index: usize,
+    pub candidate_id: usize,
     pub score: f64,
     pub positions: Vec<usize>,
     pub string: String,
@@ -134,7 +135,7 @@ impl Ord for StringMatch {
         self.score
             .partial_cmp(&other.score)
             .unwrap_or(Ordering::Equal)
-            .then_with(|| self.candidate_index.cmp(&other.candidate_index))
+            .then_with(|| self.candidate_id.cmp(&other.candidate_id))
     }
 }
 
@@ -198,7 +199,6 @@ pub async fn match_strings(
                         max_results,
                     );
                     matcher.match_strings(
-                        segment_start,
                         &candidates[segment_start..segment_end],
                         results,
                         cancel_flag,
@@ -321,7 +321,6 @@ impl<'a> Matcher<'a> {
 
     pub fn match_strings(
         &mut self,
-        start_index: usize,
         candidates: &[StringMatchCandidate],
         results: &mut Vec<StringMatch>,
         cancel_flag: &AtomicBool,
@@ -329,12 +328,11 @@ impl<'a> Matcher<'a> {
         self.match_internal(
             &[],
             &[],
-            start_index,
             candidates.iter(),
             results,
             cancel_flag,
-            |candidate_index, candidate, score| StringMatch {
-                candidate_index,
+            |candidate, score| StringMatch {
+                candidate_id: candidate.id,
                 score,
                 positions: Vec::new(),
                 string: candidate.string.to_string(),
@@ -358,11 +356,10 @@ impl<'a> Matcher<'a> {
         self.match_internal(
             &prefix,
             &lowercase_prefix,
-            0,
             path_entries,
             results,
             cancel_flag,
-            |_, candidate, score| PathMatch {
+            |candidate, score| PathMatch {
                 score,
                 worktree_id: tree_id,
                 positions: Vec::new(),
@@ -376,19 +373,18 @@ impl<'a> Matcher<'a> {
         &mut self,
         prefix: &[char],
         lowercase_prefix: &[char],
-        start_index: usize,
         candidates: impl Iterator<Item = C>,
         results: &mut Vec<R>,
         cancel_flag: &AtomicBool,
         build_match: F,
     ) where
         R: Match,
-        F: Fn(usize, &C, f64) -> R,
+        F: Fn(&C, f64) -> R,
     {
         let mut candidate_chars = Vec::new();
         let mut lowercase_candidate_chars = Vec::new();
 
-        for (candidate_ix, candidate) in candidates.enumerate() {
+        for candidate in candidates {
             if !candidate.has_chars(self.query_char_bag) {
                 continue;
             }
@@ -422,7 +418,7 @@ impl<'a> Matcher<'a> {
             );
 
             if score > 0.0 {
-                let mut mat = build_match(start_index + candidate_ix, &candidate, score);
+                let mut mat = build_match(&candidate, score);
                 if let Err(i) = results.binary_search_by(|m| mat.cmp(&m)) {
                     if results.len() < self.max_results {
                         mat.set_positions(self.match_positions.clone());

crates/language/src/outline.rs 🔗

@@ -21,7 +21,9 @@ impl<T> Outline<T> {
         Self {
             candidates: items
                 .iter()
-                .map(|item| StringMatchCandidate {
+                .enumerate()
+                .map(|(id, item)| StringMatchCandidate {
+                    id,
                     char_bag: item.text.as_str().into(),
                     string: item.text.clone(),
                 })
@@ -37,19 +39,19 @@ impl<T> Outline<T> {
             true,
             100,
             &Default::default(),
-            executor,
+            executor.clone(),
         )
         .await;
-        matches.sort_unstable_by_key(|m| m.candidate_index);
+        matches.sort_unstable_by_key(|m| m.candidate_id);
 
         let mut tree_matches = Vec::new();
 
         let mut prev_item_ix = 0;
         for string_match in matches {
-            let outline_match = &self.items[string_match.candidate_index];
+            let outline_match = &self.items[string_match.candidate_id];
             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]
+            for (ix, item) in self.items[prev_item_ix..string_match.candidate_id]
                 .iter()
                 .enumerate()
                 .rev()
@@ -63,7 +65,7 @@ impl<T> Outline<T> {
                     tree_matches.insert(
                         insertion_ix,
                         StringMatch {
-                            candidate_index,
+                            candidate_id: candidate_index,
                             score: Default::default(),
                             positions: Default::default(),
                             string: Default::default(),
@@ -73,7 +75,7 @@ impl<T> Outline<T> {
                 }
             }
 
-            prev_item_ix = string_match.candidate_index + 1;
+            prev_item_ix = string_match.candidate_id + 1;
             tree_matches.push(string_match);
         }
 

crates/language/src/tests.rs 🔗

@@ -401,12 +401,7 @@ async fn test_outline(mut cx: gpui::TestAppContext) {
             .await;
         matches
             .into_iter()
-            .map(|mat| {
-                (
-                    outline.items[mat.candidate_index].text.as_str(),
-                    mat.positions,
-                )
-            })
+            .map(|mat| (outline.items[mat.candidate_id].text.as_str(), mat.positions))
             .collect::<Vec<_>>()
     }
 }

crates/outline/src/outline.rs 🔗

@@ -202,7 +202,7 @@ impl OutlineView {
         self.list_state.scroll_to(self.selected_match_index);
         if navigate {
             let selected_match = &self.matches[self.selected_match_index];
-            let outline_item = &self.outline.items[selected_match.candidate_index];
+            let outline_item = &self.outline.items[selected_match.candidate_id];
             self.symbol_selection_id = self.active_editor.update(cx, |active_editor, cx| {
                 let snapshot = active_editor.snapshot(cx).display_snapshot;
                 let buffer_snapshot = &snapshot.buffer_snapshot;
@@ -275,7 +275,7 @@ impl OutlineView {
                 .iter()
                 .enumerate()
                 .map(|(index, _)| StringMatch {
-                    candidate_index: index,
+                    candidate_id: index,
                     score: Default::default(),
                     positions: Default::default(),
                     string: Default::default(),
@@ -366,7 +366,7 @@ impl OutlineView {
         } else {
             &settings.theme.selector.item
         };
-        let outline_item = &self.outline.items[string_match.candidate_index];
+        let outline_item = &self.outline.items[string_match.candidate_id];
 
         Text::new(outline_item.text.clone(), style.label.text.clone())
             .with_soft_wrap(false)

crates/theme_selector/src/theme_selector.rs 🔗

@@ -157,7 +157,9 @@ impl ThemeSelector {
         let candidates = self
             .themes
             .list()
-            .map(|name| StringMatchCandidate {
+            .enumerate()
+            .map(|(id, name)| StringMatchCandidate {
+                id,
                 char_bag: name.as_str().into(),
                 string: name,
             })
@@ -169,7 +171,7 @@ impl ThemeSelector {
                 .into_iter()
                 .enumerate()
                 .map(|(index, candidate)| StringMatch {
-                    candidate_index: index,
+                    candidate_id: index,
                     string: candidate.string,
                     positions: Vec::new(),
                     score: 0.0,