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:
commit
95edcd4d3a
@ -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
|
||||||
|
|
||||||
|
5
doc/rg.1
5
doc/rg.1
@ -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.
|
||||||
|
@ -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]
|
||||||
|
@ -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)
|
||||||
|
@ -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(
|
||||||
|
@ -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(
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user