mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2025-01-13 21:28:13 +02:00
ripgrep: when given no patterns, don't match
Generally speaking, ripgrep prevents the case of not having any patterns via its arg parsing. However, it is possible for users to provide a file of patterns via the `-f` flag. If that file is empty, then ripgrep has nothing to search for and therefore should not ever produce any match. One way of fixing this might be to replace the absence of patterns with a pattern that can never match, but this still requires opening and searching through every file, which is quite a waste. Instead, we detect this case explicitly and quit early. Fixes #900
This commit is contained in:
parent
0d11497d21
commit
dca8110da2
@ -84,6 +84,8 @@ Bug fixes:
|
||||
Upgrade `grep` crate to `regex-syntax 0.5.0`.
|
||||
* [BUG #893](https://github.com/BurntSushi/ripgrep/issues/893):
|
||||
Improve support for git submodules.
|
||||
* [BUG #900](https://github.com/BurntSushi/ripgrep/issues/900):
|
||||
When no patterns are given, ripgrep should never match anything.
|
||||
* [BUG #907](https://github.com/BurntSushi/ripgrep/issues/907):
|
||||
ripgrep will now stop traversing after the first file when `--quiet --files`
|
||||
is used.
|
||||
|
32
src/args.rs
32
src/args.rs
@ -36,6 +36,7 @@ pub struct Args {
|
||||
after_context: usize,
|
||||
before_context: usize,
|
||||
byte_offset: bool,
|
||||
can_match: bool,
|
||||
color_choice: termcolor::ColorChoice,
|
||||
colors: ColorSpecs,
|
||||
column: bool,
|
||||
@ -220,10 +221,9 @@ impl Args {
|
||||
|
||||
/// Returns true if the given arguments are known to never produce a match.
|
||||
pub fn never_match(&self) -> bool {
|
||||
self.max_count == Some(0)
|
||||
!self.can_match || self.max_count == Some(0)
|
||||
}
|
||||
|
||||
|
||||
/// Returns whether ripgrep should track stats for this run
|
||||
pub fn stats(&self) -> bool {
|
||||
self.stats
|
||||
@ -385,11 +385,13 @@ impl<'a> ArgMatches<'a> {
|
||||
let (before_context, after_context) = self.contexts()?;
|
||||
let (count, count_matches) = self.counts();
|
||||
let quiet = self.is_present("quiet");
|
||||
let (grep, can_match) = self.grep()?;
|
||||
let args = Args {
|
||||
paths: paths,
|
||||
after_context: after_context,
|
||||
before_context: before_context,
|
||||
byte_offset: self.is_present("byte-offset"),
|
||||
can_match: can_match,
|
||||
color_choice: self.color_choice(),
|
||||
colors: self.color_specs()?,
|
||||
column: self.column(),
|
||||
@ -403,7 +405,7 @@ impl<'a> ArgMatches<'a> {
|
||||
files: self.is_present("files"),
|
||||
follow: self.is_present("follow"),
|
||||
glob_overrides: self.overrides()?,
|
||||
grep: self.grep()?,
|
||||
grep: grep,
|
||||
heading: self.heading(),
|
||||
hidden: self.hidden(),
|
||||
ignore_files: self.ignore_files(),
|
||||
@ -491,17 +493,6 @@ impl<'a> ArgMatches<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the pattern that should be used for searching.
|
||||
///
|
||||
/// If multiple -e/--regexp flags are given, then they are all collapsed
|
||||
/// into one pattern.
|
||||
///
|
||||
/// If any part of the pattern isn't valid UTF-8, then an error is
|
||||
/// returned.
|
||||
fn pattern(&self) -> Result<String> {
|
||||
Ok(self.patterns()?.join("|"))
|
||||
}
|
||||
|
||||
/// Get a sequence of all available patterns from the command line.
|
||||
/// This includes reading the -e/--regexp and -f/--file flags.
|
||||
///
|
||||
@ -551,8 +542,6 @@ impl<'a> ArgMatches<'a> {
|
||||
// match first, and we wouldn't get colours in the output
|
||||
if self.is_present("passthru") && !self.is_present("count") {
|
||||
pats.push("^".to_string())
|
||||
} else if pats.is_empty() {
|
||||
pats.push(self.empty_pattern())
|
||||
}
|
||||
Ok(pats)
|
||||
}
|
||||
@ -901,7 +890,10 @@ impl<'a> ArgMatches<'a> {
|
||||
///
|
||||
/// If there was a problem extracting the pattern from the command line
|
||||
/// flags, then an error is returned.
|
||||
fn grep(&self) -> Result<Grep> {
|
||||
///
|
||||
/// If no match can ever occur, then `false` is returned. Otherwise,
|
||||
/// `true` is returned.
|
||||
fn grep(&self) -> Result<(Grep, bool)> {
|
||||
let smart =
|
||||
self.is_present("smart-case")
|
||||
&& !self.is_present("ignore-case")
|
||||
@ -909,7 +901,9 @@ impl<'a> ArgMatches<'a> {
|
||||
let casei =
|
||||
self.is_present("ignore-case")
|
||||
&& !self.is_present("case-sensitive");
|
||||
let mut gb = GrepBuilder::new(&self.pattern()?)
|
||||
let pats = self.patterns()?;
|
||||
let ok = !pats.is_empty();
|
||||
let mut gb = GrepBuilder::new(&pats.join("|"))
|
||||
.case_smart(smart)
|
||||
.case_insensitive(casei)
|
||||
.line_terminator(b'\n');
|
||||
@ -920,7 +914,7 @@ impl<'a> ArgMatches<'a> {
|
||||
if let Some(limit) = self.regex_size_limit()? {
|
||||
gb = gb.size_limit(limit);
|
||||
}
|
||||
Ok(gb.build()?)
|
||||
Ok((gb.build()?, ok))
|
||||
}
|
||||
|
||||
/// Builds the set of glob overrides from the command line flags.
|
||||
|
@ -1320,6 +1320,12 @@ clean!(regression_807, "test", ".", |wd: WorkDir, mut cmd: Command| {
|
||||
assert_eq!(lines, format!("{}:test\n", path(".a/c/file")));
|
||||
});
|
||||
|
||||
// See: https://github.com/BurntSushi/ripgrep/issues/900
|
||||
sherlock!(regression_900, "-fpat", "sherlock", |wd: WorkDir, mut cmd: Command| {
|
||||
wd.create("pat", "");
|
||||
wd.assert_err(&mut cmd);
|
||||
});
|
||||
|
||||
// See: https://github.com/BurntSushi/ripgrep/issues/1
|
||||
clean!(feature_1_sjis, "Шерлок Холмс", ".", |wd: WorkDir, mut cmd: Command| {
|
||||
let sherlock =
|
||||
|
Loading…
x
Reference in New Issue
Block a user