261028.3.4 · 90f6adad22b745f059e5260a6fd924225e86c334
fix: pattern-specific case checking
Check for uppercase characters differently based on what kind of pattern we have. This fixes a bug where if the pattern wasn't a valid regex, then we didn't correctly detect if it had an uppercase character.
reading declarations
@@ -37,8 +37,9 @@ use crate::filetypes::FileTypes; #[cfg(unix)] use crate::filter::OwnerFilter; use crate::filter::TimeFilter;-use crate::patterns::build_patterns;-use crate::regex_helper::{pattern_has_uppercase_char, pattern_matches_strings_with_leading_dot};+use crate::patterns::{+ build_patterns, pattern_has_uppercase_char, patterns_match_strings_with_leading_dots,+}; // We use jemalloc for performance reasons, see https://github.com/sharkdp/fd/pull/481 // FIXME: re-enable jemalloc on macOS, see comment in Cargo.toml file for more infos@@ -103,7 +104,10 @@ fn run() -> Result<ExitCode> { // The search will be case-sensitive if the command line flag is set or // if any of the patterns has an uppercase character (smart case). let ignore_case = opts.ignore_case- || !(opts.case_sensitive || patterns.iter().any(|pat| pattern_has_uppercase_char(pat)));+ || !(opts.case_sensitive+ || patterns+ .iter()+ .any(|pat| pattern_has_uppercase_char(pattern_type, pat))); let config = construct_config(opts)?; @@ -501,17 +505,3 @@ fn ensure_use_hidden_option_for_leading_dot_pattern( Ok(()) } }--fn patterns_match_strings_with_leading_dots(- patterns: &[String],- pattern_type: PatternType,-) -> bool {- let mut iter = patterns.iter();- match pattern_type {- PatternType::Regex => iter.any(|pat| pattern_matches_strings_with_leading_dot(pat)),- // fixed strings aren't anchored so always false- PatternType::Fixed => false,- // globs and exact just check if it starts with a .- PatternType::Glob | PatternType::Exact => patterns.iter().any(|pat| pat.starts_with(".")),- }-}
@@ -5,6 +5,8 @@ use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder}; use memchr::memmem; use regex::bytes::{RegexSet, RegexSetBuilder}; +use crate::regex_helper::{self, pattern_matches_strings_with_leading_dot};+ pub trait Matcher { fn matches_path(&self, path: &OsStr) -> bool; }@@ -99,6 +101,28 @@ pub fn build_patterns( } } +pub fn patterns_match_strings_with_leading_dots(+ patterns: &[String],+ pattern_type: PatternType,+) -> bool {+ let mut iter = patterns.iter();+ match pattern_type {+ PatternType::Regex => iter.any(|pat| pattern_matches_strings_with_leading_dot(pat)),+ // fixed strings aren't anchored so always false+ PatternType::Fixed => false,+ // globs and exact just check if it starts with a .+ PatternType::Glob | PatternType::Exact => patterns.iter().any(|pat| pat.starts_with(".")),+ }+}++pub fn pattern_has_uppercase_char(pattern_type: PatternType, pattern: &str) -> bool {+ match pattern_type {+ PatternType::Regex => regex_helper::pattern_has_uppercase_char(pattern),+ // For everything else it's sufficient to just check if there are any uppercase letters+ _ => pattern.chars().any(char::is_uppercase),+ }+}+ fn build_glob_matcher(patterns: Vec<String>, ignore_case: bool) -> Result<Patterns> { Ok(if patterns.len() == 1 { Box::new(build_glob(&patterns[0], ignore_case)?.compile_matcher())
@@ -649,6 +649,7 @@ fn test_smart_case_glob_searches() { ); te.assert_output(&["--glob", "C.Foo*"], "one/two/C.Foo2");+ te.assert_output(&["--glob", "*.Foo*"], "one/two/C.Foo2"); } /// Glob-based searches (--glob) in combination with --case-sensitive