summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Gallant <jamslam@gmail.com>2016-09-22 21:32:38 -0400
committerAndrew Gallant <jamslam@gmail.com>2016-09-22 21:32:38 -0400
commitdfebed6cbe44593094e1632acd2d360e47d3abf1 (patch)
treeb9960015e7aadfbda372ffeae3f2d0a6d688e784
parent9981e7883ae936ae8863628a1cfb6d417e9d6fe7 (diff)
Add --vimgrep flag.
The --vimgrep flag forces a line to be printed for every match, with line and column numbers.
-rw-r--r--doc/rg.18
-rw-r--r--doc/rg.1.md5
-rw-r--r--src/args.rs17
-rw-r--r--src/printer.rs44
-rw-r--r--tests/tests.rs13
5 files changed, 82 insertions, 5 deletions
diff --git a/doc/rg.1 b/doc/rg.1
index 1e401906..300ad1b1 100644
--- a/doc/rg.1
+++ b/doc/rg.1
@@ -237,6 +237,14 @@ Defaults to the number of logical CPUs (capped at 6).
Show the version number of ripgrep and exit.
.RS
.RE
+.TP
+.B \-\-vimgrep
+Show results with every match on its own line, including line numbers
+and column numbers.
+(With this option, a line with more than one match of the regex will be
+printed more than once.)
+.RS
+.RE
.SH FILE TYPE MANAGEMENT OPTIONS
.TP
.B \-\-type\-list
diff --git a/doc/rg.1.md b/doc/rg.1.md
index 953bc1f8..81e974eb 100644
--- a/doc/rg.1.md
+++ b/doc/rg.1.md
@@ -153,6 +153,11 @@ the raw speed of grep.
--version
: Show the version number of ripgrep and exit.
+--vimgrep
+: Show results with every match on its own line, including line
+ numbers and column numbers. (With this option, a line with more
+ than one match of the regex will be printed more than once.)
+
# FILE TYPE MANAGEMENT OPTIONS
--type-list
diff --git a/src/args.rs b/src/args.rs
index 77210a8f..777556dc 100644
--- a/src/args.rs
+++ b/src/args.rs
@@ -153,6 +153,11 @@ Less common options:
--version
Show the version number of ripgrep and exit.
+ --vimgrep
+ Show results with every match on its own line, including line
+ numbers and column numbers. (With this option, a line with more
+ than one match of the regex will be printed more than once.)
+
File type management options:
--type-list
Show all supported file types and their associated globs.
@@ -206,6 +211,7 @@ pub struct RawArgs {
flag_type_add: Vec<String>,
flag_type_clear: Vec<String>,
flag_unrestricted: u32,
+ flag_vimgrep: bool,
flag_with_filename: bool,
flag_word_regexp: bool,
}
@@ -231,6 +237,7 @@ pub struct Args {
ignore_case: bool,
invert_match: bool,
line_number: bool,
+ line_per_match: bool,
mmap: bool,
no_ignore: bool,
no_ignore_parent: bool,
@@ -302,7 +309,9 @@ impl RawArgs {
self.flag_threads
};
let color =
- if self.flag_color == "auto" {
+ if self.flag_vimgrep {
+ false
+ } else if self.flag_color == "auto" {
atty::on_stdout() || self.flag_pretty
} else {
self.flag_color == "always"
@@ -344,6 +353,7 @@ impl RawArgs {
ignore_case: self.flag_ignore_case,
invert_match: self.flag_invert_match,
line_number: !self.flag_no_line_number && self.flag_line_number,
+ line_per_match: self.flag_vimgrep,
mmap: mmap,
no_ignore: no_ignore,
no_ignore_parent:
@@ -367,6 +377,10 @@ impl RawArgs {
args.heading = true;
}
}
+ if self.flag_vimgrep {
+ args.column = true;
+ args.line_number = true;
+ }
Ok(args)
}
@@ -490,6 +504,7 @@ impl Args {
.context_separator(self.context_separator.clone())
.eol(self.eol)
.heading(self.heading)
+ .line_per_match(self.line_per_match)
.quiet(self.quiet)
.with_filename(self.with_filename);
if let Some(ref rep) = self.replace {
diff --git a/src/printer.rs b/src/printer.rs
index afc0de4f..65905f9c 100644
--- a/src/printer.rs
+++ b/src/printer.rs
@@ -28,6 +28,8 @@ pub struct Printer<W> {
///
/// N.B. If with_filename is false, then this setting has no effect.
heading: bool,
+ /// Whether to show every match on its own line.
+ line_per_match: bool,
/// Whether to suppress all output.
quiet: bool,
/// A string to use as a replacement of each match in a matching line.
@@ -46,6 +48,7 @@ impl<W: Terminal + Send> Printer<W> {
context_separator: "--".to_string().into_bytes(),
eol: b'\n',
heading: false,
+ line_per_match: false,
quiet: false,
replace: None,
with_filename: false,
@@ -79,6 +82,12 @@ impl<W: Terminal + Send> Printer<W> {
self
}
+ /// Whether to show every match on its own line.
+ pub fn line_per_match(mut self, yes: bool) -> Printer<W> {
+ self.line_per_match = yes;
+ self
+ }
+
/// When set, all output is suppressed.
pub fn quiet(mut self, yes: bool) -> Printer<W> {
self.quiet = yes;
@@ -166,6 +175,34 @@ impl<W: Terminal + Send> Printer<W> {
end: usize,
line_number: Option<u64>,
) {
+ if !self.line_per_match {
+ let column =
+ if self.column {
+ Some(re.find(&buf[start..end])
+ .map(|(s, _)| s + 1).unwrap_or(0) as u64)
+ } else {
+ None
+ };
+ return self.write_match(
+ re, path, buf, start, end, line_number, column);
+ }
+ for (s, _) in re.find_iter(&buf[start..end]) {
+ let column = if self.column { Some(s as u64) } else { None };
+ self.write_match(
+ re, path.as_ref(), buf, start, end, line_number, column);
+ }
+ }
+
+ fn write_match<P: AsRef<Path>>(
+ &mut self,
+ re: &Regex,
+ path: P,
+ buf: &[u8],
+ start: usize,
+ end: usize,
+ line_number: Option<u64>,
+ column: Option<u64>,
+ ) {
if self.heading && self.with_filename && !self.has_printed {
self.write_heading(path.as_ref());
} else if !self.heading && self.with_filename {
@@ -175,8 +212,7 @@ impl<W: Terminal + Send> Printer<W> {
if let Some(line_number) = line_number {
self.line_number(line_number, b':');
}
- if self.column {
- let c = re.find(&buf[start..end]).map(|(s, _)| s + 1).unwrap_or(0);
+ if let Some(c) = column {
self.write(c.to_string().as_bytes());
self.write(b":");
}
@@ -185,14 +221,14 @@ impl<W: Terminal + Send> Printer<W> {
&buf[start..end], &**self.replace.as_ref().unwrap());
self.write(&line);
} else {
- self.write_match(re, &buf[start..end]);
+ self.write_matched_line(re, &buf[start..end]);
}
if buf[start..end].last() != Some(&self.eol) {
self.write_eol();
}
}
- pub fn write_match(&mut self, re: &Regex, buf: &[u8]) {
+ fn write_matched_line(&mut self, re: &Regex, buf: &[u8]) {
if !self.wtr.supports_color() {
self.write(buf);
return;
diff --git a/tests/tests.rs b/tests/tests.rs
index 1341aa10..693c74be 100644
--- a/tests/tests.rs
+++ b/tests/tests.rs
@@ -569,6 +569,19 @@ sherlock!(unrestricted3, "foo", ".", |wd: WorkDir, mut cmd: Command| {
assert_eq!(lines, "file:foo\x00bar\nfile:foo\x00baz\n");
});
+sherlock!(vimgrep, "Sherlock|Watson", ".", |wd: WorkDir, mut cmd: Command| {
+ cmd.arg("--vimgrep");
+
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+sherlock:1:15:For the Doctor Watsons of this world, as opposed to the Sherlock
+sherlock:1:56:For the Doctor Watsons of this world, as opposed to the Sherlock
+sherlock:3:48:be, to a very large extent, the result of luck. Sherlock Holmes
+sherlock:5:11:but Doctor Watson has to have it taken out for him and dusted,
+";
+ assert_eq!(lines, expected);
+});
+
#[test]
fn binary_nosearch() {
let wd = WorkDir::new("binary_nosearch");