1
0
mirror of https://github.com/BurntSushi/ripgrep.git synced 2024-12-02 02:56:32 +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,23 +65,30 @@ xrep is like the silver searcher and grep, but faster than both.
WARNING: Searching stdin isn't yet supported.
Options:
-c, --count Suppress normal output and show count of line matches.
--debug Show debug messages.
--files Print each file that would be searched
(but don't search).
--hidden Search hidden directories and files.
-i, --ignore-case Case insensitive search.
-L, --follow Follow symlinks.
-n, --line-number Show line numbers (1-based).
-t, --threads ARG The number of threads to use. Defaults to the number
of logical CPUs. [default: 0]
-v, --invert-match Invert matching.
-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.
--files Print each file that would be searched
(but don't search).
--hidden Search hidden directories and files.
-i, --ignore-case Case insensitive search.
-L, --follow Follow symlinks.
-n, --line-number Show line numbers (1-based).
-t, --threads ARG The number of threads to use. Defaults to the
number of logical CPUs. [default: 0]
-v, --invert-match Invert matching.
";
#[derive(RustcDecodable)]
struct Args {
arg_pattern: String,
arg_path: Vec<String>,
flag_after_context: usize,
flag_before_context: usize,
flag_context: usize,
flag_count: bool,
flag_debug: bool,
flag_files: bool,
@ -238,6 +245,8 @@ impl Worker {
searcher = searcher.count(self.args.flag_count);
searcher = searcher.line_number(self.args.flag_line_number);
searcher = searcher.invert_match(self.args.flag_invert_match);
searcher = searcher.before_context(
self.args.flag_before_context);
if let Err(err) = searcher.run() {
eprintln!("{}", err);
}

View File

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

View File

@ -66,7 +66,7 @@ pub struct Searcher<'a, R, W: 'a> {
match_count: u64,
line_count: Option<u64>,
last_match: Match,
last_printed: (usize, usize),
last_printed: Option<(usize, usize)>,
after_context_remaining: usize,
count: bool,
invert_match: bool,
@ -104,7 +104,7 @@ impl<'a, R: io::Read, W: io::Write> Searcher<'a, R, W> {
match_count: 0,
line_count: None,
last_match: Match::default(),
last_printed: (0, 0),
last_printed: None,
after_context_remaining: 0,
count: 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.line_count = if self.line_number { Some(0) } else { None };
self.last_match = Match::default();
self.last_printed = (0, 0);
self.last_printed = None;
self.after_context_remaining = 0;
loop {
let mut keep_from = self.inp.lastnl;
if self.before_context > 0 {
let start_of_keep = cmp::min(
self.inp.lastnl, self.last_printed.1 + 2);
keep_from = start_of_previous_lines(
self.inp.lastnl,
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.lastnl - start_of_keep,
(self.inp.lastnl - start_of_keep).saturating_sub(1),
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| {
Error::from_io(err, &self.path)
@ -176,6 +183,7 @@ impl<'a, R: io::Read, W: io::Write> Searcher<'a, R, W> {
if !ok {
break;
}
self.last_printed = None;
while self.inp.pos < self.inp.lastnl {
let ok = self.grep.read_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;
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 {
let inverted_upto = self.last_match.start();
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);
let start = self.last_match.start();
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);
}
// 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) {
self.printer.matched(
&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;
}
#[inline(always)]
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.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
}
fn show(bytes: &[u8]) -> &str {
::std::str::from_utf8(bytes).unwrap()
}
#[cfg(test)]
mod tests {
use std::io;
@ -757,9 +782,11 @@ and exhibited clearly, with a label attached.\
assert_eq!(out, "/baz.rs:4\n");
}
#[test]
fn before_context_one() {
let text = hay("\
macro_rules! before_context {
($name:ident, $query:expr, $num:expr, $expected:expr) => {
#[test]
fn $name() {
let text = hay("\
For the Doctor Watsons of this world, as opposed to the Sherlock
Holmeses, success in the province of detective work must always
be, to a very large extent, the result of luck. Sherlock Holmes
@ -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,
and exhibited clearly, with a label attached.\
");
let mut inp = InputBuffer::with_capacity(1);
let mut pp = Printer::new(vec![]);
let grep = matcher("Sherlock");
let count = {
let searcher = Searcher::new(
&mut inp, &mut pp, &grep, test_path(), text);
searcher.before_context(1).run().unwrap()
};
assert_eq!(2, count);
let out = String::from_utf8(pp.into_inner()).unwrap();
assert_eq!(out, "\
let mut inp = InputBuffer::with_capacity(4096);
let mut pp = Printer::new(vec![]);
let grep = matcher($query);
let count = {
let searcher = Searcher::new(
&mut inp, &mut pp, &grep, test_path(), text);
searcher.before_context($num).run().unwrap()
};
let out = String::from_utf8(pp.into_inner()).unwrap();
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-Holmeses, success in the province of detective work must always
/baz.rs:be, to a very large extent, the result of luck. Sherlock Holmes
");
}
}