mirror of https://github.com/sharkdp/fd.git
Show error if pattern matches leading dot but --hidden is not given, closes #615
This commit is contained in:
parent
17bd256ae6
commit
cadaef3f07
13
src/main.rs
13
src/main.rs
|
@ -30,7 +30,7 @@ use crate::filetypes::FileTypes;
|
|||
use crate::filter::OwnerFilter;
|
||||
use crate::filter::{SizeFilter, TimeFilter};
|
||||
use crate::options::Options;
|
||||
use crate::regex_helper::pattern_has_uppercase_char;
|
||||
use crate::regex_helper::{pattern_has_uppercase_char, pattern_matches_strings_with_leading_dot};
|
||||
|
||||
// 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
|
||||
|
@ -431,6 +431,17 @@ fn run() -> Result<ExitCode> {
|
|||
}),
|
||||
};
|
||||
|
||||
if cfg!(unix)
|
||||
&& config.ignore_hidden
|
||||
&& pattern_matches_strings_with_leading_dot(&pattern_regex)
|
||||
{
|
||||
return Err(anyhow!(
|
||||
"The pattern seems to only match files with a leading dot, but hidden files are \
|
||||
filtered by default. Consider adding -H/--hidden to search hidden files as well \
|
||||
or adjust your search pattern."
|
||||
));
|
||||
}
|
||||
|
||||
let re = RegexBuilder::new(&pattern_regex)
|
||||
.case_insensitive(!config.case_sensitive)
|
||||
.dot_matches_new_line(true)
|
||||
|
|
|
@ -34,6 +34,45 @@ fn hir_has_uppercase_char(hir: &Hir) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
/// Determine if a regex pattern only matches strings starting with a literal dot (hidden files)
|
||||
pub fn pattern_matches_strings_with_leading_dot(pattern: &str) -> bool {
|
||||
let mut parser = ParserBuilder::new().allow_invalid_utf8(true).build();
|
||||
|
||||
parser
|
||||
.parse(pattern)
|
||||
.map(|hir| hir_matches_strings_with_leading_dot(&hir))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// See above.
|
||||
fn hir_matches_strings_with_leading_dot(hir: &Hir) -> bool {
|
||||
use regex_syntax::hir::*;
|
||||
|
||||
// Note: this only really detects the simplest case where a regex starts with
|
||||
// "^\\.", i.e. a start text anchor and a literal dot character. There are a lot
|
||||
// of other patterns that ONLY match hidden files, e.g. ^(\\.foo|\\.bar) which are
|
||||
// not (yet) detected by this algorithm.
|
||||
match *hir.kind() {
|
||||
HirKind::Concat(ref hirs) => {
|
||||
let mut hirs = hirs.iter();
|
||||
if let Some(hir) = hirs.next() {
|
||||
if *hir.kind() != HirKind::Anchor(Anchor::StartText) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Some(hir) = hirs.next() {
|
||||
*hir.kind() == HirKind::Literal(Literal::Unicode('.'))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pattern_has_uppercase_char_simple() {
|
||||
assert!(pattern_has_uppercase_char("A"));
|
||||
|
@ -50,3 +89,12 @@ fn pattern_has_uppercase_char_advanced() {
|
|||
assert!(!pattern_has_uppercase_char(r"\Acargo"));
|
||||
assert!(!pattern_has_uppercase_char(r"carg\x6F"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matches_strings_with_leading_dot_simple() {
|
||||
assert!(pattern_matches_strings_with_leading_dot("^\\.gitignore"));
|
||||
|
||||
assert!(!pattern_matches_strings_with_leading_dot("^.gitignore"));
|
||||
assert!(!pattern_matches_strings_with_leading_dot("\\.gitignore"));
|
||||
assert!(!pattern_matches_strings_with_leading_dot("^gitignore"));
|
||||
}
|
||||
|
|
|
@ -1699,3 +1699,18 @@ fn test_number_parsing_errors() {
|
|||
|
||||
te.assert_failure(&["--max-results=a"]);
|
||||
}
|
||||
|
||||
/// Print error if search pattern starts with a dot and --hidden is not set
|
||||
/// (Unix only, hidden files on Windows work differently)
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_error_if_hidden_not_set_and_pattern_starts_with_dot() {
|
||||
let te = TestEnv::new(&[], &[".gitignore", ".whatever", "non-hidden"]);
|
||||
|
||||
te.assert_failure(&["^\\.gitignore"]);
|
||||
te.assert_failure(&["--glob", ".gitignore"]);
|
||||
|
||||
te.assert_output(&["--hidden", "^\\.gitignore"], ".gitignore");
|
||||
te.assert_output(&["--hidden", "--glob", ".gitignore"], ".gitignore");
|
||||
te.assert_output(&[".gitignore"], "");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue