@ 261104.1

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

Changes to src/. All files

src/main.rs

@@ -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(".")),-    }-}

src/patterns.rs

@@ -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())