diff --git a/Cargo.lock b/Cargo.lock index 9f6ee78c..657f430c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,6 @@ version = "0.3.2" dependencies = [ "bytecount 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.19.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ctrlc 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "grep 0.1.4", "ignore 0.1.6", @@ -66,16 +65,6 @@ name = "crossbeam" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "ctrlc" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "env_logger" version = "0.3.5" @@ -335,7 +324,6 @@ dependencies = [ "checksum bytecount 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49e3c21915578e2300b08d3c174a8ac887e0c6421dff86fdc4d741dc29e5d413" "checksum clap 2.19.2 (registry+https://github.com/rust-lang/crates.io-index)" = "305ad043f009db535a110200541d4567b63e172b1fe030313fbb92565da7ed24" "checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97" -"checksum ctrlc 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "77f98bb69e3fefadcc5ca80a1368a55251f70295168203e01165bcaecb270891" "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344" "checksum fs2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "640001e1bd865c7c32806292822445af576a6866175b5225aa2087ca5e3de551" diff --git a/Cargo.toml b/Cargo.toml index a2bd2c57..3a24d53a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,6 @@ path = "tests/tests.rs" [dependencies] bytecount = "0.1.4" clap = "2.19.0" -ctrlc = "2.0" env_logger = "0.3" grep = { version = "0.1.4", path = "grep" } ignore = { version = "0.1.5", path = "ignore" } diff --git a/src/args.rs b/src/args.rs index 2b87b32c..4048b119 100644 --- a/src/args.rs +++ b/src/args.rs @@ -6,6 +6,8 @@ use std::io::{self, BufRead}; use std::ops; use std::path::{Path, PathBuf}; use std::process; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; use clap; use env_logger; @@ -60,6 +62,7 @@ pub struct Args { no_messages: bool, null: bool, quiet: bool, + quiet_matched: QuietMatched, replace: Option>, text: bool, threads: usize, @@ -125,6 +128,15 @@ impl Args { self.quiet } + /// Returns a thread safe boolean for determining whether to quit a search + /// early when quiet mode is enabled. + /// + /// If quiet mode is disabled, then QuietMatched.has_match always returns + /// false. + pub fn quiet_matched(&self) -> QuietMatched { + self.quiet_matched.clone() + } + /// Create a new printer of individual search results that writes to the /// writer given. pub fn printer(&self, wtr: W) -> Printer { @@ -145,7 +157,12 @@ impl Args { /// Retrieve the configured file separator. pub fn file_separator(&self) -> Option> { - if self.heading && !self.count && !self.files_with_matches && !self.files_without_matches { + let use_heading_sep = + self.heading + && !self.count + && !self.files_with_matches + && !self.files_without_matches; + if use_heading_sep { Some(b"".to_vec()) } else if self.before_context > 0 || self.after_context > 0 { Some(self.context_separator.clone()) @@ -264,8 +281,8 @@ impl Args { } } -/// `ArgMatches` wraps `clap::ArgMatches` and provides semantic meaning to several -/// options/flags. +/// `ArgMatches` wraps `clap::ArgMatches` and provides semantic meaning to +/// several options/flags. struct ArgMatches<'a>(clap::ArgMatches<'a>); impl<'a> ops::Deref for ArgMatches<'a> { @@ -281,6 +298,7 @@ impl<'a> ArgMatches<'a> { let mmap = try!(self.mmap(&paths)); let with_filename = self.with_filename(&paths); let (before_context, after_context) = try!(self.contexts()); + let quiet = self.is_present("quiet"); let args = Args { paths: paths, after_context: after_context, @@ -312,7 +330,8 @@ impl<'a> ArgMatches<'a> { no_ignore_vcs: self.no_ignore_vcs(), no_messages: self.is_present("no-messages"), null: self.is_present("null"), - quiet: self.is_present("quiet"), + quiet: quiet, + quiet_matched: QuietMatched::new(quiet), replace: self.replace(), text: self.text(), threads: try!(self.threads()), @@ -746,3 +765,42 @@ fn pattern_to_str(s: &OsStr) -> Result<&str> { s.to_string_lossy()))), } } + +/// A simple thread safe abstraction for determining whether a search should +/// stop if the user has requested quiet mode. +#[derive(Clone, Debug)] +pub struct QuietMatched(Arc>); + +impl QuietMatched { + /// Create a new QuietMatched value. + /// + /// If quiet is true, then set_match and has_match will reflect whether + /// a search should quit or not because it found a match. + /// + /// If quiet is false, then set_match is always a no-op and has_match + /// always returns false. + fn new(quiet: bool) -> QuietMatched { + let atomic = if quiet { Some(AtomicBool::new(false)) } else { None }; + QuietMatched(Arc::new(atomic)) + } + + /// Returns true if and only if quiet mode is enabled and a match has + /// occurred. + pub fn has_match(&self) -> bool { + match *self.0 { + None => false, + Some(ref matched) => matched.load(Ordering::SeqCst), + } + } + + /// Sets whether a match has occurred or not. + /// + /// If quiet mode is disabled, then this is a no-op. + pub 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/main.rs b/src/main.rs index a26812b1..236c093e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,6 @@ extern crate bytecount; #[macro_use] extern crate clap; -extern crate ctrlc; extern crate env_logger; extern crate grep; extern crate ignore; @@ -21,16 +20,13 @@ extern crate termcolor; extern crate winapi; use std::error::Error; -use std::io::Write; use std::process; use std::result; use std::sync::Arc; -use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::mpsc; use std::thread; -use termcolor::WriteColor; - use args::Args; use worker::Work; @@ -74,15 +70,6 @@ fn run(args: Arc) -> Result { if args.never_match() { return Ok(0); } - { - let args = args.clone(); - ctrlc::set_handler(move || { - let mut writer = args.stdout(); - let _ = writer.reset(); - let _ = writer.flush(); - process::exit(1); - }); - } let threads = args.threads(); if args.files() { if threads == 1 || args.is_one_path() { @@ -101,7 +88,7 @@ fn run(args: Arc) -> Result { fn run_parallel(args: Arc) -> Result { let bufwtr = Arc::new(args.buffer_writer()); - let quiet_matched = QuietMatched::new(args.quiet()); + let quiet_matched = args.quiet_matched(); let paths_searched = Arc::new(AtomicUsize::new(0)); let match_count = Arc::new(AtomicUsize::new(0)); @@ -281,42 +268,3 @@ fn eprint_nothing_searched() { applied a filter you didn't expect. \ Try running again with --debug."); } - -/// A simple thread safe abstraction for determining whether a search should -/// stop if the user has requested quiet mode. -#[derive(Clone, Debug)] -pub struct QuietMatched(Arc>); - -impl QuietMatched { - /// Create a new QuietMatched value. - /// - /// If quiet is true, then set_match and has_match will reflect whether - /// a search should quit or not because it found a match. - /// - /// If quiet is false, then set_match is always a no-op and has_match - /// always returns false. - pub fn new(quiet: bool) -> QuietMatched { - let atomic = if quiet { Some(AtomicBool::new(false)) } else { None }; - QuietMatched(Arc::new(atomic)) - } - - /// Returns true if and only if quiet mode is enabled and a match has - /// occurred. - pub fn has_match(&self) -> bool { - match *self.0 { - None => false, - Some(ref matched) => matched.load(Ordering::SeqCst), - } - } - - /// Sets whether a match has occurred or not. - /// - /// If quiet mode is disabled, then this is a no-op. - pub 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 } - } - } -}