summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndrew Gallant <jamslam@gmail.com>2016-09-28 20:50:50 -0400
committerAndrew Gallant <jamslam@gmail.com>2016-09-28 20:50:50 -0400
commit46dff8f4becc9007b073a1f3f412d6a1a544440c (patch)
tree867085ae3daeadbd75235db9427c0e7edb93a03b /src
parent7aa6e87952cfa36168e3fcb02bb009b2d8d52512 (diff)
Be better with short circuiting with --quiet.
It didn't make sense for --quiet to be part of the printer, because --quiet doesn't just mean "don't print," it also means, "stop after the first match is found." This needs to be wired all the way up through directory traversal, and it also needs to cause all of the search workers to quit as well. We do it with an atomic that is only checked with --quiet is given. Fixes #116.
Diffstat (limited to 'src')
-rw-r--r--src/args.rs8
-rw-r--r--src/main.rs47
-rw-r--r--src/printer.rs27
-rw-r--r--src/search_buffer.rs9
-rw-r--r--src/search_stream.rs24
5 files changed, 82 insertions, 33 deletions
diff --git a/src/args.rs b/src/args.rs
index 5cfb14ad..73675ff4 100644
--- a/src/args.rs
+++ b/src/args.rs
@@ -571,6 +571,11 @@ impl Args {
self.mmap
}
+ /// Whether ripgrep should be quiet or not.
+ pub fn quiet(&self) -> bool {
+ self.quiet
+ }
+
/// Create a new printer of individual search results that writes to the
/// writer given.
pub fn printer<W: Terminal + Send>(&self, wtr: W) -> Printer<W> {
@@ -580,7 +585,6 @@ impl Args {
.eol(self.eol)
.heading(self.heading)
.line_per_match(self.line_per_match)
- .quiet(self.quiet)
.null(self.null)
.with_filename(self.with_filename);
if let Some(ref rep) = self.replace {
@@ -660,6 +664,7 @@ impl Args {
.eol(self.eol)
.line_number(self.line_number)
.invert_match(self.invert_match)
+ .quiet(self.quiet)
.text(self.text)
}
@@ -679,6 +684,7 @@ impl Args {
.eol(self.eol)
.line_number(self.line_number)
.invert_match(self.invert_match)
+ .quiet(self.quiet)
.text(self.text)
}
diff --git a/src/main.rs b/src/main.rs
index b095f009..5f8b3dfe 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -27,6 +27,7 @@ use std::path::Path;
use std::process;
use std::result;
use std::sync::{Arc, Mutex};
+use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::cmp;
@@ -102,6 +103,7 @@ fn run(args: Args) -> Result<u64> {
}
let out = Arc::new(Mutex::new(args.out()));
+ let quiet_matched = QuietMatched::new(args.quiet());
let mut workers = vec![];
let workq = {
@@ -109,6 +111,7 @@ fn run(args: Args) -> Result<u64> {
for _ in 0..threads {
let worker = MultiWorker {
chan_work: stealer.clone(),
+ quiet_matched: quiet_matched.clone(),
out: out.clone(),
outbuf: Some(args.outbuf()),
worker: Worker {
@@ -124,11 +127,17 @@ fn run(args: Args) -> Result<u64> {
};
let mut paths_searched: u64 = 0;
for p in paths {
+ if quiet_matched.has_match() {
+ break;
+ }
if p == Path::new("-") {
paths_searched += 1;
workq.push(Work::Stdin);
} else {
for ent in try!(args.walker(p)) {
+ if quiet_matched.has_match() {
+ break;
+ }
paths_searched += 1;
workq.push(Work::File(ent));
}
@@ -161,6 +170,9 @@ fn run_one_thread(args: Arc<Args>) -> Result<u64> {
let mut paths_searched: u64 = 0;
for p in paths {
+ if args.quiet() && worker.match_count > 0 {
+ break;
+ }
if p == Path::new("-") {
paths_searched += 1;
let mut printer = args.printer(&mut term);
@@ -175,6 +187,9 @@ fn run_one_thread(args: Arc<Args>) -> Result<u64> {
paths_searched += 1;
let mut printer = args.printer(&mut term);
if worker.match_count > 0 {
+ if args.quiet() {
+ break;
+ }
if let Some(sep) = args.file_separator() {
printer = printer.file_separator(sep);
}
@@ -240,6 +255,7 @@ enum WorkReady {
struct MultiWorker {
chan_work: Stealer<Work>,
+ quiet_matched: QuietMatched,
out: Arc<Mutex<Out>>,
#[cfg(not(windows))]
outbuf: Option<ColoredTerminal<term::TerminfoTerminal<Vec<u8>>>>,
@@ -258,6 +274,9 @@ struct Worker {
impl MultiWorker {
fn run(mut self) -> u64 {
loop {
+ if self.quiet_matched.has_match() {
+ break;
+ }
let work = match self.chan_work.steal() {
Stolen::Empty | Stolen::Abort => continue,
Stolen::Data(Work::Quit) => break,
@@ -276,6 +295,9 @@ impl MultiWorker {
outbuf.clear();
let mut printer = self.worker.args.printer(outbuf);
self.worker.do_work(&mut printer, work);
+ if self.quiet_matched.set_match(self.worker.match_count > 0) {
+ break;
+ }
let outbuf = printer.into_inner();
if !outbuf.get_ref().is_empty() {
let mut out = self.out.lock().unwrap();
@@ -359,3 +381,28 @@ impl Worker {
).run())
}
}
+
+#[derive(Clone, Debug)]
+struct QuietMatched(Arc<Option<AtomicBool>>);
+
+impl QuietMatched {
+ fn new(quiet: bool) -> QuietMatched {
+ let atomic = if quiet { Some(AtomicBool::new(false)) } else { None };
+ QuietMatched(Arc::new(atomic))
+ }
+
+ fn has_match(&self) -> bool {
+ match *self.0 {
+ None => false,
+ Some(ref matched) => matched.load(Ordering::SeqCst),
+ }
+ }
+
+ fn set_match(&self, yes: bool) -> bool {
+ match *self.0 {
+ None => false,
+ Some(_) if !yes => false,
+ Some(ref m) => { m.store(true, Ordering::SeqCst); true }
+ }
+ }
+}
diff --git a/src/printer.rs b/src/printer.rs
index 11848830..9a5c649d 100644
--- a/src/printer.rs
+++ b/src/printer.rs
@@ -33,8 +33,6 @@ pub struct Printer<W> {
heading: bool,
/// Whether to show every match on its own line.
line_per_match: bool,
- /// Whether to suppress all output.
- quiet: bool,
/// Whether to print NUL bytes after a file path instead of new lines
/// or `:`.
null: bool,
@@ -42,8 +40,7 @@ pub struct Printer<W> {
replace: Option<Vec<u8>>,
/// Whether to prefix each match with the corresponding file name.
with_filename: bool,
-
- /// The choice of Colours
+ /// The choice of colors.
color_choice: ColorChoice
}
@@ -54,7 +51,6 @@ struct ColorChoice {
}
impl ColorChoice {
-
#[cfg(unix)]
pub fn new() -> ColorChoice {
ColorChoice {
@@ -86,7 +82,6 @@ impl<W: Terminal + Send> Printer<W> {
file_separator: None,
heading: false,
line_per_match: false,
- quiet: false,
null: false,
replace: None,
with_filename: false,
@@ -141,12 +136,6 @@ impl<W: Terminal + Send> Printer<W> {
self
}
- /// When set, all output is suppressed.
- pub fn quiet(mut self, yes: bool) -> Printer<W> {
- self.quiet = yes;
- self
- }
-
/// Replace every match in each matching line with the replacement string
/// given.
///
@@ -168,11 +157,6 @@ impl<W: Terminal + Send> Printer<W> {
self.has_printed
}
- /// Returns true if the printer has been configured to be quiet.
- pub fn is_quiet(&self) -> bool {
- self.quiet
- }
-
/// Flushes the underlying writer and returns it.
pub fn into_inner(mut self) -> W {
let _ = self.wtr.flush();
@@ -222,9 +206,6 @@ impl<W: Terminal + Send> Printer<W> {
/// Prints the context separator.
pub fn context_separate(&mut self) {
// N.B. We can't use `write` here because of borrowing restrictions.
- if self.quiet {
- return;
- }
if self.context_separator.is_empty() {
return;
}
@@ -398,9 +379,6 @@ impl<W: Terminal + Send> Printer<W> {
}
fn write(&mut self, buf: &[u8]) {
- if self.quiet {
- return;
- }
self.has_printed = true;
let _ = self.wtr.write_all(buf);
}
@@ -411,9 +389,6 @@ impl<W: Terminal + Send> Printer<W> {
}
fn write_file_sep(&mut self) {
- if self.quiet {
- return;
- }
if let Some(ref sep) = self.file_separator {
self.has_printed = true;
let _ = self.wtr.write_all(sep);
diff --git a/src/search_buffer.rs b/src/search_buffer.rs
index efc66cd7..6a32a631 100644
--- a/src/search_buffer.rs
+++ b/src/search_buffer.rs
@@ -81,6 +81,13 @@ impl<'a, W: Send + Terminal> BufferSearcher<'a, W> {
self
}
+ /// If enabled, don't show any output and quit searching after the first
+ /// match is found.
+ pub fn quiet(mut self, yes: bool) -> Self {
+ self.opts.quiet = yes;
+ self
+ }
+
/// If enabled, search binary files as if they were text.
pub fn text(mut self, yes: bool) -> Self {
self.opts.text = yes;
@@ -104,7 +111,7 @@ impl<'a, W: Send + Terminal> BufferSearcher<'a, W> {
self.print_match(m.start(), m.end());
}
last_end = m.end();
- if self.printer.is_quiet() || self.opts.files_with_matches {
+ if self.opts.stop_after_first_match() {
break;
}
}
diff --git a/src/search_stream.rs b/src/search_stream.rs
index 3407366e..8f458ca5 100644
--- a/src/search_stream.rs
+++ b/src/search_stream.rs
@@ -84,6 +84,7 @@ pub struct Options {
pub eol: u8,
pub invert_match: bool,
pub line_number: bool,
+ pub quiet: bool,
pub text: bool,
}
@@ -97,6 +98,7 @@ impl Default for Options {
eol: b'\n',
invert_match: false,
line_number: false,
+ quiet: false,
text: false,
}
}
@@ -104,10 +106,16 @@ impl Default for Options {
}
impl Options {
- /// Both --count and --files-with-matches options imply that we should not
- /// display matches at all.
+ /// Several options (--quiet, --count, --files-with-matches) imply that
+ /// we shouldn't ever display matches.
pub fn skip_matches(&self) -> bool {
- return self.count || self.files_with_matches;
+ self.count || self.files_with_matches || self.quiet
+ }
+
+ /// Some options (--quiet, --files-with-matches) imply that we can stop
+ /// searching after the first match.
+ pub fn stop_after_first_match(&self) -> bool {
+ self.files_with_matches || self.quiet
}
}
@@ -197,6 +205,13 @@ impl<'a, R: io::Read, W: Terminal + Send> Searcher<'a, R, W> {
self
}
+ /// If enabled, don't show any output and quit searching after the first
+ /// match is found.
+ pub fn quiet(mut self, yes: bool) -> Self {
+ self.opts.quiet = yes;
+ self
+ }
+
/// If enabled, search binary files as if they were text.
pub fn text(mut self, yes: bool) -> Self {
self.opts.text = yes;
@@ -265,8 +280,7 @@ impl<'a, R: io::Read, W: Terminal + Send> Searcher<'a, R, W> {
#[inline(always)]
fn terminate(&self) -> bool {
- self.match_count > 0
- && (self.printer.is_quiet() || self.opts.files_with_matches)
+ self.match_count > 0 && self.opts.stop_after_first_match()
}
#[inline(always)]