diff --git a/src/args.rs b/src/args.rs index 0f49e53e4..5bc8e43b5 100644 --- a/src/args.rs +++ b/src/args.rs @@ -165,6 +165,10 @@ Less common options: a list of matching files such as with --count, --files-with-matches and --files. + -o, --only-matching + Only print the text that matches the regex, with each match on a + separate line. + -p, --pretty Alias for --color=always --heading -n. @@ -236,6 +240,7 @@ pub struct RawArgs { flag_no_mmap: bool, flag_no_filename: bool, flag_null: bool, + flag_only_matching: bool, flag_pretty: bool, flag_quiet: bool, flag_regexp: Vec, @@ -283,6 +288,7 @@ pub struct Args { no_ignore_parent: bool, no_ignore_vcs: bool, null: bool, + only_matching: bool, quiet: bool, replace: Option>, text: bool, @@ -415,6 +421,7 @@ impl RawArgs { // --no-ignore implies --no-ignore-vcs self.flag_no_ignore_vcs || no_ignore, null: self.flag_null, + only_matching: self.flag_only_matching, quiet: self.flag_quiet, replace: self.flag_replace.clone().map(|s| s.into_bytes()), text: text, @@ -570,7 +577,8 @@ impl Args { .line_per_match(self.line_per_match) .quiet(self.quiet) .null(self.null) - .with_filename(self.with_filename); + .with_filename(self.with_filename) + .only_matching(self.only_matching); if let Some(ref rep) = self.replace { p = p.replace(rep.clone()); } diff --git a/src/printer.rs b/src/printer.rs index 21845beb2..7b9a53fa5 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -42,6 +42,8 @@ pub struct Printer { replace: Option>, /// Whether to prefix each match with the corresponding file name. with_filename: bool, + /// Whether to only print matching text. + only_matching: bool, /// The choice of Colours color_choice: ColorChoice @@ -90,6 +92,7 @@ impl Printer { null: false, replace: None, with_filename: false, + only_matching: false, color_choice: ColorChoice::new() } } @@ -163,6 +166,13 @@ impl Printer { self } + /// When set, only the text that matches the regex is printed, with each match on a + /// separate line. + pub fn only_matching(mut self, yes: bool) -> Printer { + self.only_matching = yes; + self + } + /// Returns true if and only if something has been printed. pub fn has_printed(&self) -> bool { self.has_printed @@ -242,6 +252,13 @@ impl Printer { end: usize, line_number: Option, ) { + if self.only_matching { + for (match_start, match_end) in re.find_iter(&buf[start..end]) { + self.write(&buf[start + match_start..start + match_end]); + self.write_eol(); + } + return; + } if !self.line_per_match { let column = if self.column { diff --git a/tests/tests.rs b/tests/tests.rs index 660b3523e..d81a07cd6 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -925,3 +925,17 @@ fn type_list() { // This can change over time, so just make sure we print something. assert!(!lines.is_empty()); } + +// See: https://github.com/BurntSushi/ripgrep/issues/34 +sherlock!(only_matching, r"of \w+", |wd: WorkDir, mut cmd: Command| { + cmd.arg("--only-matching"); + let lines: String = wd.stdout(&mut cmd); + let expected = "\ +of this +of detective +of luck +of straw +of cigar +"; + assert_eq!(lines, expected); +});