1
0
mirror of https://github.com/BurntSushi/ripgrep.git synced 2025-04-19 09:02:15 +02:00

Make "before" context work.

No line numbers. And match inverting is broken.

This is awful.
This commit is contained in:
Andrew Gallant 2016-09-01 21:56:23 -04:00
parent 5aa3b9bc58
commit 5450aed9a8
4 changed files with 125 additions and 44 deletions

4
compile Executable file
View File

@ -0,0 +1,4 @@
#!/bin/sh
export RUSTFLAGS="-C target-feature=+ssse3"
cargo build --release --features simd-accel

View File

@ -65,7 +65,11 @@ xrep is like the silver searcher and grep, but faster than both.
WARNING: Searching stdin isn't yet supported. WARNING: Searching stdin isn't yet supported.
Options: Options:
-c, --count Suppress normal output and show count of line matches. -c, --count Suppress normal output and show count of line
matches.
-A, --after-context NUM Show NUM lines after each match.
-B, --before-context NUM Show NUM lines before each match.
-C, --context NUM Show NUM lines before and after each match.
--debug Show debug messages. --debug Show debug messages.
--files Print each file that would be searched --files Print each file that would be searched
(but don't search). (but don't search).
@ -73,8 +77,8 @@ Options:
-i, --ignore-case Case insensitive search. -i, --ignore-case Case insensitive search.
-L, --follow Follow symlinks. -L, --follow Follow symlinks.
-n, --line-number Show line numbers (1-based). -n, --line-number Show line numbers (1-based).
-t, --threads ARG The number of threads to use. Defaults to the number -t, --threads ARG The number of threads to use. Defaults to the
of logical CPUs. [default: 0] number of logical CPUs. [default: 0]
-v, --invert-match Invert matching. -v, --invert-match Invert matching.
"; ";
@ -82,6 +86,9 @@ Options:
struct Args { struct Args {
arg_pattern: String, arg_pattern: String,
arg_path: Vec<String>, arg_path: Vec<String>,
flag_after_context: usize,
flag_before_context: usize,
flag_context: usize,
flag_count: bool, flag_count: bool,
flag_debug: bool, flag_debug: bool,
flag_files: bool, flag_files: bool,
@ -238,6 +245,8 @@ impl Worker {
searcher = searcher.count(self.args.flag_count); searcher = searcher.count(self.args.flag_count);
searcher = searcher.line_number(self.args.flag_line_number); searcher = searcher.line_number(self.args.flag_line_number);
searcher = searcher.invert_match(self.args.flag_invert_match); searcher = searcher.invert_match(self.args.flag_invert_match);
searcher = searcher.before_context(
self.args.flag_before_context);
if let Err(err) = searcher.run() { if let Err(err) = searcher.run() {
eprintln!("{}", err); eprintln!("{}", err);
} }

View File

@ -15,15 +15,21 @@ macro_rules! w {
pub struct Printer<W> { pub struct Printer<W> {
wtr: W, wtr: W,
has_printed: bool,
} }
impl<W: io::Write> Printer<W> { impl<W: io::Write> Printer<W> {
pub fn new(wtr: W) -> Printer<W> { pub fn new(wtr: W) -> Printer<W> {
Printer { Printer {
wtr: wtr, wtr: wtr,
has_printed: false,
} }
} }
pub fn has_printed(&self) -> bool {
self.has_printed
}
pub fn into_inner(self) -> W { pub fn into_inner(self) -> W {
self.wtr self.wtr
} }
@ -40,6 +46,10 @@ impl<W: io::Write> Printer<W> {
wln!(&mut self.wtr, "{}", count); wln!(&mut self.wtr, "{}", count);
} }
pub fn context_separator(&mut self) {
wln!(&mut self.wtr, "--");
}
pub fn matched<P: AsRef<Path>>( pub fn matched<P: AsRef<Path>>(
&mut self, &mut self,
path: P, path: P,
@ -81,6 +91,7 @@ impl<W: io::Write> Printer<W> {
} }
fn write(&mut self, buf: &[u8]) { fn write(&mut self, buf: &[u8]) {
self.has_printed = true;
let _ = self.wtr.write_all(buf); let _ = self.wtr.write_all(buf);
} }
} }

View File

@ -66,7 +66,7 @@ pub struct Searcher<'a, R, W: 'a> {
match_count: u64, match_count: u64,
line_count: Option<u64>, line_count: Option<u64>,
last_match: Match, last_match: Match,
last_printed: (usize, usize), last_printed: Option<(usize, usize)>,
after_context_remaining: usize, after_context_remaining: usize,
count: bool, count: bool,
invert_match: bool, invert_match: bool,
@ -104,7 +104,7 @@ impl<'a, R: io::Read, W: io::Write> Searcher<'a, R, W> {
match_count: 0, match_count: 0,
line_count: None, line_count: None,
last_match: Match::default(), last_match: Match::default(),
last_printed: (0, 0), last_printed: None,
after_context_remaining: 0, after_context_remaining: 0,
count: false, count: false,
invert_match: false, invert_match: false,
@ -158,17 +158,24 @@ impl<'a, R: io::Read, W: io::Write> Searcher<'a, R, W> {
self.match_count = 0; self.match_count = 0;
self.line_count = if self.line_number { Some(0) } else { None }; self.line_count = if self.line_number { Some(0) } else { None };
self.last_match = Match::default(); self.last_match = Match::default();
self.last_printed = (0, 0); self.last_printed = None;
self.after_context_remaining = 0; self.after_context_remaining = 0;
loop { loop {
let mut keep_from = self.inp.lastnl; let mut keep_from = self.inp.lastnl;
if self.before_context > 0 { if self.before_context > 0 {
let start_of_keep = cmp::min( let start_of_keep = cmp::min(
self.inp.lastnl, self.last_printed.1 + 2); self.inp.lastnl,
keep_from = start_of_previous_lines( self.last_printed.map(|(_, end)| end).unwrap_or(0));
keep_from = start_of_keep + start_of_previous_lines(
&self.inp.buf[start_of_keep..], &self.inp.buf[start_of_keep..],
self.inp.lastnl - start_of_keep, (self.inp.lastnl - start_of_keep).saturating_sub(1),
self.before_context); self.before_context);
// println!("start_of_keep: {}, lastnl: {}, last_printed: {:?}",
// start_of_keep, self.inp.lastnl, self.last_printed);
// println!("keep_from: {}", keep_from);
// println!(
// "KEEPING: {}",
// show(&self.inp.buf[keep_from..self.inp.lastnl]));
} }
let ok = try!(self.inp.fill(&mut self.haystack, keep_from).map_err(|err| { let ok = try!(self.inp.fill(&mut self.haystack, keep_from).map_err(|err| {
Error::from_io(err, &self.path) Error::from_io(err, &self.path)
@ -176,6 +183,7 @@ impl<'a, R: io::Read, W: io::Write> Searcher<'a, R, W> {
if !ok { if !ok {
break; break;
} }
self.last_printed = None;
while self.inp.pos < self.inp.lastnl { while self.inp.pos < self.inp.lastnl {
let ok = self.grep.read_match( let ok = self.grep.read_match(
&mut self.last_match, &mut self.last_match,
@ -191,6 +199,21 @@ impl<'a, R: io::Read, W: io::Write> Searcher<'a, R, W> {
self.inp.pos = upto; self.inp.pos = upto;
break; break;
} }
if self.before_context > 0 {
let start = self.last_printed.map(|(_, e)| e).unwrap_or(0);
let end = self.last_match.start().saturating_sub(1);
if end > start {
let before_context_start =
start + start_of_previous_lines(
&self.inp.buf[start..],
end - start,
self.before_context);
let mut it = IterLines::new(before_context_start);
while let Some((s, e)) = it.next(&self.inp.buf[..end]) {
self.print_context(s, e);
}
}
}
if self.invert_match { if self.invert_match {
let inverted_upto = self.last_match.start(); let inverted_upto = self.last_match.start();
self.find_inverted_matches(inverted_upto); self.find_inverted_matches(inverted_upto);
@ -208,16 +231,6 @@ impl<'a, R: io::Read, W: io::Write> Searcher<'a, R, W> {
self.count_lines(upto); self.count_lines(upto);
let start = self.last_match.start(); let start = self.last_match.start();
let end = self.last_match.end(); let end = self.last_match.end();
if self.before_context > 0 {
let start = start.saturating_sub(1);
let before_context_start = start_of_previous_lines(
&self.inp.buf, start, self.before_context);
let mut it = IterLines::new(before_context_start);
while let Some((s, e)) = it.next(&self.inp.buf[..start]) {
self.print_context(s, e);
}
}
self.print_match(start, end); self.print_match(start, end);
} }
// Move the position one past the end of the match so that // Move the position one past the end of the match so that
@ -260,15 +273,23 @@ impl<'a, R: io::Read, W: io::Write> Searcher<'a, R, W> {
fn print_match(&mut self, start: usize, end: usize) { fn print_match(&mut self, start: usize, end: usize) {
self.printer.matched( self.printer.matched(
&self.path, &self.inp.buf, start, end, self.line_count); &self.path, &self.inp.buf, start, end, self.line_count);
self.last_printed = (start, end); self.last_printed = Some((start, cmp::min(end + 1, self.inp.lastnl)));
self.after_context_remaining = self.after_context; self.after_context_remaining = self.after_context;
} }
#[inline(always)] #[inline(always)]
fn print_context(&mut self, start: usize, end: usize) { fn print_context(&mut self, start: usize, end: usize) {
// println!("has_printed: {}, last_printed: {:?}, this: {:?}",
// self.printer.has_printed(),
// self.last_printed,
// (start, end));
if self.printer.has_printed()
&& self.last_printed.map(|(_, end)| start > end).unwrap_or(true) {
self.printer.context_separator();
}
self.printer.context( self.printer.context(
&self.path, &self.inp.buf, start, end, self.line_count); &self.path, &self.inp.buf, start, end, self.line_count);
self.last_printed = (start, end); self.last_printed = Some((start, cmp::min(end + 1, self.inp.lastnl)));
} }
} }
@ -498,6 +519,10 @@ fn start_of_previous_lines(
end + 2 end + 2
} }
fn show(bytes: &[u8]) -> &str {
::std::str::from_utf8(bytes).unwrap()
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::io; use std::io;
@ -757,8 +782,10 @@ and exhibited clearly, with a label attached.\
assert_eq!(out, "/baz.rs:4\n"); assert_eq!(out, "/baz.rs:4\n");
} }
macro_rules! before_context {
($name:ident, $query:expr, $num:expr, $expected:expr) => {
#[test] #[test]
fn before_context_one() { fn $name() {
let text = hay("\ let text = hay("\
For the Doctor Watsons of this world, as opposed to the Sherlock For the Doctor Watsons of this world, as opposed to the Sherlock
Holmeses, success in the province of detective work must always Holmeses, success in the province of detective work must always
@ -767,20 +794,50 @@ can extract a clew from a wisp of straw or a flake of cigar ash;
but Doctor Watson has to have it taken out for him and dusted, but Doctor Watson has to have it taken out for him and dusted,
and exhibited clearly, with a label attached.\ and exhibited clearly, with a label attached.\
"); ");
let mut inp = InputBuffer::with_capacity(1); let mut inp = InputBuffer::with_capacity(4096);
let mut pp = Printer::new(vec![]); let mut pp = Printer::new(vec![]);
let grep = matcher("Sherlock"); let grep = matcher($query);
let count = { let count = {
let searcher = Searcher::new( let searcher = Searcher::new(
&mut inp, &mut pp, &grep, test_path(), text); &mut inp, &mut pp, &grep, test_path(), text);
searcher.before_context(1).run().unwrap() searcher.before_context($num).run().unwrap()
}; };
assert_eq!(2, count);
let out = String::from_utf8(pp.into_inner()).unwrap(); let out = String::from_utf8(pp.into_inner()).unwrap();
assert_eq!(out, "\ assert_eq!(out, $expected);
}
}
}
before_context!(before_context_one, "Sherlock", 1, "\
/baz.rs:For the Doctor Watsons of this world, as opposed to the Sherlock
/baz.rs-Holmeses, success in the province of detective work must always
/baz.rs:be, to a very large extent, the result of luck. Sherlock Holmes
");
before_context!(before_context_two1, "Sherlock", 2, "\
/baz.rs:For the Doctor Watsons of this world, as opposed to the Sherlock
/baz.rs-Holmeses, success in the province of detective work must always
/baz.rs:be, to a very large extent, the result of luck. Sherlock Holmes
");
before_context!(before_context_two2, "dusted", 2, "\
/baz.rs-be, to a very large extent, the result of luck. Sherlock Holmes
/baz.rs-can extract a clew from a wisp of straw or a flake of cigar ash;
/baz.rs:but Doctor Watson has to have it taken out for him and dusted,
");
before_context!(before_context_two3, "success|attached", 2, "\
/baz.rs-For the Doctor Watsons of this world, as opposed to the Sherlock
/baz.rs:Holmeses, success in the province of detective work must always
--
/baz.rs-can extract a clew from a wisp of straw or a flake of cigar ash;
/baz.rs-but Doctor Watson has to have it taken out for him and dusted,
/baz.rs:and exhibited clearly, with a label attached.
");
before_context!(before_context_three, "Sherlock", 3, "\
/baz.rs:For the Doctor Watsons of this world, as opposed to the Sherlock /baz.rs:For the Doctor Watsons of this world, as opposed to the Sherlock
/baz.rs-Holmeses, success in the province of detective work must always /baz.rs-Holmeses, success in the province of detective work must always
/baz.rs:be, to a very large extent, the result of luck. Sherlock Holmes /baz.rs:be, to a very large extent, the result of luck. Sherlock Holmes
"); ");
} }
}