mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-12-19 05:13:44 +08:00
Use idiomatic names for CaseSensitivity and ContainType
This commit is contained in:
parent
b570c7f6a6
commit
b949497bc1
|
@ -102,59 +102,67 @@ pub fn ifind(haystack: &wstr, needle: &wstr, fuzzy: bool /* = false */) -> Optio
|
||||||
}
|
}
|
||||||
|
|
||||||
// The ways one string can contain another.
|
// The ways one string can contain another.
|
||||||
|
//
|
||||||
|
// Note that the order of entries below affects the sort order of completions.
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum ContainType {
|
pub enum ContainType {
|
||||||
/// exact match: foobar matches foo
|
/// Exact match: `foobar` matches `foo`
|
||||||
exact,
|
Exact,
|
||||||
/// prefix match: foo matches foobar
|
/// Prefix match: `foo` matches `foobar`
|
||||||
prefix,
|
Prefix,
|
||||||
/// substring match: ooba matches foobar
|
/// Substring match: `ooba` matches `foobar`
|
||||||
substr,
|
Substr,
|
||||||
/// subsequence match: fbr matches foobar
|
/// Subsequence match: `fbr` matches `foobar`
|
||||||
subseq,
|
Subseq,
|
||||||
}
|
}
|
||||||
|
|
||||||
// The case-folding required for the match.
|
// The case-folding required for the match.
|
||||||
|
//
|
||||||
|
// Note that the order of entries below affects the sort order of completions.
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum CaseFold {
|
pub enum CaseSensitivity {
|
||||||
/// exact match: foobar matches foobar
|
/// Exact match: `foobar` only matches `foobar`
|
||||||
samecase,
|
Sensitive,
|
||||||
/// case insensitive match with lowercase input. foobar matches FoBar.
|
/// Case insensitive match if lowercase input: `foobar` matches `FooBar`.
|
||||||
smartcase,
|
Smart,
|
||||||
/// case insensitive: FoBaR matches foobAr
|
/// Case insensitive: `FooBaR` matches `foobAr`
|
||||||
icase,
|
Insensitive,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A lightweight value-type describing how closely a string fuzzy-matches another string.
|
/// A lightweight value-type describing how closely a string fuzzy-matches another string.
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct StringFuzzyMatch {
|
pub struct StringFuzzyMatch {
|
||||||
pub typ: ContainType,
|
pub typ: ContainType,
|
||||||
pub case_fold: CaseFold,
|
pub case_fold: CaseSensitivity,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StringFuzzyMatch {
|
impl StringFuzzyMatch {
|
||||||
pub fn new(typ: ContainType, case_fold: CaseFold) -> Self {
|
pub fn new(typ: ContainType, case_fold: CaseSensitivity) -> Self {
|
||||||
Self { typ, case_fold }
|
Self { typ, case_fold }
|
||||||
}
|
}
|
||||||
// Helper to return an exact match.
|
// Helper to return an exact match.
|
||||||
|
#[inline(always)]
|
||||||
pub fn exact_match() -> Self {
|
pub fn exact_match() -> Self {
|
||||||
Self::new(ContainType::exact, CaseFold::samecase)
|
Self::new(ContainType::Exact, CaseSensitivity::Sensitive)
|
||||||
}
|
}
|
||||||
/// Return whether this is a samecase exact match.
|
/// Return whether this is a samecase exact match.
|
||||||
|
#[inline(always)]
|
||||||
pub fn is_samecase_exact(&self) -> bool {
|
pub fn is_samecase_exact(&self) -> bool {
|
||||||
self.typ == ContainType::exact && self.case_fold == CaseFold::samecase
|
self.typ == ContainType::Exact && self.case_fold == CaseSensitivity::Sensitive
|
||||||
}
|
}
|
||||||
/// Return if we are exact or prefix match.
|
/// Return if we are exact or prefix match.
|
||||||
|
#[inline(always)]
|
||||||
pub fn is_exact_or_prefix(&self) -> bool {
|
pub fn is_exact_or_prefix(&self) -> bool {
|
||||||
matches!(self.typ, ContainType::exact | ContainType::prefix)
|
matches!(self.typ, ContainType::Exact | ContainType::Prefix)
|
||||||
}
|
}
|
||||||
// Return if our match requires a full replacement, i.e. is not a strict extension of our
|
// Return if our match requires a full replacement, i.e. is not a strict extension of our
|
||||||
// existing string. This is false only if our case matches, and our type is prefix or exact.
|
// existing string. This is false only if our case matches and our type is prefix or exact.
|
||||||
|
#[inline(always)]
|
||||||
pub fn requires_full_replacement(&self) -> bool {
|
pub fn requires_full_replacement(&self) -> bool {
|
||||||
if self.case_fold != CaseFold::samecase {
|
if self.case_fold != CaseSensitivity::Sensitive {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
matches!(self.typ, ContainType::substr | ContainType::subseq)
|
matches!(self.typ, ContainType::Substr | ContainType::Subseq)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try creating a fuzzy match for `string` against `match_against`.
|
/// Try creating a fuzzy match for `string` against `match_against`.
|
||||||
|
@ -170,10 +178,10 @@ impl StringFuzzyMatch {
|
||||||
let get_case_fold = || {
|
let get_case_fold = || {
|
||||||
for c in string.chars() {
|
for c in string.chars() {
|
||||||
if c.to_lowercase().next().unwrap() != c {
|
if c.to_lowercase().next().unwrap() != c {
|
||||||
return CaseFold::icase;
|
return CaseSensitivity::Insensitive;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CaseFold::smartcase
|
CaseSensitivity::Smart
|
||||||
};
|
};
|
||||||
|
|
||||||
// A string cannot fuzzy match against a shorter string.
|
// A string cannot fuzzy match against a shorter string.
|
||||||
|
@ -184,27 +192,27 @@ impl StringFuzzyMatch {
|
||||||
// exact samecase
|
// exact samecase
|
||||||
if string == match_against {
|
if string == match_against {
|
||||||
return Some(StringFuzzyMatch::new(
|
return Some(StringFuzzyMatch::new(
|
||||||
ContainType::exact,
|
ContainType::Exact,
|
||||||
CaseFold::samecase,
|
CaseSensitivity::Sensitive,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// prefix samecase
|
// prefix samecase
|
||||||
if match_against.starts_with(string) {
|
if match_against.starts_with(string) {
|
||||||
return Some(StringFuzzyMatch::new(
|
return Some(StringFuzzyMatch::new(
|
||||||
ContainType::prefix,
|
ContainType::Prefix,
|
||||||
CaseFold::samecase,
|
CaseSensitivity::Sensitive,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// exact icase
|
// exact icase
|
||||||
if wcscasecmp(string, match_against).is_eq() {
|
if wcscasecmp(string, match_against).is_eq() {
|
||||||
return Some(StringFuzzyMatch::new(ContainType::exact, get_case_fold()));
|
return Some(StringFuzzyMatch::new(ContainType::Exact, get_case_fold()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// prefix icase
|
// prefix icase
|
||||||
if string_prefixes_string_case_insensitive(string, match_against) {
|
if string_prefixes_string_case_insensitive(string, match_against) {
|
||||||
return Some(StringFuzzyMatch::new(ContainType::prefix, get_case_fold()));
|
return Some(StringFuzzyMatch::new(ContainType::Prefix, get_case_fold()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If anchor_start is set, this is as far as we go.
|
// If anchor_start is set, this is as far as we go.
|
||||||
|
@ -219,21 +227,21 @@ impl StringFuzzyMatch {
|
||||||
.any(|window| wstr::from_char_slice(window) == string)
|
.any(|window| wstr::from_char_slice(window) == string)
|
||||||
{
|
{
|
||||||
return Some(StringFuzzyMatch::new(
|
return Some(StringFuzzyMatch::new(
|
||||||
ContainType::substr,
|
ContainType::Substr,
|
||||||
CaseFold::samecase,
|
CaseSensitivity::Sensitive,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// substr icase
|
// substr icase
|
||||||
if ifind(match_against, string, true /* fuzzy */).is_some() {
|
if ifind(match_against, string, true /* fuzzy */).is_some() {
|
||||||
return Some(StringFuzzyMatch::new(ContainType::substr, get_case_fold()));
|
return Some(StringFuzzyMatch::new(ContainType::Substr, get_case_fold()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// subseq samecase
|
// subseq samecase
|
||||||
if subsequence_in_string(string, match_against) {
|
if subsequence_in_string(string, match_against) {
|
||||||
return Some(StringFuzzyMatch::new(
|
return Some(StringFuzzyMatch::new(
|
||||||
ContainType::subseq,
|
ContainType::Subseq,
|
||||||
CaseFold::samecase,
|
CaseSensitivity::Sensitive,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,13 +254,13 @@ impl StringFuzzyMatch {
|
||||||
// smaller. Treat 'exact' types the same as 'prefix' types; this is because we do not
|
// smaller. Treat 'exact' types the same as 'prefix' types; this is because we do not
|
||||||
// prefer exact matches to prefix matches when presenting completions to the user.
|
// prefer exact matches to prefix matches when presenting completions to the user.
|
||||||
// Treat smartcase the same as samecase; see #3978.
|
// Treat smartcase the same as samecase; see #3978.
|
||||||
let effective_type = if self.typ == ContainType::exact {
|
let effective_type = if self.typ == ContainType::Exact {
|
||||||
ContainType::prefix
|
ContainType::Prefix
|
||||||
} else {
|
} else {
|
||||||
self.typ
|
self.typ
|
||||||
};
|
};
|
||||||
let effective_case = if self.case_fold == CaseFold::smartcase {
|
let effective_case = if self.case_fold == CaseSensitivity::Smart {
|
||||||
CaseFold::samecase
|
CaseSensitivity::Sensitive
|
||||||
} else {
|
} else {
|
||||||
self.case_fold
|
self.case_fold
|
||||||
};
|
};
|
||||||
|
@ -587,18 +595,63 @@ fn test_fuzzy_match() {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
validate!("", "", ContainType::exact, CaseFold::samecase);
|
validate!("", "", ContainType::Exact, CaseSensitivity::Sensitive);
|
||||||
validate!("alpha", "alpha", ContainType::exact, CaseFold::samecase);
|
validate!(
|
||||||
validate!("alp", "alpha", ContainType::prefix, CaseFold::samecase);
|
"alpha",
|
||||||
validate!("alpha", "AlPhA", ContainType::exact, CaseFold::smartcase);
|
"alpha",
|
||||||
validate!("alpha", "AlPhA!", ContainType::prefix, CaseFold::smartcase);
|
ContainType::Exact,
|
||||||
validate!("ALPHA", "alpha!", ContainType::prefix, CaseFold::icase);
|
CaseSensitivity::Sensitive
|
||||||
validate!("ALPHA!", "alPhA!", ContainType::exact, CaseFold::icase);
|
);
|
||||||
validate!("alPh", "ALPHA!", ContainType::prefix, CaseFold::icase);
|
validate!(
|
||||||
validate!("LPH", "ALPHA!", ContainType::substr, CaseFold::samecase);
|
"alp",
|
||||||
validate!("lph", "AlPhA!", ContainType::substr, CaseFold::smartcase);
|
"alpha",
|
||||||
validate!("lPh", "ALPHA!", ContainType::substr, CaseFold::icase);
|
ContainType::Prefix,
|
||||||
validate!("AA", "ALPHA!", ContainType::subseq, CaseFold::samecase);
|
CaseSensitivity::Sensitive
|
||||||
|
);
|
||||||
|
validate!("alpha", "AlPhA", ContainType::Exact, CaseSensitivity::Smart);
|
||||||
|
validate!(
|
||||||
|
"alpha",
|
||||||
|
"AlPhA!",
|
||||||
|
ContainType::Prefix,
|
||||||
|
CaseSensitivity::Smart
|
||||||
|
);
|
||||||
|
validate!(
|
||||||
|
"ALPHA",
|
||||||
|
"alpha!",
|
||||||
|
ContainType::Prefix,
|
||||||
|
CaseSensitivity::Insensitive
|
||||||
|
);
|
||||||
|
validate!(
|
||||||
|
"ALPHA!",
|
||||||
|
"alPhA!",
|
||||||
|
ContainType::Exact,
|
||||||
|
CaseSensitivity::Insensitive
|
||||||
|
);
|
||||||
|
validate!(
|
||||||
|
"alPh",
|
||||||
|
"ALPHA!",
|
||||||
|
ContainType::Prefix,
|
||||||
|
CaseSensitivity::Insensitive
|
||||||
|
);
|
||||||
|
validate!(
|
||||||
|
"LPH",
|
||||||
|
"ALPHA!",
|
||||||
|
ContainType::Substr,
|
||||||
|
CaseSensitivity::Sensitive
|
||||||
|
);
|
||||||
|
validate!("lph", "AlPhA!", ContainType::Substr, CaseSensitivity::Smart);
|
||||||
|
validate!(
|
||||||
|
"lPh",
|
||||||
|
"ALPHA!",
|
||||||
|
ContainType::Substr,
|
||||||
|
CaseSensitivity::Insensitive
|
||||||
|
);
|
||||||
|
validate!(
|
||||||
|
"AA",
|
||||||
|
"ALPHA!",
|
||||||
|
ContainType::Subseq,
|
||||||
|
CaseSensitivity::Sensitive
|
||||||
|
);
|
||||||
// no subseq icase
|
// no subseq icase
|
||||||
validate!("lh", "ALPHA!", None);
|
validate!("lh", "ALPHA!", None);
|
||||||
validate!("BB", "ALPHA!", None);
|
validate!("BB", "ALPHA!", None);
|
||||||
|
|
|
@ -16,7 +16,7 @@ use crate::future_feature_flags::feature_test;
|
||||||
use crate::future_feature_flags::FeatureFlag;
|
use crate::future_feature_flags::FeatureFlag;
|
||||||
use crate::wchar::prelude::*;
|
use crate::wchar::prelude::*;
|
||||||
use crate::wcstringutil::{
|
use crate::wcstringutil::{
|
||||||
string_fuzzy_match_string, string_suffixes_string_case_insensitive, CaseFold,
|
string_fuzzy_match_string, string_suffixes_string_case_insensitive, CaseSensitivity,
|
||||||
};
|
};
|
||||||
use crate::wutil::dir_iter::DirEntryType;
|
use crate::wutil::dir_iter::DirEntryType;
|
||||||
use crate::wutil::{dir_iter::DirEntry, lwstat, waccess};
|
use crate::wutil::{dir_iter::DirEntry, lwstat, waccess};
|
||||||
|
@ -84,9 +84,9 @@ struct WcCompletePack<'orig, 'f> {
|
||||||
|
|
||||||
// Weirdly specific and non-reusable helper function that makes its one call site much clearer.
|
// Weirdly specific and non-reusable helper function that makes its one call site much clearer.
|
||||||
fn has_prefix_match(comps: &CompletionReceiver, first: usize) -> bool {
|
fn has_prefix_match(comps: &CompletionReceiver, first: usize) -> bool {
|
||||||
comps[first..]
|
comps[first..].iter().any(|c| {
|
||||||
.iter()
|
c.r#match.is_exact_or_prefix() && c.r#match.case_fold == CaseSensitivity::Sensitive
|
||||||
.any(|c| c.r#match.is_exact_or_prefix() && c.r#match.case_fold == CaseFold::samecase)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Matches the string against the wildcard, and if the wildcard is a possible completion of the
|
/// Matches the string against the wildcard, and if the wildcard is a possible completion of the
|
||||||
|
|
Loading…
Reference in New Issue
Block a user