mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2025-08-02 13:11:58 -07:00
Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
de79be2db2 | ||
|
416b69bae5 | ||
|
3e78fce3a3 | ||
|
7a3fd1f23f | ||
|
d306403440 | ||
|
ebabe1df6a | ||
|
f27aa3ff6f | ||
|
20ccd441f2 | ||
|
104d740f76 | ||
|
2da0eab2b8 | ||
|
b8c7864a02 | ||
|
ec26995655 | ||
|
a41235a3b5 | ||
|
1a91b900e7 | ||
|
2b15832655 |
23
CHANGELOG.md
23
CHANGELOG.md
@@ -1,3 +1,26 @@
|
||||
0.2.1
|
||||
=====
|
||||
Feature enhancements:
|
||||
|
||||
* Added or improved file type filtering for Clojure and SystemVerilog.
|
||||
* [FEATURE #89](https://github.com/BurntSushi/ripgrep/issues/89):
|
||||
Add a --null flag that outputs a NUL byte after every file path.
|
||||
|
||||
Bug fixes:
|
||||
|
||||
* [BUG #98](https://github.com/BurntSushi/ripgrep/issues/98):
|
||||
Fix a bug in single threaded mode when if opening a file failed, ripgrep
|
||||
quit instead of continuing the search.
|
||||
* [BUG #99](https://github.com/BurntSushi/ripgrep/issues/99):
|
||||
Fix another bug in single threaded mode where empty lines were being printed
|
||||
by mistake.
|
||||
* [BUG #105](https://github.com/BurntSushi/ripgrep/issues/105):
|
||||
Fix an off-by-one error with --column.
|
||||
* [BUG #106](https://github.com/BurntSushi/ripgrep/issues/106):
|
||||
Fix a bug where a whitespace only line in a gitignore file caused ripgrep
|
||||
to panic (i.e., crash).
|
||||
|
||||
|
||||
0.2.0
|
||||
=====
|
||||
Feature enhancements:
|
||||
|
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -1,6 +1,6 @@
|
||||
[root]
|
||||
name = "ripgrep"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"docopt 0.6.85 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ripgrep"
|
||||
version = "0.2.0" #:version
|
||||
version = "0.2.1" #:version
|
||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||
description = """
|
||||
Line oriented search tool using Rust's regex library. Combines the raw
|
||||
|
8
doc/rg.1
8
doc/rg.1
@@ -239,6 +239,14 @@ Note that .ignore files will continue to be respected.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
.B \-\-null
|
||||
Whenever a file name is printed, follow it with a NUL byte.
|
||||
This includes printing filenames before matches, and when printing a
|
||||
list of matching files such as with \-\-count, \-\-files\-with\-matches
|
||||
and \-\-files.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
.B \-p, \-\-pretty
|
||||
Alias for \-\-color=always \-\-heading \-n.
|
||||
.RS
|
||||
|
@@ -155,6 +155,12 @@ the raw speed of grep.
|
||||
: Don't respect version control ignore files (e.g., .gitignore).
|
||||
Note that .ignore files will continue to be respected.
|
||||
|
||||
--null
|
||||
: Whenever a file name is printed, follow it with a NUL byte.
|
||||
This includes printing filenames before matches, and when printing
|
||||
a list of matching files such as with --count, --files-with-matches
|
||||
and --files.
|
||||
|
||||
-p, --pretty
|
||||
: Alias for --color=always --heading -n.
|
||||
|
||||
|
@@ -1,15 +1,15 @@
|
||||
require 'formula'
|
||||
class Ripgrep < Formula
|
||||
version '0.1.17'
|
||||
version '0.2.0'
|
||||
desc "Search tool like grep and The Silver Searcher."
|
||||
homepage "https://github.com/BurntSushi/ripgrep"
|
||||
|
||||
if Hardware::CPU.is_64_bit?
|
||||
url "https://github.com/BurntSushi/ripgrep/releases/download/#{version}/ripgrep-#{version}-x86_64-apple-darwin.tar.gz"
|
||||
sha256 "cb7b551a08849cef6ef8f17229224f094299692981976a3c5873c93f68c8fa1a"
|
||||
sha256 "f55ef5dac04178bcae0d6c5ba2d09690d326e8c7c3f28e561025b04e1ab81d80"
|
||||
else
|
||||
url "https://github.com/BurntSushi/ripgrep/releases/download/#{version}/ripgrep-#{version}-i686-apple-darwin.tar.gz"
|
||||
sha256 "0e936874b9f3fd661c5566e7f8fe18343baa5e9371e57d8d71000e9234fc376b"
|
||||
sha256 "d901d55ccb48c19067f563d42652dfd8642bf50d28a40c0e2a4d3e866857a93b"
|
||||
end
|
||||
|
||||
def install
|
||||
|
33
src/args.rs
33
src/args.rs
@@ -155,6 +155,12 @@ Less common options:
|
||||
Don't respect version control ignore files (e.g., .gitignore).
|
||||
Note that .ignore files will continue to be respected.
|
||||
|
||||
--null
|
||||
Whenever a file name is printed, follow it with a NUL byte.
|
||||
This includes printing filenames before matches, and when printing
|
||||
a list of matching files such as with --count, --files-with-matches
|
||||
and --files.
|
||||
|
||||
-p, --pretty
|
||||
Alias for --color=always --heading -n.
|
||||
|
||||
@@ -224,6 +230,7 @@ pub struct RawArgs {
|
||||
flag_no_line_number: bool,
|
||||
flag_no_mmap: bool,
|
||||
flag_no_filename: bool,
|
||||
flag_null: bool,
|
||||
flag_pretty: bool,
|
||||
flag_quiet: bool,
|
||||
flag_regexp: Vec<String>,
|
||||
@@ -269,6 +276,7 @@ pub struct Args {
|
||||
no_ignore: bool,
|
||||
no_ignore_parent: bool,
|
||||
no_ignore_vcs: bool,
|
||||
null: bool,
|
||||
quiet: bool,
|
||||
replace: Option<Vec<u8>>,
|
||||
text: bool,
|
||||
@@ -399,6 +407,7 @@ impl RawArgs {
|
||||
no_ignore_vcs:
|
||||
// --no-ignore implies --no-ignore-vcs
|
||||
self.flag_no_ignore_vcs || no_ignore,
|
||||
null: self.flag_null,
|
||||
quiet: self.flag_quiet,
|
||||
replace: self.flag_replace.clone().map(|s| s.into_bytes()),
|
||||
text: text,
|
||||
@@ -553,6 +562,7 @@ impl Args {
|
||||
.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 {
|
||||
p = p.replace(rep.clone());
|
||||
@@ -673,15 +683,20 @@ impl Args {
|
||||
pub fn walker(&self, path: &Path) -> Result<walk::Iter> {
|
||||
let wd = WalkDir::new(path).follow_links(self.follow);
|
||||
let mut ig = Ignore::new();
|
||||
ig.ignore_hidden(!self.hidden);
|
||||
ig.no_ignore(self.no_ignore);
|
||||
ig.no_ignore_vcs(self.no_ignore_vcs);
|
||||
ig.add_types(self.types.clone());
|
||||
if !self.no_ignore_parent {
|
||||
try!(ig.push_parents(path));
|
||||
}
|
||||
if let Some(ref overrides) = self.glob_overrides {
|
||||
ig.add_override(overrides.clone());
|
||||
// Only register ignore rules if this is a directory. If it's a file,
|
||||
// then it was explicitly given by the end user, so we always search
|
||||
// it.
|
||||
if path.is_dir() {
|
||||
ig.ignore_hidden(!self.hidden);
|
||||
ig.no_ignore(self.no_ignore);
|
||||
ig.no_ignore_vcs(self.no_ignore_vcs);
|
||||
ig.add_types(self.types.clone());
|
||||
if !self.no_ignore_parent {
|
||||
try!(ig.push_parents(path));
|
||||
}
|
||||
if let Some(ref overrides) = self.glob_overrides {
|
||||
ig.add_override(overrides.clone());
|
||||
}
|
||||
}
|
||||
Ok(walk::Iter::new(ig, wd))
|
||||
}
|
||||
|
@@ -283,12 +283,15 @@ impl GitignoreBuilder {
|
||||
from: P,
|
||||
mut line: &str,
|
||||
) -> Result<(), Error> {
|
||||
if line.is_empty() || line.starts_with("#") {
|
||||
if line.starts_with("#") {
|
||||
return Ok(());
|
||||
}
|
||||
if !line.ends_with("\\ ") {
|
||||
line = line.trim_right();
|
||||
}
|
||||
if line.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
let mut pat = Pattern {
|
||||
from: from.as_ref().to_path_buf(),
|
||||
original: line.to_string(),
|
||||
@@ -426,4 +429,10 @@ mod tests {
|
||||
not_ignored!(ignot11, ROOT, "#foo", "#foo");
|
||||
not_ignored!(ignot12, ROOT, "\n\n\n", "foo");
|
||||
not_ignored!(ignot13, ROOT, "foo/**", "foo", true);
|
||||
|
||||
// See: https://github.com/BurntSushi/ripgrep/issues/106
|
||||
#[test]
|
||||
fn regression_106() {
|
||||
Gitignore::from_str("/", " ").unwrap();
|
||||
}
|
||||
}
|
||||
|
73
src/main.rs
73
src/main.rs
@@ -22,8 +22,8 @@ extern crate winapi;
|
||||
|
||||
use std::error::Error;
|
||||
use std::fs::File;
|
||||
use std::io::{self, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
use std::process;
|
||||
use std::result;
|
||||
use std::sync::{Arc, Mutex};
|
||||
@@ -89,16 +89,15 @@ fn run(args: Args) -> Result<u64> {
|
||||
let args = Arc::new(args);
|
||||
let paths = args.paths();
|
||||
let threads = cmp::max(1, args.threads() - 1);
|
||||
let isone =
|
||||
paths.len() == 1 && (paths[0] == Path::new("-") || paths[0].is_file());
|
||||
if args.files() {
|
||||
return run_files(args.clone());
|
||||
}
|
||||
if args.type_list() {
|
||||
return run_types(args.clone());
|
||||
}
|
||||
if paths.len() == 1 && (paths[0] == Path::new("-") || paths[0].is_file()) {
|
||||
return run_one(args.clone(), &paths[0]);
|
||||
}
|
||||
if threads == 1 {
|
||||
if threads == 1 || isone {
|
||||
return run_one_thread(args.clone());
|
||||
}
|
||||
|
||||
@@ -158,32 +157,35 @@ fn run_one_thread(args: Arc<Args>) -> Result<u64> {
|
||||
match_count: 0,
|
||||
};
|
||||
let paths = args.paths();
|
||||
let filesep = args.file_separator();
|
||||
let mut term = args.stdout();
|
||||
|
||||
let mut paths_searched: u64 = 0;
|
||||
for p in paths {
|
||||
if p == Path::new("-") {
|
||||
if worker.match_count > 0 {
|
||||
if let Some(ref sep) = filesep {
|
||||
let _ = term.write_all(sep);
|
||||
let _ = term.write_all(b"\n");
|
||||
}
|
||||
}
|
||||
paths_searched += 1;
|
||||
let mut printer = args.printer(&mut term);
|
||||
if worker.match_count > 0 {
|
||||
if let Some(sep) = args.file_separator() {
|
||||
printer = printer.file_separator(sep);
|
||||
}
|
||||
}
|
||||
worker.do_work(&mut printer, WorkReady::Stdin);
|
||||
} else {
|
||||
for ent in try!(args.walker(p)) {
|
||||
if worker.match_count > 0 {
|
||||
if let Some(ref sep) = filesep {
|
||||
let _ = term.write_all(sep);
|
||||
let _ = term.write_all(b"\n");
|
||||
}
|
||||
}
|
||||
paths_searched += 1;
|
||||
let mut printer = args.printer(&mut term);
|
||||
let file = try!(File::open(ent.path()));
|
||||
if worker.match_count > 0 {
|
||||
if let Some(sep) = args.file_separator() {
|
||||
printer = printer.file_separator(sep);
|
||||
}
|
||||
}
|
||||
let file = match File::open(ent.path()) {
|
||||
Ok(file) => file,
|
||||
Err(err) => {
|
||||
eprintln!("{}: {}", ent.path().display(), err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
worker.do_work(&mut printer, WorkReady::DirFile(ent, file));
|
||||
}
|
||||
}
|
||||
@@ -196,25 +198,6 @@ fn run_one_thread(args: Arc<Args>) -> Result<u64> {
|
||||
Ok(worker.match_count)
|
||||
}
|
||||
|
||||
fn run_one(args: Arc<Args>, path: &Path) -> Result<u64> {
|
||||
let mut worker = Worker {
|
||||
args: args.clone(),
|
||||
inpbuf: args.input_buffer(),
|
||||
grep: args.grep(),
|
||||
match_count: 0,
|
||||
};
|
||||
let term = args.stdout();
|
||||
let mut printer = args.printer(term);
|
||||
let work =
|
||||
if path == Path::new("-") {
|
||||
WorkReady::Stdin
|
||||
} else {
|
||||
WorkReady::PathFile(path.to_path_buf(), try!(File::open(path)))
|
||||
};
|
||||
worker.do_work(&mut printer, work);
|
||||
Ok(worker.match_count)
|
||||
}
|
||||
|
||||
fn run_files(args: Arc<Args>) -> Result<u64> {
|
||||
let term = args.stdout();
|
||||
let mut printer = args.printer(term);
|
||||
@@ -253,7 +236,6 @@ enum Work {
|
||||
enum WorkReady {
|
||||
Stdin,
|
||||
DirFile(DirEntry, File),
|
||||
PathFile(PathBuf, File),
|
||||
}
|
||||
|
||||
struct MultiWorker {
|
||||
@@ -328,17 +310,6 @@ impl Worker {
|
||||
self.search(printer, path, file)
|
||||
}
|
||||
}
|
||||
WorkReady::PathFile(path, file) => {
|
||||
let mut path = &*path;
|
||||
if let Some(p) = strip_prefix("./", path) {
|
||||
path = p;
|
||||
}
|
||||
if self.args.mmap() {
|
||||
self.search_mmap(printer, path, &file)
|
||||
} else {
|
||||
self.search(printer, path, file)
|
||||
}
|
||||
}
|
||||
};
|
||||
match result {
|
||||
Ok(count) => {
|
||||
|
@@ -48,8 +48,6 @@ impl Out {
|
||||
|
||||
/// If set, the separator is printed between matches from different files.
|
||||
/// By default, no separator is printed.
|
||||
///
|
||||
/// If sep is empty, then no file separator is printed.
|
||||
pub fn file_separator(mut self, sep: Vec<u8>) -> Out {
|
||||
self.file_separator = Some(sep);
|
||||
self
|
||||
|
@@ -25,6 +25,8 @@ pub struct Printer<W> {
|
||||
/// printed via the match directly, but occasionally we need to insert them
|
||||
/// ourselves (for example, to print a context separator).
|
||||
eol: u8,
|
||||
/// A file separator to show before any matches are printed.
|
||||
file_separator: Option<Vec<u8>>,
|
||||
/// Whether to show file name as a heading or not.
|
||||
///
|
||||
/// N.B. If with_filename is false, then this setting has no effect.
|
||||
@@ -33,6 +35,9 @@ pub struct Printer<W> {
|
||||
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,
|
||||
/// A string to use as a replacement of each match in a matching line.
|
||||
replace: Option<Vec<u8>>,
|
||||
/// Whether to prefix each match with the corresponding file name.
|
||||
@@ -48,9 +53,11 @@ impl<W: Terminal + Send> Printer<W> {
|
||||
column: false,
|
||||
context_separator: "--".to_string().into_bytes(),
|
||||
eol: b'\n',
|
||||
file_separator: None,
|
||||
heading: false,
|
||||
line_per_match: false,
|
||||
quiet: false,
|
||||
null: false,
|
||||
replace: None,
|
||||
with_filename: false,
|
||||
}
|
||||
@@ -75,6 +82,13 @@ impl<W: Terminal + Send> Printer<W> {
|
||||
self
|
||||
}
|
||||
|
||||
/// If set, the separator is printed before any matches. By default, no
|
||||
/// separator is printed.
|
||||
pub fn file_separator(mut self, sep: Vec<u8>) -> Printer<W> {
|
||||
self.file_separator = Some(sep);
|
||||
self
|
||||
}
|
||||
|
||||
/// Whether to show file name as a heading or not.
|
||||
///
|
||||
/// N.B. If with_filename is false, then this setting has no effect.
|
||||
@@ -89,6 +103,13 @@ impl<W: Terminal + Send> Printer<W> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Whether to cause NUL bytes to follow file paths instead of other
|
||||
/// visual separators (like `:`, `-` and `\n`).
|
||||
pub fn null(mut self, yes: bool) -> Printer<W> {
|
||||
self.null = yes;
|
||||
self
|
||||
}
|
||||
|
||||
/// When set, all output is suppressed.
|
||||
pub fn quiet(mut self, yes: bool) -> Printer<W> {
|
||||
self.quiet = yes;
|
||||
@@ -146,14 +167,22 @@ impl<W: Terminal + Send> Printer<W> {
|
||||
pub fn path<P: AsRef<Path>>(&mut self, path: P) {
|
||||
let path = strip_prefix("./", path.as_ref()).unwrap_or(path.as_ref());
|
||||
self.write_path(path);
|
||||
self.write_eol();
|
||||
if self.null {
|
||||
self.write(b"\x00");
|
||||
} else {
|
||||
self.write_eol();
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints the given path and a count of the number of matches found.
|
||||
pub fn path_count<P: AsRef<Path>>(&mut self, path: P, count: u64) {
|
||||
if self.with_filename {
|
||||
self.write_path(path);
|
||||
self.write(b":");
|
||||
if self.null {
|
||||
self.write(b"\x00");
|
||||
} else {
|
||||
self.write(b":");
|
||||
}
|
||||
}
|
||||
self.write(count.to_string().as_bytes());
|
||||
self.write_eol();
|
||||
@@ -186,7 +215,7 @@ impl<W: Terminal + Send> Printer<W> {
|
||||
let column =
|
||||
if self.column {
|
||||
Some(re.find(&buf[start..end])
|
||||
.map(|(s, _)| s + 1).unwrap_or(0) as u64)
|
||||
.map(|(s, _)| s).unwrap_or(0) as u64)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -211,10 +240,15 @@ impl<W: Terminal + Send> Printer<W> {
|
||||
column: Option<u64>,
|
||||
) {
|
||||
if self.heading && self.with_filename && !self.has_printed {
|
||||
self.write_file_sep();
|
||||
self.write_heading(path.as_ref());
|
||||
} else if !self.heading && self.with_filename {
|
||||
self.write_path(path.as_ref());
|
||||
self.write(b":");
|
||||
if self.null {
|
||||
self.write(b"\x00");
|
||||
} else {
|
||||
self.write(b":");
|
||||
}
|
||||
}
|
||||
if let Some(line_number) = line_number {
|
||||
self.line_number(line_number, b':');
|
||||
@@ -261,10 +295,15 @@ impl<W: Terminal + Send> Printer<W> {
|
||||
line_number: Option<u64>,
|
||||
) {
|
||||
if self.heading && self.with_filename && !self.has_printed {
|
||||
self.write_file_sep();
|
||||
self.write_heading(path.as_ref());
|
||||
} else if !self.heading && self.with_filename {
|
||||
self.write_path(path.as_ref());
|
||||
self.write(b"-");
|
||||
if self.null {
|
||||
self.write(b"\x00");
|
||||
} else {
|
||||
self.write(b"-");
|
||||
}
|
||||
}
|
||||
if let Some(line_number) = line_number {
|
||||
self.line_number(line_number, b'-');
|
||||
@@ -281,7 +320,11 @@ impl<W: Terminal + Send> Printer<W> {
|
||||
let _ = self.wtr.attr(Attr::Bold);
|
||||
}
|
||||
self.write_path(path.as_ref());
|
||||
self.write_eol();
|
||||
if self.null {
|
||||
self.write(b"\x00");
|
||||
} else {
|
||||
self.write_eol();
|
||||
}
|
||||
if self.wtr.supports_color() {
|
||||
let _ = self.wtr.reset();
|
||||
}
|
||||
@@ -324,4 +367,15 @@ impl<W: Terminal + Send> Printer<W> {
|
||||
let eol = self.eol;
|
||||
self.write(&[eol]);
|
||||
}
|
||||
|
||||
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);
|
||||
let _ = self.wtr.write_all(b"\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@ const TYPE_EXTENSIONS: &'static [(&'static str, &'static [&'static str])] = &[
|
||||
("awk", &["*.awk"]),
|
||||
("c", &["*.c", "*.h", "*.H"]),
|
||||
("cbor", &["*.cbor"]),
|
||||
("clojure", &["*.clj", "*.cljs"]),
|
||||
("clojure", &["*.clj", "*.cljc", "*.cljs", "*.cljx"]),
|
||||
("cmake", &["CMakeLists.txt"]),
|
||||
("coffeescript", &["*.coffee"]),
|
||||
("cpp", &[
|
||||
@@ -70,6 +70,7 @@ const TYPE_EXTENSIONS: &'static [(&'static str, &'static [&'static str])] = &[
|
||||
("scala", &["*.scala"]),
|
||||
("sh", &["*.bash", "*.csh", "*.ksh", "*.sh", "*.tcsh"]),
|
||||
("sql", &["*.sql"]),
|
||||
("sv", &["*.v", "*.vg", "*.sv", "*.svh", "*.h"]),
|
||||
("swift", &["*.swift"]),
|
||||
("tex", &["*.tex", "*.cls", "*.sty"]),
|
||||
("ts", &["*.ts", "*.tsx"]),
|
||||
|
@@ -54,6 +54,13 @@ fn path(unix: &str) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
fn sort_lines(lines: &str) -> String {
|
||||
let mut lines: Vec<String> =
|
||||
lines.trim().lines().map(|s| s.to_owned()).collect();
|
||||
lines.sort();
|
||||
format!("{}\n", lines.join("\n"))
|
||||
}
|
||||
|
||||
sherlock!(single_file, |wd: WorkDir, mut cmd| {
|
||||
let lines: String = wd.stdout(&mut cmd);
|
||||
let expected = "\
|
||||
@@ -86,8 +93,8 @@ sherlock!(columns, |wd: WorkDir, mut cmd: Command| {
|
||||
cmd.arg("--column");
|
||||
let lines: String = wd.stdout(&mut cmd);
|
||||
let expected = "\
|
||||
58:For the Doctor Watsons of this world, as opposed to the Sherlock
|
||||
50:be, to a very large extent, the result of luck. Sherlock Holmes
|
||||
57:For the Doctor Watsons of this world, as opposed to the Sherlock
|
||||
49:be, to a very large extent, the result of luck. Sherlock Holmes
|
||||
";
|
||||
assert_eq!(lines, expected);
|
||||
});
|
||||
@@ -716,6 +723,36 @@ clean!(regression_93, r"(\d{1,3}\.){3}\d{1,3}", ".",
|
||||
assert_eq!(lines, "foo:192.168.1.1\n");
|
||||
});
|
||||
|
||||
// See: https://github.com/BurntSushi/ripgrep/issues/99
|
||||
clean!(regression_99, "test", ".",
|
||||
|wd: WorkDir, mut cmd: Command| {
|
||||
wd.create("foo1", "test");
|
||||
wd.create("foo2", "zzz");
|
||||
wd.create("bar", "test");
|
||||
cmd.arg("-j1").arg("--heading");
|
||||
|
||||
let lines: String = wd.stdout(&mut cmd);
|
||||
assert_eq!(sort_lines(&lines), sort_lines("bar\ntest\n\nfoo1\ntest\n"));
|
||||
});
|
||||
|
||||
// See: https://github.com/BurntSushi/ripgrep/issues/105
|
||||
clean!(regression_105_part1, "test", ".", |wd: WorkDir, mut cmd: Command| {
|
||||
wd.create("foo", "zztest");
|
||||
cmd.arg("--vimgrep");
|
||||
|
||||
let lines: String = wd.stdout(&mut cmd);
|
||||
assert_eq!(lines, "foo:1:3:zztest\n");
|
||||
});
|
||||
|
||||
// See: https://github.com/BurntSushi/ripgrep/issues/105
|
||||
clean!(regression_105_part2, "test", ".", |wd: WorkDir, mut cmd: Command| {
|
||||
wd.create("foo", "zztest");
|
||||
cmd.arg("--column");
|
||||
|
||||
let lines: String = wd.stdout(&mut cmd);
|
||||
assert_eq!(lines, "foo:3:zztest\n");
|
||||
});
|
||||
|
||||
// See: https://github.com/BurntSushi/ripgrep/issues/20
|
||||
sherlock!(feature_20, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
|
||||
cmd.arg("--no-filename");
|
||||
@@ -752,6 +789,48 @@ sherlock:be, to a very large extent, the result of luck. Sherlock Holmes
|
||||
assert_eq!(lines, expected);
|
||||
});
|
||||
|
||||
// See: https://github.com/BurntSushi/ripgrep/issues/89
|
||||
sherlock!(feature_89_files_with_matches, "Sherlock", ".",
|
||||
|wd: WorkDir, mut cmd: Command| {
|
||||
cmd.arg("--null").arg("--files-with-matches");
|
||||
|
||||
let lines: String = wd.stdout(&mut cmd);
|
||||
assert_eq!(lines, "sherlock\x00");
|
||||
});
|
||||
|
||||
// See: https://github.com/BurntSushi/ripgrep/issues/89
|
||||
sherlock!(feature_89_count, "Sherlock", ".",
|
||||
|wd: WorkDir, mut cmd: Command| {
|
||||
cmd.arg("--null").arg("--count");
|
||||
|
||||
let lines: String = wd.stdout(&mut cmd);
|
||||
assert_eq!(lines, "sherlock\x002\n");
|
||||
});
|
||||
|
||||
// See: https://github.com/BurntSushi/ripgrep/issues/89
|
||||
sherlock!(feature_89_files, "NADA", ".",
|
||||
|wd: WorkDir, mut cmd: Command| {
|
||||
cmd.arg("--null").arg("--files");
|
||||
|
||||
let lines: String = wd.stdout(&mut cmd);
|
||||
assert_eq!(lines, "sherlock\x00");
|
||||
});
|
||||
|
||||
// See: https://github.com/BurntSushi/ripgrep/issues/89
|
||||
sherlock!(feature_89_match, "Sherlock", ".",
|
||||
|wd: WorkDir, mut cmd: Command| {
|
||||
cmd.arg("--null").arg("-C1");
|
||||
|
||||
let lines: String = wd.stdout(&mut cmd);
|
||||
let expected = "\
|
||||
sherlock\x00For the Doctor Watsons of this world, as opposed to the Sherlock
|
||||
sherlock\x00Holmeses, success in the province of detective work must always
|
||||
sherlock\x00be, to a very large extent, the result of luck. Sherlock Holmes
|
||||
sherlock\x00can extract a clew from a wisp of straw or a flake of cigar ash;
|
||||
";
|
||||
assert_eq!(lines, expected);
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn binary_nosearch() {
|
||||
let wd = WorkDir::new("binary_nosearch");
|
||||
|
Reference in New Issue
Block a user