Add a matches method instead of remove_last

This commit is contained in:
ysthakur
2024-10-21 00:42:27 -04:00
parent 6442596949
commit 433fcb2eda
2 changed files with 58 additions and 47 deletions

View File

@ -59,7 +59,7 @@ impl CommandCompletion {
.max_results
> executables.len() as i64
{
continue;
break;
}
let Ok(name) = item.file_name().into_string() else {
continue;
@ -72,24 +72,23 @@ impl CommandCompletion {
} else {
name.clone()
};
if matcher.add(
name.clone(),
SemanticSuggestion {
suggestion: Suggestion {
value,
span: sugg_span,
append_whitespace: true,
..Default::default()
if matcher.matches(&name) && is_executable::is_executable(item.path()) {
executables.insert(name.clone());
// This causes the matcher to match the executable name twice,
// but it's likely a cost we can eat
matcher.add(
name,
SemanticSuggestion {
suggestion: Suggestion {
value,
span: sugg_span,
append_whitespace: true,
..Default::default()
},
// TODO: is there a way to create a test?
kind: None,
},
// TODO: is there a way to create a test?
kind: None,
},
) {
if is_executable::is_executable(item.path()) {
executables.insert(name);
} else {
matcher.remove_last();
}
);
}
}
}

View File

@ -34,6 +34,7 @@ enum State<T> {
items: Vec<(String, T)>,
},
Fuzzy {
matcher: Box<SkimMatcherV2>,
/// Holds (haystack, item, score)
items: Vec<(String, T, i64)>,
},
@ -57,11 +58,22 @@ impl<T> NuMatcher<T> {
needle: lowercase_needle,
state: State::Prefix { items: Vec::new() },
},
MatchAlgorithm::Fuzzy => NuMatcher {
options,
needle: orig_needle.to_owned(),
state: State::Fuzzy { items: Vec::new() },
},
MatchAlgorithm::Fuzzy => {
let mut matcher = SkimMatcherV2::default();
if options.case_sensitive {
matcher = matcher.respect_case();
} else {
matcher = matcher.ignore_case();
};
NuMatcher {
options,
needle: orig_needle.to_owned(),
state: State::Fuzzy {
matcher: Box::new(matcher),
items: Vec::new(),
},
}
}
}
}
@ -69,51 +81,51 @@ impl<T> NuMatcher<T> {
///
/// Returns whether the item was added.
pub fn add(&mut self, haystack: String, item: T) -> bool {
let haystack = trim_quotes_str(&haystack);
match &mut self.state {
State::Prefix { items } => {
let haystack = trim_quotes_str(&haystack).to_owned();
let haystack_lowercased = if self.options.case_sensitive {
Cow::Borrowed(&haystack)
let haystack = if self.options.case_sensitive {
Cow::Borrowed(haystack)
} else {
Cow::Owned(haystack.to_folded_case())
};
let matches = if self.options.positional {
haystack_lowercased.starts_with(self.needle.as_str())
haystack.starts_with(self.needle.as_str())
} else {
haystack_lowercased.contains(self.needle.as_str())
haystack.contains(self.needle.as_str())
};
if matches {
items.push((haystack, item));
items.push((haystack.to_string(), item));
}
matches
}
State::Fuzzy { items } => {
let mut matcher = SkimMatcherV2::default();
if self.options.case_sensitive {
matcher = matcher.respect_case();
} else {
matcher = matcher.ignore_case();
};
let Some(score) = matcher.fuzzy_match(&haystack, &self.needle) else {
State::Fuzzy { items, matcher } => {
let Some(score) = matcher.fuzzy_match(haystack, &self.needle) else {
return false;
};
items.push((haystack, item, score));
items.push((haystack.to_string(), item, score));
true
}
}
}
/// Remove the last added item. This is useful if you want to filter matched
/// completions by some expensive condition. You can call `add`, run the expensive condition,
/// then call `remove_last` if the expensive condition is false.
pub fn remove_last(&mut self) {
/// Returns whether the item was added.
pub fn matches(&mut self, haystack: &str) -> bool {
let haystack = trim_quotes_str(haystack).to_owned();
match &mut self.state {
State::Prefix { items } => {
items.pop();
}
State::Fuzzy { items } => {
items.pop();
State::Prefix { .. } => {
let haystack = if self.options.case_sensitive {
Cow::Borrowed(&haystack)
} else {
Cow::Owned(haystack.to_folded_case())
};
if self.options.positional {
haystack.starts_with(self.needle.as_str())
} else {
haystack.contains(self.needle.as_str())
}
}
State::Fuzzy { matcher, .. } => matcher.fuzzy_match(&haystack, &self.needle).is_some(),
}
}