@@ -19,6 +19,7 @@ test-support = [
[dependencies]
clock = { path = "../clock" }
collections = { path = "../collections" }
+fuzzy = { path = "../fuzzy" }
gpui = { path = "../gpui" }
lsp = { path = "../lsp" }
rpc = { path = "../rpc" }
@@ -1,7 +1,13 @@
use std::ops::Range;
+use fuzzy::{StringMatch, StringMatchCandidate};
+use gpui::AppContext;
+
#[derive(Debug)]
-pub struct Outline(pub Vec<OutlineItem>);
+pub struct Outline {
+ pub items: Vec<OutlineItem>,
+ candidates: Vec<StringMatchCandidate>,
+}
#[derive(Clone, Debug)]
pub struct OutlineItem {
@@ -11,3 +17,65 @@ pub struct OutlineItem {
pub text: String,
pub name_range_in_text: Range<usize>,
}
+
+impl Outline {
+ pub fn new(items: Vec<OutlineItem>) -> Self {
+ Self {
+ candidates: items
+ .iter()
+ .map(|item| {
+ let text = &item.text[item.name_range_in_text.clone()];
+ StringMatchCandidate {
+ string: text.to_string(),
+ char_bag: text.into(),
+ }
+ })
+ .collect(),
+ items,
+ }
+ }
+
+ pub fn search(&self, query: &str, cx: &AppContext) -> Vec<StringMatch> {
+ let mut matches = smol::block_on(fuzzy::match_strings(
+ &self.candidates,
+ query,
+ true,
+ 100,
+ &Default::default(),
+ cx.background().clone(),
+ ));
+ matches.sort_unstable_by_key(|m| m.candidate_index);
+
+ let mut tree_matches = Vec::new();
+
+ let mut prev_item_ix = 0;
+ for mut string_match in matches {
+ let outline_match = &self.items[string_match.candidate_index];
+ for position in &mut string_match.positions {
+ *position += outline_match.name_range_in_text.start;
+ }
+
+ for (ix, item) in self.items[prev_item_ix..string_match.candidate_index]
+ .iter()
+ .enumerate()
+ {
+ let candidate_index = ix + prev_item_ix;
+ if item.range.contains(&outline_match.range.start)
+ && item.range.contains(&outline_match.range.end)
+ {
+ tree_matches.push(StringMatch {
+ candidate_index,
+ score: Default::default(),
+ positions: Default::default(),
+ string: Default::default(),
+ });
+ }
+ }
+
+ prev_item_ix = string_match.candidate_index;
+ tree_matches.push(string_match);
+ }
+
+ tree_matches
+ }
+}