Fix minor problems

This commit is contained in:
Vansh Nath 2025-04-07 11:43:25 +02:00
parent bb79acff1a
commit 284e887f46
No known key found for this signature in database
GPG Key ID: 709BF3EAFB217A96
3 changed files with 45 additions and 61 deletions

View File

@ -18,17 +18,17 @@ pub enum MatchAlgorithm {
/// "git switch" is matched by "git sw" /// "git switch" is matched by "git sw"
Prefix, Prefix,
/// Only show suggestions which contain the input chars at any place
///
/// Example:
/// "git checkout" is matched by "gco"
Fuzzy,
/// Only show suggestions which have a substring matching with the given input /// Only show suggestions which have a substring matching with the given input
/// ///
/// Example: /// Example:
/// "git checkout" is matched by "checkout" /// "git checkout" is matched by "checkout"
Substring, Substring,
/// Only show suggestions which contain the input chars at any place
///
/// Example:
/// "git checkout" is matched by "gco"
Fuzzy,
} }
pub struct NuMatcher<'a, T> { pub struct NuMatcher<'a, T> {
@ -42,16 +42,16 @@ enum State<T> {
/// Holds (haystack, item) /// Holds (haystack, item)
items: Vec<(String, T)>, items: Vec<(String, T)>,
}, },
Substring {
/// Holds (haystack, item)
items: Vec<(String, T)>,
},
Fuzzy { Fuzzy {
matcher: Matcher, matcher: Matcher,
atom: Atom, atom: Atom,
/// Holds (haystack, item, score) /// Holds (haystack, item, score)
items: Vec<(String, T, u16)>, items: Vec<(String, T, u16)>,
}, },
Substring {
/// Holds (haystack, item)
items: Vec<(String, T)>,
},
} }
/// Filters and sorts suggestions /// Filters and sorts suggestions
@ -74,6 +74,18 @@ impl<T> NuMatcher<'_, T> {
state: State::Prefix { items: Vec::new() }, state: State::Prefix { items: Vec::new() },
} }
} }
MatchAlgorithm::Substring => {
let lowercase_needle = if options.case_sensitive {
needle.to_owned()
} else {
needle.to_folded_case()
};
NuMatcher {
options,
needle: lowercase_needle,
state: State::Substring { items: Vec::new() },
}
}
MatchAlgorithm::Fuzzy => { MatchAlgorithm::Fuzzy => {
let atom = Atom::new( let atom = Atom::new(
needle, needle,
@ -96,18 +108,6 @@ impl<T> NuMatcher<'_, T> {
}, },
} }
} }
MatchAlgorithm::Substring => {
let lowercase_needle = if options.case_sensitive {
needle.to_owned()
} else {
needle.to_folded_case()
};
NuMatcher {
options,
needle: lowercase_needle,
state: State::Substring { items: Vec::new() },
}
}
} }
} }
@ -132,6 +132,20 @@ impl<T> NuMatcher<'_, T> {
} }
matches matches
} }
State::Substring { items } => {
let haystack_folded = if self.options.case_sensitive {
Cow::Borrowed(haystack)
} else {
Cow::Owned(haystack.to_folded_case())
};
let matches = haystack_folded.contains(self.needle.as_str());
if matches {
if let Some(item) = item {
items.push((haystack.to_string(), item));
}
}
matches
}
State::Fuzzy { State::Fuzzy {
matcher, matcher,
atom, atom,
@ -148,20 +162,6 @@ impl<T> NuMatcher<'_, T> {
} }
true true
} }
State::Substring { items } => {
let haystack_folded = if self.options.case_sensitive {
Cow::Borrowed(haystack)
} else {
Cow::Owned(haystack.to_folded_case())
};
let matches = haystack_folded.contains(self.needle.as_str());
if matches {
if let Some(item) = item {
items.push((haystack.to_string(), item));
}
}
matches
}
} }
} }
@ -180,7 +180,7 @@ impl<T> NuMatcher<'_, T> {
/// Get all the items that matched (sorted) /// Get all the items that matched (sorted)
pub fn results(self) -> Vec<T> { pub fn results(self) -> Vec<T> {
match self.state { match self.state {
State::Prefix { mut items, .. } => { State::Prefix { mut items, .. } | State::Substring { mut items , ..} => {
items.sort_by(|(haystack1, _), (haystack2, _)| { items.sort_by(|(haystack1, _), (haystack2, _)| {
let cmp_sensitive = haystack1.cmp(haystack2); let cmp_sensitive = haystack1.cmp(haystack2);
if self.options.case_sensitive { if self.options.case_sensitive {
@ -212,20 +212,6 @@ impl<T> NuMatcher<'_, T> {
.map(|(_, item, _)| item) .map(|(_, item, _)| item)
.collect::<Vec<_>>() .collect::<Vec<_>>()
} }
State::Substring { mut items, .. } => {
items.sort_by(|(haystack1, _), (haystack2, _)| {
let cmp_sensitive = haystack1.cmp(haystack2);
if self.options.case_sensitive {
cmp_sensitive
} else {
haystack1
.to_folded_case()
.cmp(&haystack2.to_folded_case())
.then(cmp_sensitive)
}
});
items.into_iter().map(|(_, item)| item).collect::<Vec<_>>()
}
} }
} }
} }
@ -241,8 +227,8 @@ impl From<CompletionAlgorithm> for MatchAlgorithm {
fn from(value: CompletionAlgorithm) -> Self { fn from(value: CompletionAlgorithm) -> Self {
match value { match value {
CompletionAlgorithm::Prefix => MatchAlgorithm::Prefix, CompletionAlgorithm::Prefix => MatchAlgorithm::Prefix,
CompletionAlgorithm::Fuzzy => MatchAlgorithm::Fuzzy,
CompletionAlgorithm::Substring => MatchAlgorithm::Substring, CompletionAlgorithm::Substring => MatchAlgorithm::Substring,
CompletionAlgorithm::Fuzzy => MatchAlgorithm::Fuzzy,
} }
} }
} }
@ -253,8 +239,8 @@ impl TryFrom<String> for MatchAlgorithm {
fn try_from(value: String) -> Result<Self, Self::Error> { fn try_from(value: String) -> Result<Self, Self::Error> {
match value.as_str() { match value.as_str() {
"prefix" => Ok(Self::Prefix), "prefix" => Ok(Self::Prefix),
"fuzzy" => Ok(Self::Fuzzy),
"substring" => Ok(Self::Substring), "substring" => Ok(Self::Substring),
"fuzzy" => Ok(Self::Fuzzy),
_ => Err(InvalidMatchAlgorithm::Unknown), _ => Err(InvalidMatchAlgorithm::Unknown),
} }
} }
@ -302,16 +288,14 @@ mod test {
#[case(MatchAlgorithm::Prefix, "example text", "", true)] #[case(MatchAlgorithm::Prefix, "example text", "", true)]
#[case(MatchAlgorithm::Prefix, "example text", "examp", true)] #[case(MatchAlgorithm::Prefix, "example text", "examp", true)]
#[case(MatchAlgorithm::Prefix, "example text", "text", false)] #[case(MatchAlgorithm::Prefix, "example text", "text", false)]
#[case(MatchAlgorithm::Substring, "example text", "", true)]
#[case(MatchAlgorithm::Substring, "example text", "text", true)]
#[case(MatchAlgorithm::Substring, "example text", "mplxt", false)]
#[case(MatchAlgorithm::Fuzzy, "example text", "", true)] #[case(MatchAlgorithm::Fuzzy, "example text", "", true)]
#[case(MatchAlgorithm::Fuzzy, "example text", "examp", true)] #[case(MatchAlgorithm::Fuzzy, "example text", "examp", true)]
#[case(MatchAlgorithm::Fuzzy, "example text", "ext", true)] #[case(MatchAlgorithm::Fuzzy, "example text", "ext", true)]
#[case(MatchAlgorithm::Fuzzy, "example text", "mplxt", true)] #[case(MatchAlgorithm::Fuzzy, "example text", "mplxt", true)]
#[case(MatchAlgorithm::Fuzzy, "example text", "mpp", false)] #[case(MatchAlgorithm::Fuzzy, "example text", "mpp", false)]
#[case(MatchAlgorithm::Substring, "example text", "", true)]
#[case(MatchAlgorithm::Substring, "example text", "examp", true)]
#[case(MatchAlgorithm::Substring, "example text", "ple", true)]
#[case(MatchAlgorithm::Substring, "example text", "text", true)]
#[case(MatchAlgorithm::Substring, "example text", "mplxt", false)]
fn match_algorithm_simple( fn match_algorithm_simple(
#[case] match_algorithm: MatchAlgorithm, #[case] match_algorithm: MatchAlgorithm,
#[case] haystack: &str, #[case] haystack: &str,

View File

@ -112,10 +112,10 @@ impl<T: Completer> Completer for CustomCompletion<T> {
if let Some(positional) = if let Some(positional) =
options.get("positional").and_then(|val| val.as_bool().ok()) options.get("positional").and_then(|val| val.as_bool().ok())
{ {
log::warn!("Use of the positional option is deprecated. Use the substring match algorithm instead.");
if !positional if !positional
&& completion_options.match_algorithm == MatchAlgorithm::Prefix && completion_options.match_algorithm == MatchAlgorithm::Prefix
{ {
log::warn!("Use of the positional option is deprecated. Use the substring match algorithm instead.");
completion_options.match_algorithm = MatchAlgorithm::Substring completion_options.match_algorithm = MatchAlgorithm::Substring
} }
} }

View File

@ -6,8 +6,8 @@ use crate::engine::Closure;
pub enum CompletionAlgorithm { pub enum CompletionAlgorithm {
#[default] #[default]
Prefix, Prefix,
Fuzzy,
Substring, Substring,
Fuzzy,
} }
impl FromStr for CompletionAlgorithm { impl FromStr for CompletionAlgorithm {
@ -16,8 +16,8 @@ impl FromStr for CompletionAlgorithm {
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_ascii_lowercase().as_str() { match s.to_ascii_lowercase().as_str() {
"prefix" => Ok(Self::Prefix), "prefix" => Ok(Self::Prefix),
"fuzzy" => Ok(Self::Fuzzy),
"substring" => Ok(Self::Substring), "substring" => Ok(Self::Substring),
"fuzzy" => Ok(Self::Fuzzy),
_ => Err("'prefix' or 'fuzzy' or 'substring'"), _ => Err("'prefix' or 'fuzzy' or 'substring'"),
} }
} }