From b79d6c3164afdd7561e1b0e0d04c75cecfa1d88b Mon Sep 17 00:00:00 2001 From: MilesCranmer Date: Mon, 22 Apr 2024 11:58:50 +0100 Subject: [PATCH] Create "substring" match type # Description Similar behavior to zsh's history-substring-search method, this matching algorithm will check if a given string is contained within the other, regardless of position. --- crates/nu-cli/src/completions/completion_options.rs | 10 ++++++++++ crates/nu-cli/src/completions/custom_completions.rs | 2 +- crates/nu-protocol/src/config/completer.rs | 3 +++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/crates/nu-cli/src/completions/completion_options.rs b/crates/nu-cli/src/completions/completion_options.rs index a414aafedf..8a6ccf0a63 100644 --- a/crates/nu-cli/src/completions/completion_options.rs +++ b/crates/nu-cli/src/completions/completion_options.rs @@ -24,6 +24,12 @@ pub enum MatchAlgorithm { /// Example: /// "git checkout" is matched by "gco" Fuzzy, + + /// Only show suggestions which contain the substring starting at any place + /// + /// Example: + /// "git checkout" is matched by "check" + Substring } impl MatchAlgorithm { @@ -37,6 +43,7 @@ impl MatchAlgorithm { let matcher = SkimMatcherV2::default(); matcher.fuzzy_match(haystack, needle).is_some() } + MatchAlgorithm::Substring => haystack.contains(needle), } } @@ -51,6 +58,7 @@ impl MatchAlgorithm { let matcher = SkimMatcherV2::default(); matcher.fuzzy_match(&haystack_str, &needle_str).is_some() } + MatchAlgorithm::Substring => haystack.windows(needle.len()).any(|window| window == needle), } } } @@ -60,6 +68,7 @@ impl From for MatchAlgorithm { match value { CompletionAlgorithm::Prefix => MatchAlgorithm::Prefix, CompletionAlgorithm::Fuzzy => MatchAlgorithm::Fuzzy, + CompletionAlgorithm::Substring => MatchAlgorithm::Substring, } } } @@ -71,6 +80,7 @@ impl TryFrom for MatchAlgorithm { match value.as_str() { "prefix" => Ok(Self::Prefix), "fuzzy" => Ok(Self::Fuzzy), + "substring" => Ok(Self::Substring), _ => Err(InvalidMatchAlgorithm::Unknown), } } diff --git a/crates/nu-cli/src/completions/custom_completions.rs b/crates/nu-cli/src/completions/custom_completions.rs index 12a7762e94..2e7e8c8860 100644 --- a/crates/nu-cli/src/completions/custom_completions.rs +++ b/crates/nu-cli/src/completions/custom_completions.rs @@ -163,7 +163,7 @@ fn filter( } } }, - MatchAlgorithm::Fuzzy => options + MatchAlgorithm::Fuzzy | MatchAlgorithm::Substring => options .match_algorithm .matches_u8(it.suggestion.value.as_bytes(), prefix), }) diff --git a/crates/nu-protocol/src/config/completer.rs b/crates/nu-protocol/src/config/completer.rs index 67bde52e27..db865f2ff8 100644 --- a/crates/nu-protocol/src/config/completer.rs +++ b/crates/nu-protocol/src/config/completer.rs @@ -11,6 +11,7 @@ pub enum CompletionAlgorithm { #[default] Prefix, Fuzzy, + Substring, } impl FromStr for CompletionAlgorithm { @@ -20,6 +21,7 @@ impl FromStr for CompletionAlgorithm { match s.to_ascii_lowercase().as_str() { "prefix" => Ok(Self::Prefix), "fuzzy" => Ok(Self::Fuzzy), + "substring" => Ok(Self::Substring), _ => Err("expected either 'prefix' or 'fuzzy'"), } } @@ -30,6 +32,7 @@ impl ReconstructVal for CompletionAlgorithm { let str = match self { CompletionAlgorithm::Prefix => "prefix", CompletionAlgorithm::Fuzzy => "fuzzy", + CompletionAlgorithm::Substring => "substring", }; Value::string(str, span) }