summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml7
-rw-r--r--Cargo.lock78
-rw-r--r--Cargo.toml8
-rw-r--r--build.rs23
-rw-r--r--ci/before_deploy.sh1
-rw-r--r--doc/rg.125
-rw-r--r--doc/rg.1.md18
-rw-r--r--src/app.rs432
-rw-r--r--src/args.rs1038
-rw-r--r--src/main.rs23
-rw-r--r--src/search_stream.rs3
-rw-r--r--src/unescape.rs128
-rw-r--r--tests/tests.rs22
-rw-r--r--tests/workdir.rs23
14 files changed, 1173 insertions, 656 deletions
diff --git a/.travis.yml b/.travis.yml
index 85112278..cd7bd542 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -30,13 +30,10 @@ matrix:
env: TARGET=x86_64-apple-darwin
# Minimum Rust supported channel.
- os: linux
- rust: 1.9.0
- env: TARGET=x86_64-unknown-linux-musl
- - os: linux
- rust: 1.9.0
+ rust: 1.11.0
env: TARGET=x86_64-unknown-linux-gnu
- os: osx
- rust: 1.9.0
+ rust: 1.11.0
env: TARGET=x86_64-apple-darwin
before_install:
diff --git a/Cargo.lock b/Cargo.lock
index ecca3818..ada226fb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3,8 +3,8 @@ name = "ripgrep"
version = "0.2.9"
dependencies = [
"bytecount 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clap 2.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ctrlc 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "docopt 0.6.86 (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.5",
@@ -16,7 +16,6 @@ dependencies = [
"memmap 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -30,6 +29,16 @@ dependencies = [
]
[[package]]
+name = "ansi_term"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "bitflags"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "bytecount"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -38,6 +47,21 @@ dependencies = [
]
[[package]]
+name = "clap"
+version = "2.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "strsim 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "term_size 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-segmentation 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-width 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "crossbeam"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -53,17 +77,6 @@ dependencies = [
]
[[package]]
-name = "docopt"
-version = "0.6.86"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
- "strsim 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
name = "env_logger"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -194,11 +207,6 @@ version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "rustc-serialize"
-version = "0.3.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
name = "simd"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -218,6 +226,16 @@ dependencies = [
]
[[package]]
+name = "term_size"
+version = "0.2.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.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "thread-id"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -253,6 +271,16 @@ dependencies = [
]
[[package]]
+name = "unicode-segmentation"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "unreachable"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -266,6 +294,11 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "vec_map"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -291,10 +324,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
+"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
+"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
"checksum bytecount 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49e3c21915578e2300b08d3c174a8ac887e0c6421dff86fdc4d741dc29e5d413"
+"checksum clap 2.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "40046b8a004bf3ba43b9078bf4b9b6d1708406a234848f925dbd7160a374c8a8"
"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 docopt 0.6.86 (registry+https://github.com/rust-lang/crates.io-index)" = "4a7ef30445607f6fc8720f0a0a2c7442284b629cf0d049286860fae23e71c4d9"
"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"
@@ -307,16 +342,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum num_cpus 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8890e6084723d57d0df8d2720b0d60c6ee67d6c93e7169630e4371e88765dcad"
"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
-"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
"checksum simd 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "63b5847c2d766ca7ce7227672850955802fabd779ba616aeabead4c2c3877023"
"checksum strsim 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "50c069df92e4b01425a8bf3576d5d417943a6a7272fbabaf5bd80b1aaa76442e"
"checksum term 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3deff8a2b3b6607d6d7cc32ac25c0b33709453ca9cceac006caac51e963cf94a"
+"checksum term_size 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f7f5f3f71b0040cecc71af239414c23fd3c73570f5ff54cf50e03cef637f2a0"
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
"checksum thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a"
"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5"
"checksum thread_local 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50057ca52c629a39aed52d8eb253800cb727875fa6fc7c4b1445f0ac3b50c27c"
+"checksum unicode-segmentation 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b905d0fc2a1f0befd86b0e72e31d1787944efef9d38b9358a9e92a69757f7e3b"
+"checksum unicode-width 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2d6722facc10989f63ee0e20a83cd4e1714a9ae11529403ac7e0afd069abc39e"
"checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91"
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
+"checksum vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cac5efe5cb0fa14ec2f84f83c701c562ee63f6dcc680861b21d65c682adfb05f"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum walkdir 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "98da26f00240118fbb7a06fa29579d1b39d34cd6e0505ea5c125b26d5260a967"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
diff --git a/Cargo.toml b/Cargo.toml
index c4d787ec..afed8439 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,6 +13,7 @@ readme = "README.md"
keywords = ["regex", "grep", "egrep", "search", "pattern"]
license = "Unlicense/MIT"
exclude = ["HomebrewFormula"]
+build = "build.rs"
[[bin]]
bench = false
@@ -25,8 +26,8 @@ path = "tests/tests.rs"
[dependencies]
bytecount = "0.1.4"
+clap = "2.18"
ctrlc = "2.0"
-docopt = "0.6"
env_logger = "0.3"
grep = { version = "0.1.4", path = "grep" }
ignore = { version = "0.1.5", path = "ignore" }
@@ -37,13 +38,16 @@ memchr = "0.1"
memmap = "0.5"
num_cpus = "1"
regex = "0.1.77"
-rustc-serialize = "=0.3.19"
term = "0.4"
[target.'cfg(windows)'.dependencies]
kernel32-sys = "0.2"
winapi = "0.2"
+[build-dependencies]
+clap = "2.18"
+lazy_static = "0.2"
+
[features]
avx-accel = ["bytecount/avx-accel"]
simd-accel = ["bytecount/simd-accel", "regex/simd-accel"]
diff --git a/build.rs b/build.rs
new file mode 100644
index 00000000..b2522708
--- /dev/null
+++ b/build.rs
@@ -0,0 +1,23 @@
+#[macro_use]
+extern crate clap;
+#[macro_use]
+extern crate lazy_static;
+
+use std::fs;
+
+use clap::Shell;
+
+#[allow(dead_code)]
+#[path = "src/app.rs"]
+mod app;
+
+fn main() {
+ fs::create_dir_all(env!("OUT_DIR")).unwrap();
+
+ let mut app = app::app_short();
+ app.gen_completions("rg", Shell::Bash, env!("OUT_DIR"));
+ app.gen_completions("rg", Shell::Fish, env!("OUT_DIR"));
+ // Zsh seems to fail with a panic.
+ // app.gen_completions("rg", Shell::Zsh, env!("OUT_DIR"));
+ app.gen_completions("rg", Shell::PowerShell, env!("OUT_DIR"));
+}
diff --git a/ci/before_deploy.sh b/ci/before_deploy.sh
index 3d033d87..fedd5fcf 100644
--- a/ci/before_deploy.sh
+++ b/ci/before_deploy.sh
@@ -19,6 +19,7 @@ mk_tarball() {
cp target/$TARGET/release/rg "$td/$name/"
cp {doc/rg.1,README.md,UNLICENSE,COPYING,LICENSE-MIT} "$td/$name/"
+ cp target/$TARGET/release/build/ripgrep-*/out/{_rg.,rg.}* "$td/$name/"
pushd $td
tar czf "$out_dir/$name.tar.gz" *
diff --git a/doc/rg.1 b/doc/rg.1
index d1a59dc9..bc756317 100644
--- a/doc/rg.1
+++ b/doc/rg.1
@@ -7,11 +7,11 @@
rg \- recursively search current directory for lines matching a pattern
.SH SYNOPSIS
.PP
-rg [\f[I]options\f[]] \-e PATTERN ...
-[\f[I]<\f[]path\f[I]> ...\f[]]
-.PP
rg [\f[I]options\f[]] <\f[I]pattern\f[]> [\f[I]<\f[]path\f[I]> ...\f[]]
.PP
+rg [\f[I]options\f[]] (\-e PATTERN | \-f FILE) ...
+[\f[I]<\f[]path\f[I]> ...\f[]]
+.PP
rg [\f[I]options\f[]] \-\-files [\f[I]<\f[]path\f[I]> ...\f[]]
.PP
rg [\f[I]options\f[]] \-\-type\-list
@@ -163,6 +163,15 @@ Show debug messages.
.RS
.RE
.TP
+.B \-f, \-\-file FILE ...
+Search for patterns from the given file, with one pattern per line.
+When this flag is used or multiple times or in combination with the
+\-e/\-\-regexp flag, then all patterns provided are searched.
+Empty pattern lines will match all input lines, and the newline is not
+counted as part of the pattern.
+.RS
+.RE
+.TP
.B \-\-files
Print each file that would be searched (but don\[aq]t search).
.RS
@@ -202,6 +211,16 @@ Search hidden directories and files.
.RS
.RE
.TP
+.B \-\-ignore\-file FILE ...
+Specify additional ignore files for filtering file paths.
+Ignore files should be in the gitignore format and are matched relative
+to the current working directory.
+These ignore files have lower precedence than all other ignore files.
+When specifying multiple ignore files, earlier files have lower
+precedence than later files.
+.RS
+.RE
+.TP
.B \-L, \-\-follow
Follow symlinks.
.RS
diff --git a/doc/rg.1.md b/doc/rg.1.md
index bf850a98..a3d37667 100644
--- a/doc/rg.1.md
+++ b/doc/rg.1.md
@@ -4,10 +4,10 @@ rg - recursively search current directory for lines matching a pattern
# SYNOPSIS
-rg [*options*] -e PATTERN ... [*<*path*> ...*]
-
rg [*options*] <*pattern*> [*<*path*> ...*]
+rg [*options*] (-e PATTERN | -f FILE) ... [*<*path*> ...*]
+
rg [*options*] --files [*<*path*> ...*]
rg [*options*] --type-list
@@ -107,6 +107,12 @@ Project home page: https://github.com/BurntSushi/ripgrep
--debug
: Show debug messages.
+-f, --file FILE ...
+: Search for patterns from the given file, with one pattern per line. When this
+ flag is used or multiple times or in combination with the -e/--regexp flag,
+ then all patterns provided are searched. Empty pattern lines will match all
+ input lines, and the newline is not counted as part of the pattern.
+
--files
: Print each file that would be searched (but don't search).
@@ -132,6 +138,14 @@ Project home page: https://github.com/BurntSushi/ripgrep
: Search hidden directories and files. (Hidden directories and files are
skipped by default.)
+--ignore-file FILE ...
+: Specify additional ignore files for filtering file paths.
+ Ignore files should be in the gitignore format and are matched
+ relative to the current working directory. These ignore files
+ have lower precedence than all other ignore files. When
+ specifying multiple ignore files, earlier files have lower
+ precedence than later files.
+
-L, --follow
: Follow symlinks.
diff --git a/src/app.rs b/src/app.rs
new file mode 100644
index 00000000..5edaf999
--- /dev/null
+++ b/src/app.rs
@@ -0,0 +1,432 @@
+use std::collections::HashMap;
+
+use clap::{App, AppSettings, Arg};
+
+const ABOUT: &'static str = "
+ripgrep (rg) recursively searches your current directory for a regex pattern.
+
+Project home page: https://github.com/BurntSushi/ripgrep
+
+Use -h for short descriptions and --help for more details.";
+
+const USAGE: &'static str = "
+ rg [OPTIONS] <pattern> [<path> ...]
+ rg [OPTIONS] [-e PATTERN | -f FILE ]... [<path> ...]
+ rg [OPTIONS] --files [<path> ...]
+ rg [OPTIONS] --type-list";
+
+const TEMPLATE: &'static str = "\
+{bin} {version}
+{author}
+{about}
+
+USAGE:{usage}
+
+ARGS:
+{positionals}
+
+OPTIONS:
+{unified}";
+
+/// Build a clap application with short help strings.
+pub fn app_short() -> App<'static, 'static> {
+ app(false, |k| USAGES[k].short)
+}
+
+/// Build a clap application with long help strings.
+pub fn app_long() -> App<'static, 'static> {
+ app(true, |k| USAGES[k].long)
+}
+
+/// Build a clap application parameterized by usage strings.
+///
+/// The function given should take a clap argument name and return a help
+/// string. `app` will panic if a usage string is not defined.
+///
+/// This is an intentionally stand-alone module so that it can be used easily
+/// in a `build.rs` script to build shell completion files.
+fn app<F>(next_line_help: bool, doc: F) -> App<'static, 'static>
+ where F: Fn(&'static str) -> &'static str {
+ let arg = |name| {
+ Arg::with_name(name).help(doc(name)).next_line_help(next_line_help)
+ };
+ let flag = |name| arg(name).long(name);
+
+ App::new("ripgrep")
+ .author(crate_authors!())
+ .version(crate_version!())
+ .about(ABOUT)
+ .max_term_width(100)
+ .setting(AppSettings::UnifiedHelpMessage)
+ .usage(USAGE)
+ .template(TEMPLATE)
+ // Handle help/version manually to make their output formatting
+ // consistent with short/long views.
+ .arg(arg("help-short").short("h"))
+ .arg(flag("help"))
+ .arg(flag("version").short("V"))
+ // First, set up primary positional/flag arguments.
+ .arg(arg("pattern")
+ .required_unless_one(&[
+ "file", "files", "help-short", "help", "regexp", "type-list",
+ "version",
+ ]))
+ .arg(arg("path").multiple(true))
+ .arg(flag("regexp").short("e")
+ .takes_value(true).multiple(true).number_of_values(1)
+ .value_name("pattern"))
+ .arg(flag("files")
+ // This should also conflict with `pattern`, but the first file
+ // path will actually be in `pattern`.
+ .conflicts_with_all(&["file", "regexp", "type-list"]))
+ .arg(flag("type-list")
+ .conflicts_with_all(&["file", "files", "pattern", "regexp"]))
+ // Second, set up common flags.
+ .arg(flag("text").short("a"))
+ .arg(flag("count").short("c"))
+ .arg(flag("color")
+ .value_name("WHEN")
+ .takes_value(true)
+ .hide_possible_values(true)
+ .possible_values(&["never", "always", "auto"]))
+ .arg(flag("fixed-strings").short("F"))
+ .arg(flag("glob").short("g")
+ .takes_value(true).multiple(true).number_of_values(1)
+ .value_name("GLOB"))
+ .arg(flag("ignore-case").short("i"))
+ .arg(flag("line-number").short("n"))
+ .arg(flag("no-line-number").short("N"))
+ .arg(flag("quiet").short("q"))
+ .arg(flag("type").short("t")
+ .takes_value(true).multiple(true).number_of_values(1)
+ .value_name("TYPE"))
+ .arg(flag("type-not").short("T")
+ .takes_value(true).multiple(true).number_of_values(1)
+ .value_name("TYPE"))
+ .arg(flag("unrestricted").short("u")
+ .multiple(true))
+ .arg(flag("invert-match").short("v"))
+ .arg(flag("word-regexp").short("w"))
+ // Third, set up less common flags.
+ .arg(flag("after-context").short("A")
+ .value_name("NUM").takes_value(true)
+ .validator(validate_number))
+ .arg(flag("before-context").short("B")
+ .value_name("NUM").takes_value(true)
+ .validator(validate_number))
+ .arg(flag("context").short("C")
+ .value_name("NUM").takes_value(true)
+ .validator(validate_number))
+ .arg(flag("column"))
+ .arg(flag("context-separator").value_name("ARG").takes_value(true))
+ .arg(flag("debug"))
+ .arg(flag("file").short("f")
+ .value_name("FILE").takes_value(true)
+ .multiple(true).number_of_values(1))
+ .arg(flag("files-with-matches").short("l"))
+ .arg(flag("with-filename").short("H"))
+ .arg(flag("no-filename"))
+ .arg(flag("heading"))
+ .arg(flag("no-heading"))
+ .arg(flag("hidden"))
+ .arg(flag("ignore-file")
+ .value_name("FILE").takes_value(true)
+ .multiple(true).number_of_values(1))
+ .arg(flag("follow").short("L"))
+ .arg(flag("max-count")
+ .short("m").value_name("NUM").takes_value(true)
+ .validator(validate_number))
+ .arg(flag("maxdepth")
+ .value_name("NUM").takes_value(true)
+ .validator(validate_number))
+ .arg(flag("mmap"))
+ .arg(flag("no-messages"))
+ .arg(flag("no-mmap"))
+ .arg(flag("no-ignore"))
+ .arg(flag("no-ignore-parent"))
+ .arg(flag("no-ignore-vcs"))
+ .arg(flag("null"))
+ .arg(flag("pretty").short("p"))
+ .arg(flag("replace").short("r").value_name("ARG").takes_value(true))
+ .arg(flag("case-sensitive").short("s"))
+ .arg(flag("smart-case").short("S"))
+ .arg(flag("threads")
+ .short("j").value_name("ARG").takes_value(true)
+ .validator(validate_number))
+ .arg(flag("vimgrep"))
+ .arg(flag("type-add")
+ .value_name("TYPE").takes_value(true)
+ .multiple(true).number_of_values(1))
+ .arg(flag("type-clear")
+ .value_name("TYPE").takes_value(true)
+ .multiple(true).number_of_values(1))
+}
+
+struct Usage {
+ short: &'static str,
+ long: &'static str,
+}
+
+macro_rules! doc {
+ ($map:expr, $name:expr, $short:expr) => {
+ doc!($map, $name, $short, $short)
+ };
+ ($map:expr, $name:expr, $short:expr, $long:expr) => {
+ $map.insert($name, Usage {
+ short: $short,
+ long: concat!($long, "\n "),
+ });
+ };
+}
+
+lazy_static! {
+ static ref USAGES: HashMap<&'static str, Usage> = {
+ let mut h = HashMap::new();
+ doc!(h, "help-short",
+ "Show short help output.",
+ "Show short help output. Use --help to show more details.");
+ doc!(h, "help",
+ "Show verbose help output.",
+ "When given, more details about flags are provided.");
+ doc!(h, "version",
+ "Prints version information.");
+
+ doc!(h, "pattern",
+ "A regular expression used for searching.",
+ "A regular expression used for searching. Multiple patterns \
+ may be given. To match a pattern beginning with a -, use [-].");
+ doc!(h, "regexp",
+ "A regular expression used for searching.",
+ "A regular expression used for searching. Multiple patterns \
+ may be given. To match a pattern beginning with a -, use [-].");
+ doc!(h, "path",
+ "A file or directory to search.",
+ "A file or directory to search. Directories are searched \
+ recursively.");
+ doc!(h, "files",
+ "Print each file that would be searched.",
+ "Print each file that would be searched without actually \
+ performing the search. This is useful to determine whether a \
+ particular file is being searched or not.");
+ doc!(h, "type-list",
+ "Show all supported file types.",
+ "Show all supported file types and their corresponding globs.");
+
+ doc!(h, "text",
+ "Search binary files as if they were text.");
+ doc!(h, "count",
+ "Only show count of matches for each file.");
+ doc!(h, "color",
+ "When to use color. [default: auto]",
+ "When to use color in the output. The possible values are \
+ never, always or auto. The default is auto.");
+ doc!(h, "fixed-strings",
+ "Treat the pattern as a literal string.",
+ "Treat the pattern as a literal string instead of a regular \
+ expression. When this flag is used, special regular expression \
+ meta characters such as (){}*+. do not need to be escaped.");
+ doc!(h, "glob",
+ "Include or exclude files/directories.",
+ "Include or exclude files/directories for searching that \
+ match the given glob. This always overrides any other \
+ ignore logic. Multiple glob flags may be used. Globbing \
+ rules match .gitignore globs. Precede a glob with a ! \
+ to exclude it.");
+ doc!(h, "ignore-case",
+ "Case insensitive search.",
+ "Case insensitive search. This is overridden by \
+ --case-sensitive.");
+ doc!(h, "line-number",
+ "Show line numbers.",
+ "Show line numbers (1-based). This is enabled by default when \
+ searching in a tty.");
+ doc!(h, "no-line-number",
+ "Suppress line numbers.",
+ "Suppress line numbers. This is enabled by default when NOT \
+ searching in a tty.");
+ doc!(h, "quiet",
+ "Do not print anything to stdout.",
+ "Do not print anything to stdout. If a match is found in a file, \
+ stop searching. This is useful when ripgrep is used only for \
+ its exit code.");
+ doc!(h, "type",
+ "Only search files matching TYPE.",
+ "Only search files matching TYPE. Multiple type flags may be \
+ provided. Use the --type-list flag to list all available \
+ types.");
+ doc!(h, "type-not",
+ "Do not search files matching TYPE.",
+ "Do not search files matching TYPE. Multiple type-not flags may \
+ be provided. Use the --type-list flag to list all available \
+ types.");
+ doc!(h, "unrestricted",
+ "Reduce the level of \"smart\" searching.",
+ "Reduce the level of \"smart\" searching. A single -u \
+ won't respect .gitignore (etc.) files. Two -u flags will \
+ additionally search hidden files and directories. Three \
+ -u flags will additionally search binary files. -uu is \
+ roughly equivalent to grep -r and -uuu is roughly \
+ equivalent to grep -a -r.");
+ doc!(h, "invert-match",
+ "Invert matching.",
+ "Invert matching. Show lines that don't match given patterns.");
+ doc!(h, "word-regexp",
+ "Only show matches surrounded by word boundaries.",
+ "Only show matches surrounded by word boundaries. This is \
+ equivalent to putting \\b before and after all of the search \
+ patterns.");
+
+ doc!(h, "after-context",
+ "Show NUM lines after each match.");
+ doc!(h, "before-context",
+ "Show NUM lines before each match.");
+ doc!(h, "context",
+ "Show NUM lines before and after each match.");
+ doc!(h, "column",
+ "Show column numbers",
+ "Show column numbers (1-based). This only shows the column \
+ numbers for the first match on each line. This does not try \
+ to account for Unicode. One byte is equal to one column.");
+ doc!(h, "context-separator",
+ "Set the context separator string. [default: --]",
+ "The string used to separate non-contiguous context lines in the \
+ output. Escape sequences like \\x7F or \\t may be used. The \
+ default value is --.");
+ doc!(h, "debug",
+ "Show debug messages.",
+ "Show debug messages. Please use this when filing a bug report.");
+ doc!(h, "file",
+ "Search for patterns from the given file.",
+ "Search for patterns from the given file, with one pattern per \
+ line. When this flag is used or multiple times or in \
+ combination with the -e/--regexp flag, then all patterns \
+ provided are searched. Empty pattern lines will match all input \
+ lines, and the newline is not counted as part of the pattern.");
+ doc!(h, "files-with-matches",
+ "Only show the path of each file with at least one match.");
+ doc!(h, "with-filename",
+ "Show file name for each match.",
+ "Prefix each match with the file name that contains it. This is \
+ the default when more than one file is searched.");
+ doc!(h, "no-filename",
+ "Never show the file name for a match.",
+ "Never show the file name for a match. This is the default when \
+ one file is searched.");
+ doc!(h, "heading",
+ "Show matches grouped by each file.",
+ "This shows the file name above clusters of matches from each \
+ file. This is the default mode at a tty.");
+ doc!(h, "no-heading",
+ "Don't group matches by each file.",
+ "Don't group matches by each file. This is the default mode \
+ when not at a tty.");
+ doc!(h, "hidden",
+ "Search hidden files and directories.",
+ "Search hidden files and directories. By default, hidden files \
+ and directories are skipped.");
+ doc!(h, "ignore-file",
+ "Specify additional ignore files.",
+ "Specify additional ignore files for filtering file paths. \
+ Ignore files should be in the gitignore format and are matched \
+ relative to the current working directory. These ignore files \
+ have lower precedence than all other ignore files. When \
+ specifying multiple ignore files, earlier files have lower \
+ precedence than later files.");
+ doc!(h, "follow",
+ "Follow symbolic links.");
+ doc!(h, "max-count",
+ "Limit the number of matches.",
+ "Limit the number of matching lines per file searched to NUM.");
+ doc!(h, "maxdepth",
+ "Descend at most NUM directories.",
+ "Limit the depth of directory traversal to NUM levels beyond \
+ the paths given. A value of zero only searches the \
+ starting-points themselves.\n\nFor example, \
+ 'rg --maxdepth 0 dir/' is a no-op because dir/ will not be \
+ descended into. 'rg --maxdepth 1 dir/' will search only the \
+ direct children of dir/.");
+ doc!(h, "mmap",
+ "Searching using memory maps when possible.",
+ "Search using memory maps when possible. This is enabled by \
+ default when ripgrep thinks it will be faster. Note that memory \
+ map searching doesn't currently support all options, so if an \
+ incompatible option (e.g., --context) is given with --mmap, \
+ then memory maps will not be used.");
+ doc!(h, "no-messages",
+ "Suppress all error messages.",
+ "Suppress all error messages. This is equivalent to redirecting \
+ stderr to /dev/null.");
+ doc!(h, "no-mmap",
+ "Never use memory maps.",
+ "Never use memory maps, even when they might be faster.");
+ doc!(h, "no-ignore",
+ "Don't respect ignore files.",
+ "Don't respect ignore files (.gitignore, .ignore, etc.). This \
+ implies --no-ignore-parent and --no-ignore-vcs.");
+ doc!(h, "no-ignore-parent",
+ "Don't respect ignore files in parent directories.",
+ "Don't respect ignore files (.gitignore, .ignore, etc.) in \
+ parent directories.");
+ doc!(h, "no-ignore-vcs",
+ "Don't respect VCS ignore files",
+ "Don't respect version control ignore files (.gitignore, etc.). \
+ This implies --no-ignore-parent. Note that .ignore files will \
+ continue to be respected.");
+ doc!(h, "null",
+ "Print NUL byte after file names",
+ "Whenever a file name is printed, follow it with a NUL byte. \
+ This includes printing file names before matches, and when \
+ printing a list of matching files such as with --count, \
+ --files-with-matches and --files. This option is useful for use \
+ with xargs.");
+ doc!(h, "pretty",
+ "Alias for --color always --heading -n.");
+ doc!(h, "replace",
+ "Replace matches with string given.",
+ "Replace every match with the string given when printing \
+ results. Neither this flag nor any other flag will modify your \
+ files.\n\nCapture group indices (e.g., $5) and names \
+ (e.g., $foo) are supported in the replacement string.");
+ doc!(h, "case-sensitive",
+ "Search case sensitively.",
+ "Search case sensitively. This overrides -i/--ignore-case and \
+ -S/--smart-case.");
+ doc!(h, "smart-case",
+ "Smart case search.",
+ "Searches case insensitively if the pattern is all lowercase. \
+ Search case sensitively otherwise. This is overridden by \
+ either -s/--case-sensitive or -i/--ignore-case.");
+ doc!(h, "threads",
+ "The approximate number of threads to use.",
+ "The approximate number of threads to use. A value of 0 (which \
+ is the default) causes ripgrep to choose the thread count \
+ using heuristics.");
+ doc!(h, "vimgrep",
+ "Show results in vim compatible format.",
+ "Show results with every match on its own line, including \
+ line numbers and column numbers. With this option, a line with \
+ more than one match will be printed more than once.");
+
+ doc!(h, "type-add",
+ "Add a new glob for a file type.",
+ "Add a new glob for a particular file type. Only one glob can be \
+ added at a time. Multiple --type-add flags can be provided. \
+ Unless --type-clear is used, globs are added to any existing \
+ globs defined inside of ripgrep.\n\nNote that this MUST be \
+ passed to every invocation of ripgrep. Type settings are NOT \
+ persisted.\n\nExample: \
+ rg --type-add 'foo:*.foo' -tfoo PATTERN.");
+ doc!(h, "type-clear",
+ "Clear globs for given file type.",
+ "Clear the file type globs previously defined for TYPE. This \
+ only clears the default tpye definitions that are found inside \