mirror of
https://github.com/sharkdp/fd
synced 2024-11-05 16:58:21 +00:00
Improve smart case to only consider literal uppercase chars (#103)
This commit is contained in:
parent
8fc3a83d92
commit
b441528067
5 changed files with 40 additions and 6 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -9,6 +9,7 @@ dependencies = [
|
|||
"ignore 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ ansi_term = "0.9"
|
|||
clap = "2.26.0"
|
||||
atty = "0.2"
|
||||
regex = "0.2"
|
||||
regex-syntax = "0.4"
|
||||
ignore = "0.2"
|
||||
num_cpus = "1.6.2"
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ use std::io::Write;
|
|||
|
||||
use lscolors::LsColors;
|
||||
use walk::FileType;
|
||||
use regex_syntax::{Expr, ExprBuilder};
|
||||
|
||||
/// Root directory
|
||||
#[cfg(unix)]
|
||||
|
@ -78,3 +79,28 @@ pub fn error(message: &str) -> ! {
|
|||
writeln!(&mut ::std::io::stderr(), "{}", message).expect("Failed writing to stderr");
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
/// Determine if a regex pattern contains a literal uppercase character.
|
||||
pub fn pattern_has_uppercase_char(pattern: &str) -> bool {
|
||||
ExprBuilder::new()
|
||||
.parse(pattern)
|
||||
.map(|expr| expr_has_uppercase_char(&expr))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Determine if a regex expression contains a literal uppercase character.
|
||||
fn expr_has_uppercase_char(expr: &Expr) -> bool {
|
||||
match *expr {
|
||||
Expr::Literal { ref chars, .. } => chars.iter().any(|c| c.is_uppercase()),
|
||||
Expr::Class(ref ranges) => {
|
||||
ranges.iter().any(|r| {
|
||||
r.start.is_uppercase() || r.end.is_uppercase()
|
||||
})
|
||||
}
|
||||
Expr::Group { ref e, .. } => expr_has_uppercase_char(e),
|
||||
Expr::Repeat { ref e, .. } => expr_has_uppercase_char(e),
|
||||
Expr::Concat(ref es) => es.iter().any(expr_has_uppercase_char),
|
||||
Expr::Alternate(ref es) => es.iter().any(expr_has_uppercase_char),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
10
src/main.rs
10
src/main.rs
|
@ -3,6 +3,7 @@ extern crate clap;
|
|||
extern crate ansi_term;
|
||||
extern crate atty;
|
||||
extern crate regex;
|
||||
extern crate regex_syntax;
|
||||
extern crate ignore;
|
||||
extern crate num_cpus;
|
||||
|
||||
|
@ -22,7 +23,7 @@ use std::time;
|
|||
use atty::Stream;
|
||||
use regex::RegexBuilder;
|
||||
|
||||
use internal::{error, FdOptions, PathDisplay, ROOT_DIR};
|
||||
use internal::{error, pattern_has_uppercase_char, FdOptions, PathDisplay, ROOT_DIR};
|
||||
use lscolors::LsColors;
|
||||
use walk::FileType;
|
||||
|
||||
|
@ -65,11 +66,8 @@ fn main() {
|
|||
|
||||
// The search will be case-sensitive if the command line flag is set or
|
||||
// if the pattern has an uppercase character (smart case).
|
||||
let case_sensitive = if !matches.is_present("ignore-case") {
|
||||
matches.is_present("case-sensitive") || pattern.chars().any(char::is_uppercase)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let case_sensitive = !matches.is_present("ignore-case") &&
|
||||
(matches.is_present("case-sensitive") || pattern_has_uppercase_char(pattern));
|
||||
|
||||
let colored_output = match matches.value_of("color") {
|
||||
Some("always") => true,
|
||||
|
|
|
@ -115,6 +115,14 @@ fn test_smart_case() {
|
|||
te.assert_output(&["C.Foo"], "one/two/C.Foo2");
|
||||
|
||||
te.assert_output(&["Foo"], "one/two/C.Foo2");
|
||||
|
||||
// Only literal uppercase chars should trigger case sensitivity.
|
||||
te.assert_output(
|
||||
&["\\Ac"],
|
||||
"one/two/c.foo
|
||||
one/two/C.Foo2",
|
||||
);
|
||||
te.assert_output(&["\\AC"], "one/two/C.Foo2");
|
||||
}
|
||||
|
||||
/// Case sensitivity (--case-sensitive)
|
||||
|
|
Loading…
Reference in a new issue