@@ -6,6 +6,8 @@ use std::{ops::Range, sync::Arc};
pub struct Outline<T> {
pub items: Vec<OutlineItem<T>>,
candidates: Vec<StringMatchCandidate>,
+ path_candidates: Vec<StringMatchCandidate>,
+ path_candidate_prefixes: Vec<usize>,
}
#[derive(Clone, Debug)]
@@ -18,6 +20,30 @@ pub struct OutlineItem<T> {
impl<T> Outline<T> {
pub fn new(items: Vec<OutlineItem<T>>) -> Self {
+ let mut path_candidates = Vec::new();
+ let mut path_candidate_prefixes = Vec::new();
+ let mut item_text = String::new();
+ let mut stack = Vec::new();
+
+ for (id, item) in items.iter().enumerate() {
+ if item.depth < stack.len() {
+ stack.truncate(item.depth);
+ item_text.truncate(stack.last().copied().unwrap_or(0));
+ }
+ if !item_text.is_empty() {
+ item_text.push(' ');
+ }
+ path_candidate_prefixes.push(item_text.len());
+ item_text.push_str(&item.text);
+ stack.push(item_text.len());
+
+ path_candidates.push(StringMatchCandidate {
+ id,
+ string: item_text.clone(),
+ char_bag: item_text.as_str().into(),
+ });
+ }
+
Self {
candidates: items
.iter()
@@ -28,13 +54,21 @@ impl<T> Outline<T> {
string: item.text.clone(),
})
.collect(),
+ path_candidates,
+ path_candidate_prefixes,
items,
}
}
pub async fn search(&self, query: &str, executor: Arc<Background>) -> Vec<StringMatch> {
+ let query = query.trim_start();
+ let is_path_query = query.contains(' ');
let mut matches = fuzzy::match_strings(
- &self.candidates,
+ if is_path_query {
+ &self.path_candidates
+ } else {
+ &self.candidates
+ },
query,
true,
100,
@@ -47,8 +81,19 @@ impl<T> Outline<T> {
let mut tree_matches = Vec::new();
let mut prev_item_ix = 0;
- for string_match in matches {
+ for mut string_match in matches {
let outline_match = &self.items[string_match.candidate_id];
+
+ if is_path_query {
+ let prefix_len = self.path_candidate_prefixes[string_match.candidate_id];
+ string_match
+ .positions
+ .retain(|position| *position >= prefix_len);
+ for position in &mut string_match.positions {
+ *position -= prefix_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_id]