diff options
-rw-r--r-- | src/args.rs | 8 | ||||
-rw-r--r-- | src/main.rs | 47 | ||||
-rw-r--r-- | src/printer.rs | 27 | ||||
-rw-r--r-- | src/search_buffer.rs | 9 | ||||
-rw-r--r-- | src/search_stream.rs | 24 |
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)] |