1
0
mirror of https://github.com/BurntSushi/ripgrep.git synced 2025-04-19 09:02:15 +02:00

Merge pull request #42 from andschwa/files-with-matches

Files with matches
This commit is contained in:
Andrew Gallant 2016-09-25 14:53:31 -04:00 committed by GitHub
commit 95edcd4d3a
7 changed files with 96 additions and 9 deletions

View File

@ -16,6 +16,7 @@ disable_cross_doctests() {
} }
run_test_suite() { run_test_suite() {
cargo clean --target $TARGET --verbose
cargo build --target $TARGET --verbose cargo build --target $TARGET --verbose
cargo test --target $TARGET --verbose cargo test --target $TARGET --verbose

View File

@ -35,6 +35,11 @@ Only show count of line matches for each file.
.RS .RS
.RE .RE
.TP .TP
.B \-l, \-\-files\-with\-matches
Only show path of each file with matches.
.RS
.RE
.TP
.B \-\-color \f[I]WHEN\f[] .B \-\-color \f[I]WHEN\f[]
Whether to use coloring in match. Whether to use coloring in match.
Valid values are never, always or auto. Valid values are never, always or auto.

View File

@ -29,6 +29,9 @@ the raw speed of grep.
-c, --count -c, --count
: Only show count of line matches for each file. : Only show count of line matches for each file.
-l, --files-with-matches
: Only show path of each file with matches.
--color *WHEN* --color *WHEN*
: Whether to use coloring in match. Valid values are never, always or auto. : Whether to use coloring in match. Valid values are never, always or auto.
[default: auto] [default: auto]

View File

@ -47,6 +47,7 @@ rg recursively searches your current directory for a regex pattern.
Common options: Common options:
-a, --text Search binary files as if they were text. -a, --text Search binary files as if they were text.
-c, --count Only show count of line matches for each file. -c, --count Only show count of line matches for each file.
-l, --files-with-matches Only show path of each file with matches.
--color WHEN Whether to use coloring in match. --color WHEN Whether to use coloring in match.
Valid values are never, always or auto. Valid values are never, always or auto.
[default: auto] [default: auto]
@ -201,6 +202,7 @@ pub struct RawArgs {
flag_context: usize, flag_context: usize,
flag_context_separator: String, flag_context_separator: String,
flag_count: bool, flag_count: bool,
flag_files_with_matches: bool,
flag_debug: bool, flag_debug: bool,
flag_files: bool, flag_files: bool,
flag_follow: bool, flag_follow: bool,
@ -248,6 +250,7 @@ pub struct Args {
column: bool, column: bool,
context_separator: Vec<u8>, context_separator: Vec<u8>,
count: bool, count: bool,
files_with_matches: bool,
eol: u8, eol: u8,
files: bool, files: bool,
follow: bool, follow: bool,
@ -373,6 +376,7 @@ impl RawArgs {
column: self.flag_column, column: self.flag_column,
context_separator: unescape(&self.flag_context_separator), context_separator: unescape(&self.flag_context_separator),
count: self.flag_count, count: self.flag_count,
files_with_matches: self.flag_files_with_matches,
eol: eol, eol: eol,
files: self.flag_files, files: self.flag_files,
follow: self.flag_follow, follow: self.flag_follow,
@ -557,7 +561,7 @@ impl Args {
/// to the writer given. /// to the writer given.
pub fn out(&self) -> Out { pub fn out(&self) -> Out {
let mut out = Out::new(self.color); let mut out = Out::new(self.color);
if self.heading && !self.count { if self.heading && !self.count && !self.files_with_matches {
out = out.file_separator(b"".to_vec()); out = out.file_separator(b"".to_vec());
} else if self.before_context > 0 || self.after_context > 0 { } else if self.before_context > 0 || self.after_context > 0 {
out = out.file_separator(self.context_separator.clone()); out = out.file_separator(self.context_separator.clone());
@ -611,6 +615,7 @@ impl Args {
.after_context(self.after_context) .after_context(self.after_context)
.before_context(self.before_context) .before_context(self.before_context)
.count(self.count) .count(self.count)
.files_with_matches(self.files_with_matches)
.eol(self.eol) .eol(self.eol)
.line_number(self.line_number) .line_number(self.line_number)
.invert_match(self.invert_match) .invert_match(self.invert_match)
@ -629,6 +634,7 @@ impl Args {
) -> BufferSearcher<'a, W> { ) -> BufferSearcher<'a, W> {
BufferSearcher::new(printer, grep, path, buf) BufferSearcher::new(printer, grep, path, buf)
.count(self.count) .count(self.count)
.files_with_matches(self.files_with_matches)
.eol(self.eol) .eol(self.eol)
.line_number(self.line_number) .line_number(self.line_number)
.invert_match(self.invert_match) .invert_match(self.invert_match)

View File

@ -53,6 +53,14 @@ impl<'a, W: Send + Terminal> BufferSearcher<'a, W> {
self self
} }
/// If enabled, searching will print the path instead of each match.
///
/// Disabled by default.
pub fn files_with_matches(mut self, yes: bool) -> Self {
self.opts.files_with_matches = yes;
self
}
/// Set the end-of-line byte used by this searcher. /// Set the end-of-line byte used by this searcher.
pub fn eol(mut self, eol: u8) -> Self { pub fn eol(mut self, eol: u8) -> Self {
self.opts.eol = eol; self.opts.eol = eol;
@ -96,6 +104,9 @@ impl<'a, W: Send + Terminal> BufferSearcher<'a, W> {
self.print_match(m.start(), m.end()); self.print_match(m.start(), m.end());
} }
last_end = m.end(); last_end = m.end();
if self.opts.files_with_matches {
break;
}
} }
if self.opts.invert_match { if self.opts.invert_match {
let upto = self.buf.len(); let upto = self.buf.len();
@ -104,13 +115,16 @@ impl<'a, W: Send + Terminal> BufferSearcher<'a, W> {
if self.opts.count && self.match_count > 0 { if self.opts.count && self.match_count > 0 {
self.printer.path_count(self.path, self.match_count); self.printer.path_count(self.path, self.match_count);
} }
if self.opts.files_with_matches && self.match_count > 0 {
self.printer.path(self.path);
}
self.match_count self.match_count
} }
#[inline(always)] #[inline(always)]
pub fn print_match(&mut self, start: usize, end: usize) { pub fn print_match(&mut self, start: usize, end: usize) {
self.match_count += 1; self.match_count += 1;
if self.opts.count { if self.opts.skip_matches() {
return; return;
} }
self.count_lines(start); self.count_lines(start);
@ -237,6 +251,14 @@ and exhibited clearly, with a label attached.\
assert_eq!(out, "/baz.rs:2\n"); assert_eq!(out, "/baz.rs:2\n");
} }
#[test]
fn files_with_matches() {
let (count, out) = search(
"Sherlock", SHERLOCK, |s| s.files_with_matches(true));
assert_eq!(1, count);
assert_eq!(out, "/baz.rs\n");
}
#[test] #[test]
fn invert_match() { fn invert_match() {
let (count, out) = search( let (count, out) = search(

View File

@ -80,6 +80,7 @@ pub struct Options {
pub after_context: usize, pub after_context: usize,
pub before_context: usize, pub before_context: usize,
pub count: bool, pub count: bool,
pub files_with_matches: bool,
pub eol: u8, pub eol: u8,
pub invert_match: bool, pub invert_match: bool,
pub line_number: bool, pub line_number: bool,
@ -92,12 +93,22 @@ impl Default for Options {
after_context: 0, after_context: 0,
before_context: 0, before_context: 0,
count: false, count: false,
files_with_matches: false,
eol: b'\n', eol: b'\n',
invert_match: false, invert_match: false,
line_number: false, line_number: false,
text: false, text: false,
} }
} }
}
impl Options {
/// Both --count and --files-with-matches options imply that we should not
/// display matches at all.
pub fn skip_matches(&self) -> bool {
return self.count || self.files_with_matches;
}
} }
impl<'a, R: io::Read, W: Terminal + Send> Searcher<'a, R, W> { impl<'a, R: io::Read, W: Terminal + Send> Searcher<'a, R, W> {
@ -158,6 +169,14 @@ impl<'a, R: io::Read, W: Terminal + Send> Searcher<'a, R, W> {
self self
} }
/// If enabled, searching will print the path instead of each match.
///
/// Disabled by default.
pub fn files_with_matches(mut self, yes: bool) -> Self {
self.opts.files_with_matches = yes;
self
}
/// Set the end-of-line byte used by this searcher. /// Set the end-of-line byte used by this searcher.
pub fn eol(mut self, eol: u8) -> Self { pub fn eol(mut self, eol: u8) -> Self {
self.opts.eol = eol; self.opts.eol = eol;
@ -193,7 +212,7 @@ impl<'a, R: io::Read, W: Terminal + Send> Searcher<'a, R, W> {
self.line_count = if self.opts.line_number { Some(0) } else { None }; self.line_count = if self.opts.line_number { Some(0) } else { None };
self.last_match = Match::default(); self.last_match = Match::default();
self.after_context_remaining = 0; self.after_context_remaining = 0;
loop { while !self.terminate() {
let upto = self.inp.lastnl; let upto = self.inp.lastnl;
self.print_after_context(upto); self.print_after_context(upto);
if !try!(self.fill()) { if !try!(self.fill()) {
@ -202,7 +221,7 @@ impl<'a, R: io::Read, W: Terminal + Send> Searcher<'a, R, W> {
if !self.opts.text && self.inp.is_binary { if !self.opts.text && self.inp.is_binary {
break; break;
} }
while self.inp.pos < self.inp.lastnl { while !self.terminate() && self.inp.pos < self.inp.lastnl {
let matched = self.grep.read_match( let matched = self.grep.read_match(
&mut self.last_match, &mut self.last_match,
&mut self.inp.buf[..self.inp.lastnl], &mut self.inp.buf[..self.inp.lastnl],
@ -234,12 +253,21 @@ impl<'a, R: io::Read, W: Terminal + Send> Searcher<'a, R, W> {
} }
} }
} }
if self.opts.count && self.match_count > 0 { if self.match_count > 0 {
if self.opts.count {
self.printer.path_count(self.path, self.match_count); self.printer.path_count(self.path, self.match_count);
} else if self.opts.files_with_matches {
self.printer.path(self.path);
}
} }
Ok(self.match_count) Ok(self.match_count)
} }
#[inline(always)]
fn terminate(&self) -> bool {
return self.opts.files_with_matches && self.match_count > 0;
}
#[inline(always)] #[inline(always)]
fn fill(&mut self) -> Result<bool, Error> { fn fill(&mut self) -> Result<bool, Error> {
let mut keep = self.inp.lastnl; let mut keep = self.inp.lastnl;
@ -281,7 +309,7 @@ impl<'a, R: io::Read, W: Terminal + Send> Searcher<'a, R, W> {
#[inline(always)] #[inline(always)]
fn print_before_context(&mut self, upto: usize) { fn print_before_context(&mut self, upto: usize) {
if self.opts.count || self.opts.before_context == 0 { if self.opts.skip_matches() || self.opts.before_context == 0 {
return; return;
} }
let start = self.last_printed; let start = self.last_printed;
@ -304,7 +332,7 @@ impl<'a, R: io::Read, W: Terminal + Send> Searcher<'a, R, W> {
#[inline(always)] #[inline(always)]
fn print_after_context(&mut self, upto: usize) { fn print_after_context(&mut self, upto: usize) {
if self.opts.count || self.after_context_remaining == 0 { if self.opts.skip_matches() || self.after_context_remaining == 0 {
return; return;
} }
let start = self.last_printed; let start = self.last_printed;
@ -322,7 +350,7 @@ impl<'a, R: io::Read, W: Terminal + Send> Searcher<'a, R, W> {
#[inline(always)] #[inline(always)]
fn print_match(&mut self, start: usize, end: usize) { fn print_match(&mut self, start: usize, end: usize) {
self.match_count += 1; self.match_count += 1;
if self.opts.count { if self.opts.skip_matches() {
return; return;
} }
self.print_separator(start); self.print_separator(start);
@ -992,6 +1020,14 @@ fn main() {
assert_eq!(out, "/baz.rs:2\n"); assert_eq!(out, "/baz.rs:2\n");
} }
#[test]
fn files_with_matches() {
let (count, out) = search_smallcap(
"Sherlock", SHERLOCK, |s| s.files_with_matches(true));
assert_eq!(1, count);
assert_eq!(out, "/baz.rs\n");
}
#[test] #[test]
fn invert_match() { fn invert_match() {
let (count, out) = search_smallcap( let (count, out) = search_smallcap(

View File

@ -292,6 +292,20 @@ sherlock!(glob_negate, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
assert_eq!(lines, "file.py:Sherlock\n"); assert_eq!(lines, "file.py:Sherlock\n");
}); });
sherlock!(count, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
cmd.arg("--count");
let lines: String = wd.stdout(&mut cmd);
let expected = "sherlock:2\n";
assert_eq!(lines, expected);
});
sherlock!(files_with_matches, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
cmd.arg("--files-with-matches");
let lines: String = wd.stdout(&mut cmd);
let expected = "sherlock\n";
assert_eq!(lines, expected);
});
sherlock!(after_context, |wd: WorkDir, mut cmd: Command| { sherlock!(after_context, |wd: WorkDir, mut cmd: Command| {
cmd.arg("-A").arg("1"); cmd.arg("-A").arg("1");
let lines: String = wd.stdout(&mut cmd); let lines: String = wd.stdout(&mut cmd);