mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2025-07-31 04:02:00 -07:00
Compare commits
53 Commits
wincolor-0
...
termcolor-
Author | SHA1 | Date | |
---|---|---|---|
|
12a78a992c | ||
|
d97c80be63 | ||
|
5213bd30ea | ||
|
82d101907a | ||
|
30608f2444 | ||
|
3d323928a0 | ||
|
8b6a3bc858 | ||
|
e10544f819 | ||
|
dc7e39a6ba | ||
|
36c16eb00c | ||
|
fffee61f80 | ||
|
4cfb2b515b | ||
|
398326bfe2 | ||
|
01358a155c | ||
|
30ca3ecca6 | ||
|
dbc91644fd | ||
|
73c9ac4da5 | ||
|
fe7fe74b0a | ||
|
3d9acdab18 | ||
|
40bacbcd7c | ||
|
b3a9c34515 | ||
|
972ec1adc6 | ||
|
a2d4c03c71 | ||
|
b7c3cf314d | ||
|
6dce04963d | ||
|
d4b790fd8d | ||
|
9283dd122e | ||
|
4c41e9225b | ||
|
9f2b054550 | ||
|
5613df3034 | ||
|
79ad81626f | ||
|
354a5cad97 | ||
|
92e5fad27d | ||
|
f86f987d71 | ||
|
bfbd53eb92 | ||
|
0668c74ed4 | ||
|
1c03298903 | ||
|
e0e8f26c56 | ||
|
f5337329f4 | ||
|
84f4b4ef68 | ||
|
aeac85389d | ||
|
9b3921098a | ||
|
ad262f1146 | ||
|
170c078440 | ||
|
db044a058a | ||
|
c1f8040b32 | ||
|
c8a5a7a3f4 | ||
|
dd3df0ded7 | ||
|
62a182af78 | ||
|
4047d9db71 | ||
|
4683a325fa | ||
|
b6f1e5db1a | ||
|
9e51b18ac7 |
20
.travis.yml
20
.travis.yml
@@ -3,19 +3,27 @@ language: rust
|
||||
env:
|
||||
global:
|
||||
- PROJECT_NAME=ripgrep
|
||||
- RUST_BACKTRACE: full
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
# Needed for completion-function test
|
||||
- zsh
|
||||
|
||||
matrix:
|
||||
include:
|
||||
# Nightly channel.
|
||||
# (All *nix releases are done on the nightly channel to take advantage
|
||||
# of the regex library's multiple pattern SIMD search.)
|
||||
- os: linux
|
||||
rust: nightly-2017-03-13
|
||||
rust: nightly
|
||||
env: TARGET=i686-unknown-linux-musl
|
||||
- os: linux
|
||||
rust: nightly-2017-03-13
|
||||
rust: nightly
|
||||
env: TARGET=x86_64-unknown-linux-musl
|
||||
- os: osx
|
||||
rust: nightly-2017-03-13
|
||||
rust: nightly
|
||||
env: TARGET=x86_64-apple-darwin
|
||||
# Beta channel.
|
||||
- os: linux
|
||||
@@ -26,10 +34,10 @@ matrix:
|
||||
env: TARGET=x86_64-unknown-linux-gnu
|
||||
# Minimum Rust supported channel.
|
||||
- os: linux
|
||||
rust: 1.12.0
|
||||
rust: 1.17.0
|
||||
env: TARGET=x86_64-unknown-linux-gnu
|
||||
- os: linux
|
||||
rust: 1.12.0
|
||||
rust: 1.17.0
|
||||
env: TARGET=x86_64-unknown-linux-musl
|
||||
|
||||
before_install:
|
||||
@@ -57,7 +65,7 @@ deploy:
|
||||
# channel to use to produce the release artifacts
|
||||
# NOTE make sure you only release *once* per target
|
||||
# TODO you may want to pick a different channel
|
||||
condition: $TRAVIS_RUST_VERSION = nightly-2017-03-13
|
||||
condition: $TRAVIS_RUST_VERSION = nightly
|
||||
tags: true
|
||||
|
||||
branches:
|
||||
|
70
CHANGELOG.md
70
CHANGELOG.md
@@ -1,3 +1,73 @@
|
||||
0.6.0 (2017-08-23)
|
||||
==================
|
||||
This is a new minor version release of ripgrep that includes many bug fixes
|
||||
and a few new features such as `--iglob` and `-x/--line-regexp`.
|
||||
|
||||
Note that this release increases the minimum supported Rust version from 1.12
|
||||
to 1.17.
|
||||
|
||||
Feature enhancements:
|
||||
|
||||
* Added or improved file type filtering for BitBake, C++, Cabal, cshtml, Julia,
|
||||
Make, msbuild, QMake, Yocto
|
||||
* [FEATURE #163](https://github.com/BurntSushi/ripgrep/issues/163):
|
||||
Add an `--iglob` flag that is like `-g/--glob`, but matches globs
|
||||
case insensitively.
|
||||
* [FEATURE #520](https://github.com/BurntSushi/ripgrep/pull/518):
|
||||
Add `-x/--line-regexp` flag, which requires a match to span an entire line.
|
||||
* [FEATURE #551](https://github.com/BurntSushi/ripgrep/pull/551),
|
||||
[FEATURE #554](https://github.com/BurntSushi/ripgrep/pull/554):
|
||||
`ignore`: add new `matched_path_or_any_parents` method.
|
||||
|
||||
Bug fixes:
|
||||
|
||||
* [BUG #342](https://github.com/BurntSushi/ripgrep/issues/342):
|
||||
Fix invisible text in some PowerShell environments by changing the
|
||||
default color scheme on Windows.
|
||||
* [BUG #413](https://github.com/BurntSushi/ripgrep/issues/413):
|
||||
Release binaries on Unix are now `strip`'d by default. This decreases
|
||||
binary size by an order of magnitude.
|
||||
* [BUG #483](https://github.com/BurntSushi/ripgrep/issues/483):
|
||||
When `--quiet` is passed, `--files` should be quiet.
|
||||
* [BUG #488](https://github.com/BurntSushi/ripgrep/pull/488):
|
||||
When `--vimgrep` is passed, `--with-filename` should be enabled
|
||||
automatically.
|
||||
* [BUG #493](https://github.com/BurntSushi/ripgrep/issues/493):
|
||||
Fix another bug in the implementation of the `-o/--only-matching`
|
||||
flag.
|
||||
* [BUG #499](https://github.com/BurntSushi/ripgrep/pull/499):
|
||||
Permit certain flags to override others.
|
||||
* [BUG #523](https://github.com/BurntSushi/ripgrep/pull/523):
|
||||
`wincolor`: Re-fetch Windows console on all calls.
|
||||
* [BUG #523](https://github.com/BurntSushi/ripgrep/issues/524):
|
||||
`--version` now shows enabled compile-time features.
|
||||
* [BUG #532](https://github.com/BurntSushi/ripgrep/issues/532),
|
||||
[BUG #536](https://github.com/BurntSushi/ripgrep/pull/536),
|
||||
[BUG #538](https://github.com/BurntSushi/ripgrep/pull/538),
|
||||
[BUG #540](https://github.com/BurntSushi/ripgrep/pull/540),
|
||||
[BUG #560](https://github.com/BurntSushi/ripgrep/pull/560),
|
||||
[BUG #565](https://github.com/BurntSushi/ripgrep/pull/565):
|
||||
Improve zsh completion.
|
||||
* [BUG #578](https://github.com/BurntSushi/ripgrep/pull/578):
|
||||
Enable SIMD for `encoding_rs` when appropriate.
|
||||
* [BUG #580](https://github.com/BurntSushi/ripgrep/issues/580):
|
||||
Fix `-w/--word-regexp` in the presence of capturing groups.
|
||||
* [BUG #581](https://github.com/BurntSushi/ripgrep/issues/581):
|
||||
Document that ripgrep may terminate unexpectedly when searching via
|
||||
memory maps (which can happen using default settings).
|
||||
|
||||
Friends of ripgrep:
|
||||
|
||||
I'd like to give a big Thank You to @okdana for their recent hard work on
|
||||
ripgrep. This includes new features like `--line-regexp`, heroic effort on
|
||||
zsh auto-completion and thinking through some thorny argv issues with me.
|
||||
|
||||
I'd also like to thank @ericbn for their work on improving ripgrep's argv
|
||||
parsing by allowing some flags to override others.
|
||||
|
||||
Thanks @okdana and @ericbn!
|
||||
|
||||
|
||||
0.5.2 (2017-05-11)
|
||||
==================
|
||||
Feature enhancements:
|
||||
|
137
Cargo.lock
generated
137
Cargo.lock
generated
@@ -1,20 +1,19 @@
|
||||
[root]
|
||||
name = "ripgrep"
|
||||
version = "0.5.2"
|
||||
version = "0.6.0"
|
||||
dependencies = [
|
||||
"atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bytecount 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.24.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"encoding_rs 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bytecount 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"encoding_rs 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"grep 0.1.6",
|
||||
"ignore 0.2.0",
|
||||
"ignore 0.2.2",
|
||||
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memmap 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termcolor 0.3.2",
|
||||
@@ -39,41 +38,42 @@ version = "0.2.2"
|
||||
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.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.8.2"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bytecount"
|
||||
version = "0.1.6"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"simd 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"simd 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.0"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.24.1"
|
||||
version = "2.26.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)",
|
||||
"atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"textwrap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vec_map 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -83,18 +83,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.5.1"
|
||||
version = "0.6.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"simd 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.4.2"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -104,11 +105,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "fs2"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
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.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -118,7 +119,7 @@ version = "0.2.0"
|
||||
dependencies = [
|
||||
"aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -127,7 +128,7 @@ dependencies = [
|
||||
name = "grep"
|
||||
version = "0.1.6"
|
||||
dependencies = [
|
||||
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -135,15 +136,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ignore"
|
||||
version = "0.2.0"
|
||||
version = "0.2.2"
|
||||
dependencies = [
|
||||
"crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"globset 0.2.0",
|
||||
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -163,12 +164,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.23"
|
||||
version = "0.2.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.3.7"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -176,7 +177,7 @@ name = "memchr"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -184,18 +185,18 @@ name = "memmap"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fs2 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.4.0"
|
||||
version = "1.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -207,7 +208,7 @@ dependencies = [
|
||||
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"simd 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -230,6 +231,11 @@ name = "simd"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "simd"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.6.0"
|
||||
@@ -241,7 +247,7 @@ version = "0.3.0"
|
||||
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.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -249,30 +255,30 @@ dependencies = [
|
||||
name = "termcolor"
|
||||
version = "0.3.2"
|
||||
dependencies = [
|
||||
"wincolor 0.1.3",
|
||||
"wincolor 0.1.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread-id"
|
||||
version = "3.1.0"
|
||||
name = "textwrap"
|
||||
version = "0.7.0"
|
||||
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.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "0.3.3"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"thread-id 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.1.0"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -282,7 +288,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unreachable"
|
||||
version = "0.1.1"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -295,7 +301,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.7.0"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -325,7 +331,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "wincolor"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -335,35 +341,36 @@ dependencies = [
|
||||
"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699"
|
||||
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
|
||||
"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159"
|
||||
"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4"
|
||||
"checksum bytecount 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1e8f09fbc8c6726a4b616dcfbd4f54491068d6bb1b93ac03c78ac18ff9a5924a"
|
||||
"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
|
||||
"checksum clap 2.24.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7541069be0b8aec41030802abe8b5cdef0490070afaa55418adea93b1e431e0"
|
||||
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
|
||||
"checksum bytecount 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "4bbeb7c30341fce29f6078b4bdf876ea4779600866e98f5b2d203a534f195050"
|
||||
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
|
||||
"checksum clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2267a8fdd4dce6956ba6649e130f62fb279026e5e84b92aa939ac8f85ce3f9f0"
|
||||
"checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97"
|
||||
"checksum encoding_rs 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e4bc519d572af08cf72c4d61e0de9b05e9fa66d1fdb5e739fb5c405860b42d43"
|
||||
"checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83"
|
||||
"checksum encoding_rs 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e00a1b1e95eb46988805ceee6f34cd95c46a6753e290cb3ff0486931989d4a4c"
|
||||
"checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
|
||||
"checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
|
||||
"checksum fs2 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34edaee07555859dc13ca387e6ae05686bb4d0364c95d649b6dab959511f4baf"
|
||||
"checksum fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ab76cfd2aaa59b7bf6688ad9ba15bbae64bff97f04ea02144cfd3443e5c2866"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf"
|
||||
"checksum libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)" = "e7eb6b826bfc1fdea7935d46556250d1799b7fe2d9f7951071f4291710665e3e"
|
||||
"checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad"
|
||||
"checksum libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "8a014d9226c2cc402676fbe9ea2e15dd5222cd1dd57f576b5b283178c944a264"
|
||||
"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b"
|
||||
"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
|
||||
"checksum memmap 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46f3c7359028b31999287dae4e5047ddfe90a23b7dca2282ce759b491080c99b"
|
||||
"checksum num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca313f1862c7ec3e0dfe8ace9fa91b1d9cb5c84ace3d00f5ec4216238e93c167"
|
||||
"checksum num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aec53c34f2d0247c5ca5d32cca1478762f301740468ee9ee6dcb7a0dd7a0c584"
|
||||
"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b"
|
||||
"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db"
|
||||
"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
|
||||
"checksum simd 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "63b5847c2d766ca7ce7227672850955802fabd779ba616aeabead4c2c3877023"
|
||||
"checksum simd 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a94d14a2ae1f1f110937de5fb69e494372560181c7e1739a097fcc2cee37ba0"
|
||||
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
|
||||
"checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209"
|
||||
"checksum thread-id 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8df7875b676fddfadffd96deea3b1124e5ede707d4884248931077518cf1f773"
|
||||
"checksum thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c85048c6260d17cf486ceae3282d9fb6b90be220bf5b28c400f5485ffc29f0c7"
|
||||
"checksum unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18127285758f0e2c6cf325bb3f3d138a12fee27de4f23e146cd6a179f26c2cf3"
|
||||
"checksum textwrap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f728584ea33b0ad19318e20557cb0a39097751dbb07171419673502f848c7af6"
|
||||
"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14"
|
||||
"checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946"
|
||||
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
|
||||
"checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91"
|
||||
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
|
||||
"checksum vec_map 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8cdc8b93bd0198ed872357fb2e667f7125646b1762f16d60b2c96350d361897"
|
||||
"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
|
17
Cargo.toml
17
Cargo.toml
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ripgrep"
|
||||
version = "0.5.2" #:version
|
||||
version = "0.6.0" #:version
|
||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||
description = """
|
||||
Line oriented search tool using Rust's regex library. Combines the raw
|
||||
@@ -16,6 +16,10 @@ license = "Unlicense/MIT"
|
||||
exclude = ["HomebrewFormula"]
|
||||
build = "build.rs"
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "BurntSushi/ripgrep" }
|
||||
appveyor = { repository = "BurntSushi/ripgrep" }
|
||||
|
||||
[[bin]]
|
||||
bench = false
|
||||
path = "src/main.rs"
|
||||
@@ -28,13 +32,12 @@ path = "tests/tests.rs"
|
||||
[dependencies]
|
||||
atty = "0.2.2"
|
||||
bytecount = "0.1.4"
|
||||
clap = "2.24.1"
|
||||
encoding_rs = "0.5.0"
|
||||
clap = "2.26"
|
||||
encoding_rs = "0.6"
|
||||
env_logger = { version = "0.4", default-features = false }
|
||||
grep = { version = "0.1.5", path = "grep" }
|
||||
ignore = { version = "0.2.0", path = "ignore" }
|
||||
ignore = { version = "0.2.2", path = "ignore" }
|
||||
lazy_static = "0.2"
|
||||
libc = "0.2"
|
||||
log = "0.3"
|
||||
memchr = "1"
|
||||
memmap = "0.5"
|
||||
@@ -44,12 +47,12 @@ same-file = "0.1.1"
|
||||
termcolor = { version = "0.3.0", path = "termcolor" }
|
||||
|
||||
[build-dependencies]
|
||||
clap = "2.24.1"
|
||||
clap = "2.26"
|
||||
lazy_static = "0.2"
|
||||
|
||||
[features]
|
||||
avx-accel = ["bytecount/avx-accel"]
|
||||
simd-accel = ["bytecount/simd-accel", "regex/simd-accel"]
|
||||
simd-accel = ["bytecount/simd-accel", "regex/simd-accel", "encoding_rs/simd-accel"]
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
||||
|
19
README.md
19
README.md
@@ -187,17 +187,17 @@ If you're a **Gentoo** user, you can install `ripgrep` from the [official repo](
|
||||
$ emerge ripgrep
|
||||
```
|
||||
|
||||
If you're a **Fedora 24+** user, you can install `ripgrep` from [copr](https://copr.fedorainfracloud.org/coprs/carlgeorge/ripgrep/):
|
||||
If you're a **Fedora 24+** user, you can install `ripgrep` from [copr](https://copr.fedorainfracloud.org/coprs/carlwgeorge/ripgrep/):
|
||||
|
||||
```
|
||||
$ dnf copr enable carlgeorge/ripgrep
|
||||
$ dnf copr enable carlwgeorge/ripgrep
|
||||
$ dnf install ripgrep
|
||||
```
|
||||
|
||||
If you're a **RHEL/CentOS 7** user, you can install `ripgrep` from [copr](https://copr.fedorainfracloud.org/coprs/carlgeorge/ripgrep/):
|
||||
If you're a **RHEL/CentOS 7** user, you can install `ripgrep` from [copr](https://copr.fedorainfracloud.org/coprs/carlwgeorge/ripgrep/):
|
||||
|
||||
```
|
||||
$ yum-config-manager --add-repo=https://copr.fedorainfracloud.org/coprs/carlgeorge/ripgrep/repo/epel-7/carlgeorge-ripgrep-epel-7.repo
|
||||
$ yum-config-manager --add-repo=https://copr.fedorainfracloud.org/coprs/carlwgeorge/ripgrep/repo/epel-7/carlwgeorge-ripgrep-epel-7.repo
|
||||
$ yum install ripgrep
|
||||
```
|
||||
|
||||
@@ -210,7 +210,8 @@ $ # (Or using the attribute name, which is also `ripgrep`.)
|
||||
```
|
||||
|
||||
If you're a **Rust programmer**, `ripgrep` can be installed with `cargo`. Note
|
||||
that this requires you to have **Rust 1.12 or newer** installed.
|
||||
that the minimum supported version of Rust for ripgrep is **1.17**, although
|
||||
ripgrep may work with older versions.
|
||||
|
||||
```
|
||||
$ cargo install ripgrep
|
||||
@@ -346,7 +347,7 @@ For **fish**, move `complete/rg.fish` to `$HOME/.config/fish/completions/`.
|
||||
For **PowerShell**, add `. _rg.ps1` to your PowerShell
|
||||
[profile](https://technet.microsoft.com/en-us/library/bb613488(v=vs.85).aspx)
|
||||
(note the leading period). If the `_rg.ps1` file is not on your `PATH`, do
|
||||
`. /path/to/_rg.ps1` instead.
|
||||
`. /path/to/_rg.ps1` instead.
|
||||
|
||||
For **zsh**, move `complete/_rg` to one of your `$fpath` directories.
|
||||
|
||||
@@ -354,7 +355,7 @@ For **zsh**, move `complete/_rg` to one of your `$fpath` directories.
|
||||
|
||||
`ripgrep` is written in Rust, so you'll need to grab a
|
||||
[Rust installation](https://www.rust-lang.org/) in order to compile it.
|
||||
`ripgrep` compiles with Rust 1.12 (stable) or newer. Building is easy:
|
||||
`ripgrep` compiles with Rust 1.17 (stable) or newer. Building is easy:
|
||||
|
||||
```
|
||||
$ git clone https://github.com/BurntSushi/ripgrep
|
||||
@@ -392,7 +393,7 @@ from the repository root.
|
||||
##### Powershell Profile
|
||||
|
||||
To customize powershell on start-up there is a special powershell script that has to be created.
|
||||
In order to find its location run command `Get-Command $profile | Select-Object -ExpandProperty Definition`
|
||||
In order to find its location type `$profile`
|
||||
See [more](https://technet.microsoft.com/en-us/library/bb613488(v=vs.85).aspx) for profile details.
|
||||
|
||||
Any powershell code in this file gets evaluated at the start of console.
|
||||
@@ -449,7 +450,7 @@ Example `$OutputEncoding` settings:
|
||||
`$OutputEncoding = [System.Console]::OutputEncoding`
|
||||
|
||||
If you continue to have encoding problems, you can also force the encoding
|
||||
that the console will use for printing to UTF-8 with
|
||||
that the console will use for printing to UTF-8 with
|
||||
`[System.Console]::OutputEncoding = [System.Text.Encoding]::UTF8`. This
|
||||
will also reset when PowerShell is restarted, so you can add that line
|
||||
to your profile as well if you want to make the setting permanent.
|
||||
|
@@ -1,6 +1,7 @@
|
||||
environment:
|
||||
global:
|
||||
PROJECT_NAME: ripgrep
|
||||
RUST_BACKTRACE: full
|
||||
matrix:
|
||||
- TARGET: i686-pc-windows-gnu
|
||||
CHANNEL: stable
|
||||
|
@@ -1082,7 +1082,7 @@ def download_subtitles_en(suite_dir):
|
||||
if not os.path.exists(en_path):
|
||||
if not os.path.exists(en_path_gz):
|
||||
run_cmd(['curl', '-LO', SUBTITLES_EN_URL], cwd=subtitle_dir)
|
||||
run_cmd(['gunzip', en_path_gz], cwd=subtitle_dir)
|
||||
run_cmd(['gunzip', en_path_gz])
|
||||
if not os.path.exists(en_path_sample):
|
||||
# Get a sample roughly the same size as the Russian corpus so that
|
||||
# benchmarks finish in a reasonable time.
|
||||
@@ -1109,7 +1109,7 @@ def download_subtitles_ru(suite_dir):
|
||||
if not os.path.exists(ru_path):
|
||||
if not os.path.exists(ru_path_gz):
|
||||
run_cmd(['curl', '-LO', SUBTITLES_RU_URL], cwd=subtitle_dir)
|
||||
run_cmd(['gunzip', ru_path_gz], cwd=subtitle_dir)
|
||||
run_cmd(['gunzip', ru_path_gz])
|
||||
|
||||
|
||||
def has_subtitles_ru(suite_dir):
|
||||
@@ -1184,6 +1184,7 @@ def collect_benchmarks(suite_dir, filter_pat=None,
|
||||
name,
|
||||
' '.join(['--download %s' % n for n in e.missing_names]),
|
||||
))
|
||||
continue
|
||||
except MissingCommands as e:
|
||||
fmt = 'missing commands: %s, skipping benchmark %s ' \
|
||||
'(run with --allow-missing to run incomplete benchmarks)'
|
||||
@@ -1239,7 +1240,7 @@ def main():
|
||||
benchmarks = collect_benchmarks(
|
||||
args.dir, filter_pat=args.bench,
|
||||
allow_missing_commands=args.allow_missing,
|
||||
disabled_cmds=args.disabled.split(','),
|
||||
disabled_cmds=(args.disabled or '').split(','),
|
||||
warmup_iter=args.warmup_iter, bench_iter=args.bench_iter)
|
||||
for b in benchmarks:
|
||||
print(b.name)
|
||||
@@ -1266,7 +1267,7 @@ def main():
|
||||
benchmarks = collect_benchmarks(
|
||||
args.dir, filter_pat=args.bench,
|
||||
allow_missing_commands=args.allow_missing,
|
||||
disabled_cmds=args.disabled.split(','),
|
||||
disabled_cmds=(args.disabled or '').split(','),
|
||||
warmup_iter=args.warmup_iter, bench_iter=args.bench_iter)
|
||||
for i, b in enumerate(benchmarks):
|
||||
result = b.run()
|
||||
|
@@ -18,9 +18,12 @@ mk_tarball() {
|
||||
mkdir "$td/$name"
|
||||
mkdir "$td/$name/complete"
|
||||
|
||||
cp target/$TARGET/release/rg "$td/$name/"
|
||||
cp target/$TARGET/release/rg "$td/$name/rg"
|
||||
strip "$td/$name/rg"
|
||||
cp {doc/rg.1,README.md,UNLICENSE,COPYING,LICENSE-MIT} "$td/$name/"
|
||||
cp target/$TARGET/release/build/ripgrep-*/out/{rg.bash-completion,rg.fish,_rg.ps1} "$td/$name/complete/"
|
||||
cp \
|
||||
target/$TARGET/release/build/ripgrep-*/out/{rg.bash-completion,rg.fish,_rg.ps1} \
|
||||
"$td/$name/complete/"
|
||||
cp complete/_rg "$td/$name/complete/"
|
||||
|
||||
pushd $td
|
||||
|
@@ -28,6 +28,8 @@ run_test_suite() {
|
||||
cargo build --target $TARGET --verbose --manifest-path termcolor/Cargo.toml
|
||||
cargo test --target $TARGET --verbose --manifest-path termcolor/Cargo.toml
|
||||
|
||||
"$( dirname "${0}" )/test_complete.sh"
|
||||
|
||||
# sanity check the file type
|
||||
file target/$TARGET/debug/rg
|
||||
}
|
||||
|
94
ci/test_complete.sh
Executable file
94
ci/test_complete.sh
Executable file
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env zsh
|
||||
|
||||
##
|
||||
# Compares options in `rg --help` output to options in zsh completion function
|
||||
|
||||
emulate -R zsh
|
||||
setopt extended_glob
|
||||
setopt no_function_argzero
|
||||
setopt no_unset
|
||||
|
||||
get_comp_args() {
|
||||
setopt local_options unset
|
||||
|
||||
# Our completion function recognises a special variable which tells it to
|
||||
# dump the _arguments specs and then just return. But do this in a sub-shell
|
||||
# anyway to avoid any weirdness
|
||||
( _RG_COMPLETE_LIST_ARGS=1 source $1 )
|
||||
return $?
|
||||
}
|
||||
|
||||
main() {
|
||||
local diff
|
||||
local rg="${${0:a}:h}/../target/${TARGET:-}/release/rg"
|
||||
local _rg="${${0:a}:h}/../complete/_rg"
|
||||
local -a help_args comp_args
|
||||
|
||||
[[ -e $rg ]] || rg=${rg/%\/release\/rg/\/debug\/rg}
|
||||
|
||||
[[ -e $rg ]] || {
|
||||
printf >&2 'File not found: %s\n' $rg
|
||||
return 1
|
||||
}
|
||||
[[ -e $_rg ]] || {
|
||||
printf >&2 'File not found: %s\n' $_rg
|
||||
return 1
|
||||
}
|
||||
|
||||
printf 'Comparing options:\n-%s\n+%s\n' $rg $_rg
|
||||
|
||||
# 'Parse' options out of the `--help` output. To prevent false positives we
|
||||
# only look at lines where the first non-white-space character is `-`
|
||||
help_args=( ${(f)"$(
|
||||
$rg --help |
|
||||
$rg -- '^\s*-' |
|
||||
$rg -io -- '[\t ,](-[a-z0-9]|--[a-z0-9-]+)\b' |
|
||||
tr -d '\t ,' |
|
||||
sort -u
|
||||
)"} )
|
||||
|
||||
# 'Parse' options out of the completion function
|
||||
comp_args=( ${(f)"$( get_comp_args $_rg )"} )
|
||||
|
||||
comp_args=( ${comp_args#\(*\)} ) # Strip excluded options
|
||||
comp_args=( ${comp_args#\*} ) # Strip repetition indicator
|
||||
comp_args=( ${comp_args%%-[:[]*} ) # Strip everything after -optname-
|
||||
comp_args=( ${comp_args%%[:+=[]*} ) # Strip everything after other optspecs
|
||||
comp_args=( ${comp_args##[^-]*} ) # Remove non-options
|
||||
|
||||
# This probably isn't necessary, but we should ensure the same order
|
||||
comp_args=( ${(f)"$( printf '%s\n' $comp_args | sort -u )"} )
|
||||
|
||||
(( $#help_args )) || {
|
||||
printf >&2 'Failed to get help_args\n'
|
||||
return 1
|
||||
}
|
||||
(( $#comp_args )) || {
|
||||
printf >&2 'Failed to get comp_args\n'
|
||||
return 1
|
||||
}
|
||||
|
||||
diff="$(
|
||||
if diff --help 2>&1 | grep -qF -- '--label'; then
|
||||
diff -U2 \
|
||||
--label '`rg --help`' \
|
||||
--label '`_rg`' \
|
||||
=( printf '%s\n' $help_args ) =( printf '%s\n' $comp_args )
|
||||
else
|
||||
diff -U2 \
|
||||
-L '`rg --help`' \
|
||||
-L '`_rg`' \
|
||||
=( printf '%s\n' $help_args ) =( printf '%s\n' $comp_args )
|
||||
fi
|
||||
)"
|
||||
|
||||
(( $#diff )) && {
|
||||
printf >&2 '%s\n' 'zsh completion options differ from `--help` options:'
|
||||
printf >&2 '%s\n' $diff
|
||||
return 1
|
||||
}
|
||||
printf 'OK\n'
|
||||
return 0
|
||||
}
|
||||
|
||||
main "${@}"
|
299
complete/_rg
299
complete/_rg
@@ -1,4 +1,210 @@
|
||||
#compdef rg
|
||||
|
||||
##
|
||||
# zsh completion function for ripgrep
|
||||
#
|
||||
# Run ci/test_complete.sh after building to ensure that the options supported by
|
||||
# this function stay in synch with the `rg` binary.
|
||||
#
|
||||
# @see https://github.com/zsh-users/zsh/blob/master/Etc/completion-style-guide
|
||||
#
|
||||
# Based on code from the zsh-users project — see copyright notice below.
|
||||
|
||||
_rg() {
|
||||
local state_descr ret curcontext="${curcontext:-}"
|
||||
local -a context line state
|
||||
local -A opt_args val_args
|
||||
local -a rg_args
|
||||
|
||||
# Sort by long option name to match `rg --help`
|
||||
rg_args=(
|
||||
'(-A -C --after-context --context)'{-A+,--after-context=}'[specify lines to show after each match]:number of lines'
|
||||
'(-B -C --before-context --context)'{-B+,--before-context=}'[specify lines to show before each match]:number of lines'
|
||||
'(-i -s -S --ignore-case --case-sensitive --smart-case)'{-s,--case-sensitive}'[search case-sensitively]'
|
||||
'--color=[specify when to use colors in output]:when:( never auto always ansi )'
|
||||
'*--colors=[specify color settings and styles]: :->colorspec'
|
||||
'--column[show column numbers]'
|
||||
'(-A -B -C --after-context --before-context --context)'{-C+,--context=}'[specify lines to show before and after each match]:number of lines'
|
||||
'--context-separator=[specify string used to separate non-continuous context lines in output]:separator'
|
||||
'(-c --count)'{-c,--count}'[only show count of matches for each file]'
|
||||
'--debug[show debug messages]'
|
||||
'--dfa-size-limit=[specify upper size limit of generated DFA]:DFA size'
|
||||
'(-E --encoding)'{-E+,--encoding=}'[specify text encoding of files to search]: :_rg_encodings'
|
||||
'*'{-f+,--file=}'[specify file containing patterns to search for]:file:_files'
|
||||
"(1)--files[show each file that would be searched (but don't search)]"
|
||||
'(-l --files-with-matches --files-without-match)'{-l,--files-with-matches}'[only show names of files with matches]'
|
||||
'(-l --files-with-matches --files-without-match)--files-without-match[only show names of files without matches]'
|
||||
'(-F --fixed-strings)'{-F,--fixed-strings}'[treat pattern as literal string instead of regular expression]'
|
||||
'(-L --follow)'{-L,--follow}'[follow symlinks]'
|
||||
'*'{-g+,--glob=}'[include or exclude files for searching that match the specified glob]:glob'
|
||||
'(: -)'{-h,--help}'[display help information]'
|
||||
'(-p --no-heading --pretty --vimgrep)--heading[show matches grouped by file name]'
|
||||
'--hidden[search hidden files and directories]'
|
||||
'*--iglob=[include or exclude files for searching that match the specified case-insensitive glob]:glob'
|
||||
'(-i -s -S --case-sensitive --ignore-case --smart-case)'{-i,--ignore-case}'[search case-insensitively]'
|
||||
'--ignore-file=[specify additional ignore file]:file:_files'
|
||||
'(-v --invert-match)'{-v,--invert-match}'[invert matching]'
|
||||
'(-n -N --line-number --no-line-number)'{-n,--line-number}'[show line numbers]'
|
||||
'(-w -x --line-regexp --word-regexp)'{-x,--line-regexp}'[only show matches surrounded by line boundaries]'
|
||||
'(-M --max-columns)'{-M+,--max-columns=}'[specify max length of lines to print]:number of bytes'
|
||||
'(-m --max-count)'{-m+,--max-count=}'[specify max number of matches per file]:number of matches'
|
||||
'--max-filesize=[specify size above which files should be ignored]:file size'
|
||||
'--maxdepth=[specify max number of directories to descend]:number of directories'
|
||||
'(--mmap --no-mmap)--mmap[search using memory maps when possible]'
|
||||
'(-H --with-filename --no-filename)--no-filename[suppress all file names]'
|
||||
"(-p --heading --pretty --vimgrep)--no-heading[don't group matches by file name]"
|
||||
"(--no-ignore-parent)--no-ignore[don't respect ignore files]"
|
||||
"--no-ignore-parent[don't respect ignore files in parent directories]"
|
||||
"--no-ignore-vcs[don't respect version control ignore files]"
|
||||
'(-n -N --line-number --no-line-number)'{-N,--no-line-number}'[suppress line numbers]'
|
||||
'--no-messages[suppress all error messages]'
|
||||
"(--mmap --no-mmap)--no-mmap[don't search using memory maps]"
|
||||
'(-0 --null)'{-0,--null}'[print NUL byte after file names]'
|
||||
'(-o --only-matching -r --replace)'{-o,--only-matching}'[show only matching part of each line]'
|
||||
'--path-separator=[specify path separator to use when printing file names]:separator'
|
||||
'(-p --heading --no-heading --pretty --vimgrep)'{-p,--pretty}'[alias for --color=always --heading -n]'
|
||||
'(-q --quiet)'{-q,--quiet}'[suppress normal output]'
|
||||
'--regex-size-limit=[specify upper size limit of compiled regex]:regex size'
|
||||
'(1 -f --file)*'{-e+,--regexp=}'[specify pattern]:pattern'
|
||||
'(-o --only-matching -r --replace)'{-r+,--replace=}'[specify string used to replace matches]:replace string'
|
||||
'(-i -s -S --ignore-case --case-sensitive --smart-case)'{-S,--smart-case}'[search case-insensitively if the pattern is all lowercase]'
|
||||
'(-j --threads)--sort-files[sort results by file path (disables parallelism)]'
|
||||
'(-a --text)'{-a,--text}'[search binary files as if they were text]'
|
||||
'(-j --sort-files --threads)'{-j+,--threads=}'[specify approximate number of threads to use]:number of threads'
|
||||
'*'{-t+,--type=}'[only search files matching specified type]: :_rg_types'
|
||||
'*--type-add=[add new glob for file type]: :->typespec'
|
||||
'*--type-clear=[clear globs previously defined for specified file type]: :_rg_types'
|
||||
# This should actually be exclusive with everything but other type options
|
||||
'(:)--type-list[show all supported file types and their associated globs]'
|
||||
'*'{-T+,--type-not=}"[don't search files matching specified type]: :_rg_types"
|
||||
'*'{-u,--unrestricted}'[reduce level of "smart" searching]'
|
||||
'(: -)'{-V,--version}'[display version information]'
|
||||
'(-p --heading --no-heading --pretty)--vimgrep[show results in vim-compatible format]'
|
||||
'(-H --no-filename --with-filename)'{-H,--with-filename}'[prefix each match with name of file that contains it]'
|
||||
'(-w -x --line-regexp --word-regexp)'{-w,--word-regexp}'[only show matches surrounded by word boundaries]'
|
||||
'(-e -f --file --files --regexp --type-list)1: :_rg_pattern'
|
||||
'(--type-list)*:file:_files'
|
||||
)
|
||||
|
||||
[[ ${_RG_COMPLETE_LIST_ARGS:-} == (1|t*|y*) ]] && {
|
||||
printf '%s\n' "${rg_args[@]}"
|
||||
return 0
|
||||
}
|
||||
|
||||
_arguments -s -S : "${rg_args[@]}" && return 0
|
||||
|
||||
while (( $#state )); do
|
||||
case "${state[1]}" in
|
||||
colorspec)
|
||||
# @todo I don't like this because it allows you to do weird things like
|
||||
# `line:line:bg:`. Also, i would like the `compadd -q` behaviour
|
||||
[[ -prefix *:none: ]] && return 1
|
||||
[[ -prefix *:*:*:* ]] && return 1
|
||||
|
||||
_values -S ':' 'color/style type' \
|
||||
'column[specify coloring for column numbers]: :->attribute' \
|
||||
'line[specify coloring for line numbers]: :->attribute' \
|
||||
'match[specify coloring for match text]: :->attribute' \
|
||||
'path[specify color for file names]: :->attribute' && return 0
|
||||
|
||||
[[ "${state}" == 'attribute' ]] &&
|
||||
_values -S ':' 'color/style attribute' \
|
||||
'none[clear color/style for type]' \
|
||||
'bg[specify background color]: :->color' \
|
||||
'fg[specify foreground color]: :->color' \
|
||||
'style[specify text style]: :->style' && return 0
|
||||
|
||||
[[ "${state}" == 'color' ]] &&
|
||||
_values -S ':' 'color value' \
|
||||
black blue green red cyan magenta yellow white && return 0
|
||||
|
||||
[[ "${state}" == 'style' ]] &&
|
||||
_values -S ':' 'style value' \
|
||||
bold nobold intense nointense && return 0
|
||||
;;
|
||||
|
||||
typespec)
|
||||
if compset -P '[^:]##:include:'; then
|
||||
_sequence -s ',' _rg_types && return 0
|
||||
# @todo This bit in particular could be better, but it's a little
|
||||
# complex, and attempting to solve it seems to run us up against a crash
|
||||
# bug — zsh # 40362
|
||||
elif compset -P '[^:]##:'; then
|
||||
_message 'glob or include directive' && return 1
|
||||
elif [[ ! -prefix *:* ]]; then
|
||||
_rg_types -qS ':' && return 0
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
shift state
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# zsh 5.1 refuses to complete options if a 'match-less' operand like our pattern
|
||||
# could be 'completed' instead. We can use _guard() to avoid this problem, but
|
||||
# it introduces another one: zsh won't print the message if we try to complete
|
||||
# the pattern after having passed `--`. To work around *that* problem, we can
|
||||
# use this function to bypass the _guard() when `--` is on the command line.
|
||||
# This is inaccurate (it'd get confused by e.g. `rg -e --`), but zsh's handling
|
||||
# of `--` isn't accurate anyway
|
||||
_rg_pattern() {
|
||||
if (( ${words[(I)--]} )); then
|
||||
_message 'pattern'
|
||||
else
|
||||
_guard '^-*' 'pattern'
|
||||
fi
|
||||
}
|
||||
|
||||
# Complete encodings
|
||||
_rg_encodings() {
|
||||
local -a expl
|
||||
local -aU _encodings
|
||||
|
||||
# This is impossible to read, but these encodings rarely if ever change, so it
|
||||
# probably doesn't matter. They are derived from the list given here:
|
||||
# https://encoding.spec.whatwg.org/#concept-encoding-get
|
||||
_encodings=(
|
||||
{{,us-}ascii,arabic,chinese,cyrillic,greek{,8},hebrew,korean}
|
||||
logical visual mac {,cs}macintosh x-mac-{cyrillic,roman,ukrainian}
|
||||
866 ibm{819,866} csibm866
|
||||
big5{,-hkscs} {cn-,cs}big5 x-x-big5
|
||||
cp{819,866,125{0..8}} x-cp125{0..8}
|
||||
csiso2022{jp,kr} csiso8859{6,8}{e,i}
|
||||
csisolatin{{1..6},9} csisolatin{arabic,cyrillic,greek,hebrew}
|
||||
ecma-{114,118} asmo-708 elot_928 sun_eu_greek
|
||||
euc-{jp,kr} x-euc-jp cseuckr cseucpkdfmtjapanese
|
||||
{,x-}gbk csiso58gb231280 gb18030 {,cs}gb2312 gb_2312{,-80} hz-gb-2312
|
||||
iso-2022-{cn,cn-ext,jp,kr}
|
||||
iso8859{,-}{{1..11},13,14,15}
|
||||
iso-8859-{{1..11},{6,8}-{e,i},13,14,15,16} iso_8859-{{1..9},15}
|
||||
iso_8859-{1,2,6,7}:1987 iso_8859-{3,4,5,8}:1988 iso_8859-9:1989
|
||||
iso-ir-{58,100,101,109,110,126,127,138,144,148,149,157}
|
||||
koi{,8,8-r,8-ru,8-u,8_r} cskoi8r
|
||||
ks_c_5601-{1987,1989} ksc{,_}5691 csksc56011987
|
||||
latin{1..6} l{{1..6},9}
|
||||
shift{-,_}jis csshiftjis {,x-}sjis ms_kanji ms932
|
||||
utf{,-}8 utf-16{,be,le} unicode-1-1-utf-8
|
||||
windows-{31j,874,949,125{0..8}} dos-874 tis-620 ansi_x3.4-1968
|
||||
x-user-defined auto
|
||||
)
|
||||
|
||||
_wanted rg-encodings expl 'encoding' compadd -a "${@}" - _encodings
|
||||
}
|
||||
|
||||
# Complete file types
|
||||
_rg_types() {
|
||||
local -a expl
|
||||
local -aU _types
|
||||
|
||||
_types=( ${${(f)"$( _call_program rg-types rg --type-list )"}%%:*} )
|
||||
|
||||
_wanted rg-types expl 'file type' compadd -a "${@}" - _types
|
||||
}
|
||||
|
||||
_rg "${@}"
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright (c) 2011 Github zsh-users - http://github.com/zsh-users
|
||||
# All rights reserved.
|
||||
@@ -39,99 +245,6 @@
|
||||
#
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
local context state state_descr line
|
||||
local -A opt_args
|
||||
local -i ret=1
|
||||
|
||||
local -a common_options
|
||||
common_options=(
|
||||
'(-a --text)'{-a,--text}'[search binary files as if they were text]'
|
||||
'(-c, --count)'{-c,--count}'[only show count of matches for each file]'
|
||||
'--color=[whether to use coloring in match]::when:( always never auto )'
|
||||
'(1)*'{-e,--regexp=}'[specify pattern]:pattern'
|
||||
'(-E --encoding)'{-E,--encoding=}'[specify the text encoding of files to search.]:encoding'
|
||||
'(-F --fixed-strings)'{-F,--fixed-strings}'[treat the pattern as a literal string instead of a regular expression]'
|
||||
'*'{-g,--glob=}'[include or exclude files for searching that match the given glob]:glob'
|
||||
'(-h --help)'{-h,--help}'[prints help information]'
|
||||
'(-i -s -S --ignore-case --case-sensitive --smart-case)'{-i,--ignore-case}'[case insensitive search]'
|
||||
'(-n -N --line-number --no-line-number)'{-n,--line-number}'[show line numbers]'
|
||||
'(-n -N --line-number --no-line-number)'{-N,--no-line-number}'[suppress line numbers]'
|
||||
'(-q --quiet)'{-q,--quiet}'[do not print anything to stdout]'
|
||||
'(-T --type-not)*'{-t,--type=}'[only search files matching specified type]: :->type'
|
||||
'(-t --type)*'{-T,--type-not=}'[do not search files matching type]: :->type'
|
||||
'*'{-u,--unrestricted}'[reduce the level of "smart" searching]'
|
||||
'(-v --invert-match)'{-v,--invert-match}'[invert matching]'
|
||||
'(-w --word-regexp)'{-w,--word-regexp}'[only show matches surrounded by word boundaries]'
|
||||
)
|
||||
|
||||
local -a less_common_options
|
||||
less_common_options=(
|
||||
'(-A -C --after-context --context)'{-A,--after-context=}'[specify number of lines to show after each match]:number of lines'
|
||||
'(-B -C --before-context --context)'{-B,--before-context=}'[specify number of lines to show before each match]:number of lines'
|
||||
'(-A -B -C --after-context --before-context --context)'{-C,--context=}'[specify number of lines to show before and after each match]:number of lines'
|
||||
'*--colors=[configure color settings and styles]:spec'
|
||||
'--column[show column numbers in output]'
|
||||
'--context-separator=[the string used to separate non-continuous context lines in the output]:separator string'
|
||||
'--debug[show debug message]'
|
||||
'--dfa-size-limit=[the upper size limit of the generated dfa]:size'
|
||||
"--file=[search for patterns from the given file]:file:_files"
|
||||
"--ignore-file=[search additional ignore files]:file:_files"
|
||||
"--files[print each file that would be searched (but don't search)]"
|
||||
'(-l --files-with-matches)'{-l,--files-with-matches}'[only show path of each file with matches]'
|
||||
'(-H --with-filename --no-filename)'{-H,--with-filename}'[prefix each match with the file name that contains it]'
|
||||
'(-H --with-filename)--no-filename[never show the file name for a match]'
|
||||
'(-p --no-heading --pretty --vimgrep)--heading[show the file name above clusters of matches from each file]'
|
||||
"(-p --heading --pretty --vimgrep)--no-heading[don't show any file name heading]"
|
||||
'--hidden[search hidden directories and files]'
|
||||
'(-L --follow)'{-L,--follow}'[follow symlinks]'
|
||||
'(-M --max-columns)'{-M,--max-columns=}"[don't print lines longer than this limit in bytes]:number"
|
||||
'(-m --max-count)'{-m,--max-count=}'[only show count of matches for each file]:number'
|
||||
'--max-filesize=[ignore files larger than NUM in size]:size'
|
||||
'--maxdepth[descend at most N directories below the command line arguments]:depth'
|
||||
'(--no-mmap)--mmap[search using memory maps when possible]'
|
||||
'--no-messages[suppress all error messages]'
|
||||
'(--mmap)--no-mmap[never use memory maps, even when they might be faster]'
|
||||
"(--no-ignore-parent)--no-ignore[don't respect ignore files]"
|
||||
"--no-ignore-parent[don't respect ignore files in parent directories]"
|
||||
"--no-ignore-vcs[don't respect version control ignore files]"
|
||||
'(-0 --null)'{-0,--null}'[print NUL byte after file names]'
|
||||
'--path-separator=[path separator to use when printing file paths]'
|
||||
'(-p --heading --no-heading --pretty --vimgrep)'{-p,--pretty}'[alias for --color=always --heading -n]'
|
||||
'--regex-size-limit=[the upper size limit of the compiled regex]:size'
|
||||
'(-r --replace)'{-r,--replace=}'[replace matches with string given]:replace string'
|
||||
'(-i -s -S --ignore-case --case-sensitive --smart-case)'{-s,--case-sensitive}'[search case sensitively]'
|
||||
'(-i -s -S --ignore-case --case-sensitive --smart-case)'{-S,--smart-case}'[search case insensitively if the pattern is all lowercase]'
|
||||
'(-j --threads)'{-j,--threads=}'[the approximate number of threads to use]:number of threads'
|
||||
'(-v --version)'{-V,--version}'[print version information]'
|
||||
'(-p --heading --no-heading --pretty)--vimgrep[show results with every match on its own line, including line numbers and column numbers]'
|
||||
)
|
||||
|
||||
local -a file_type_management_options
|
||||
file_type_management_options=(
|
||||
'--type-list[show all supported file types and their associated globs]'
|
||||
'*--type-add=[add a new glob for a particular file type]:type'
|
||||
'*--type-clear=[clear the file type globs previously defined for specified type]: :->type'
|
||||
)
|
||||
|
||||
_arguments -S -s : \
|
||||
$common_options \
|
||||
$less_common_options \
|
||||
$file_type_management_options \
|
||||
'(-e --regexp)1: :_guard "^--*" pattern' \
|
||||
'*:file:_files' \
|
||||
&& ret=0
|
||||
|
||||
case "$state" in
|
||||
type)
|
||||
local -U types
|
||||
types=( ${${(f)"$(_call_program types rg --type-list)"}%%:*} )
|
||||
|
||||
_describe -t types "type" types && ret=0
|
||||
;;
|
||||
esac
|
||||
|
||||
return ret
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# coding: utf-8-unix
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#!/bin/sh
|
||||
#!/bin/sh -e
|
||||
|
||||
pandoc -s -t man rg.1.md -o rg.1
|
||||
sed -i 's/\.TH.*/.TH "rg" "1"/g' rg.1
|
||||
sed -i.bak 's/\.TH.*/.TH "rg" "1"/g' rg.1
|
||||
rm -f rg.1.bak # BSD `sed` requires the creation of a back-up file
|
||||
|
26
doc/rg.1
26
doc/rg.1
@@ -29,6 +29,10 @@ time searching.
|
||||
Because of this, features like backreferences and arbitrary lookaround
|
||||
are not supported.
|
||||
.PP
|
||||
Note that ripgrep may abort unexpectedly when using default settings if
|
||||
it searches a file that is simultaneously truncated.
|
||||
This behavior can be avoided by passing the \-\-no\-mmap flag.
|
||||
.PP
|
||||
Project home page: https://github.com/BurntSushi/ripgrep
|
||||
.SH COMMON OPTIONS
|
||||
.TP
|
||||
@@ -45,7 +49,10 @@ Only show count of line matches for each file.
|
||||
.B \-\-color \f[I]WHEN\f[]
|
||||
Whether to use color in the output.
|
||||
Valid values are never, auto, always or ansi.
|
||||
[default: auto]
|
||||
The default is auto.
|
||||
When always is used, coloring is attempted based on your environment.
|
||||
When ansi is used, coloring is forcefully done using ANSI escape color
|
||||
codes.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
@@ -156,6 +163,12 @@ Only show matches surrounded by word boundaries.
|
||||
This is equivalent to putting \\b before and after the search pattern.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
.B \-x, \-\-line\-regexp
|
||||
Only show matches surrounded by line boundaries.
|
||||
This is equivalent to putting ^...$ around the search pattern.
|
||||
.RS
|
||||
.RE
|
||||
.SH LESS COMMON OPTIONS
|
||||
.TP
|
||||
.B \-A, \-\-after\-context \f[I]NUM\f[]
|
||||
@@ -293,6 +306,17 @@ Search hidden directories and files.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
.B \-\-iglob \f[I]GLOB\f[] ...
|
||||
Include or exclude files/directories case insensitively.
|
||||
This always overrides any other ignore logic if there is a conflict, but
|
||||
is otherwise applied in addition to ignore files (e.g., .gitignore or
|
||||
\&.ignore).
|
||||
Multiple glob flags may be used.
|
||||
Globbing rules match .gitignore globs.
|
||||
Precede a glob with a \[aq]!\[aq] to exclude it.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
.B \-\-ignore\-file \f[I]FILE\f[] ...
|
||||
Specify additional ignore files for filtering file paths.
|
||||
Ignore files should be in the gitignore format and are matched relative
|
||||
|
19
doc/rg.1.md
19
doc/rg.1.md
@@ -25,6 +25,10 @@ ripgrep's regex engine uses finite automata and guarantees linear time
|
||||
searching. Because of this, features like backreferences and arbitrary
|
||||
lookaround are not supported.
|
||||
|
||||
Note that ripgrep may abort unexpectedly when using default settings if it
|
||||
searches a file that is simultaneously truncated. This behavior can be avoided
|
||||
by passing the --no-mmap flag.
|
||||
|
||||
Project home page: https://github.com/BurntSushi/ripgrep
|
||||
|
||||
# COMMON OPTIONS
|
||||
@@ -37,7 +41,9 @@ Project home page: https://github.com/BurntSushi/ripgrep
|
||||
|
||||
--color *WHEN*
|
||||
: Whether to use color in the output. Valid values are never, auto, always or
|
||||
ansi. [default: auto]
|
||||
ansi. The default is auto. When always is used, coloring is attempted based
|
||||
on your environment. When ansi is used, coloring is forcefully done using
|
||||
ANSI escape color codes.
|
||||
|
||||
-e, --regexp *PATTERN* ...
|
||||
: Use PATTERN to search. This option can be provided multiple times, where all
|
||||
@@ -105,6 +111,10 @@ Project home page: https://github.com/BurntSushi/ripgrep
|
||||
: Only show matches surrounded by word boundaries. This is equivalent to
|
||||
putting \\b before and after the search pattern.
|
||||
|
||||
-x, --line-regexp
|
||||
: Only show matches surrounded by line boundaries. This is equivalent to
|
||||
putting ^...$ around the search pattern.
|
||||
|
||||
# LESS COMMON OPTIONS
|
||||
|
||||
-A, --after-context *NUM*
|
||||
@@ -192,6 +202,13 @@ Project home page: https://github.com/BurntSushi/ripgrep
|
||||
: Search hidden directories and files. (Hidden directories and files are
|
||||
skipped by default.)
|
||||
|
||||
--iglob *GLOB* ...
|
||||
: Include or exclude files/directories case insensitively. This always
|
||||
overrides any other ignore logic if there is a conflict, but is otherwise
|
||||
applied in addition to ignore files (e.g., .gitignore or .ignore). Multiple
|
||||
glob flags may be used. Globbing rules match .gitignore globs. Precede a
|
||||
glob with a '!' to exclude it.
|
||||
|
||||
--ignore-file *FILE* ...
|
||||
: Specify additional ignore files for filtering file paths.
|
||||
Ignore files should be in the gitignore format and are matched
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ignore"
|
||||
version = "0.2.0" #:version
|
||||
version = "0.2.2" #:version
|
||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||
description = """
|
||||
A fast library for efficiently matching ignore files such as `.gitignore`
|
||||
|
@@ -20,7 +20,7 @@ Add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
ignore = "0.1"
|
||||
ignore = "0.2"
|
||||
```
|
||||
|
||||
and this to your crate root:
|
||||
|
@@ -169,8 +169,8 @@ impl Gitignore {
|
||||
self.num_whitelists
|
||||
}
|
||||
|
||||
/// Returns whether the given file path matched a pattern in this gitignore
|
||||
/// matcher.
|
||||
/// Returns whether the given path (file or directory) matched a pattern in
|
||||
/// this gitignore matcher.
|
||||
///
|
||||
/// `is_dir` should be true if the path refers to a directory and false
|
||||
/// otherwise.
|
||||
@@ -191,6 +191,48 @@ impl Gitignore {
|
||||
self.matched_stripped(self.strip(path.as_ref()), is_dir)
|
||||
}
|
||||
|
||||
/// Returns whether the given path (file or directory, and expected to be
|
||||
/// under the root) or any of its parent directories (up to the root)
|
||||
/// matched a pattern in this gitignore matcher.
|
||||
///
|
||||
/// NOTE: This method is more expensive than walking the directory hierarchy
|
||||
/// top-to-bottom and matching the entries. But, is easier to use in cases
|
||||
/// when a list of paths are available without a hierarchy.
|
||||
///
|
||||
/// `is_dir` should be true if the path refers to a directory and false
|
||||
/// otherwise.
|
||||
///
|
||||
/// The given path is matched relative to the path given when building
|
||||
/// the matcher. Specifically, before matching `path`, its prefix (as
|
||||
/// determined by a common suffix of the directory containing this
|
||||
/// gitignore) is stripped. If there is no common suffix/prefix overlap,
|
||||
/// then `path` is assumed to be relative to this matcher.
|
||||
pub fn matched_path_or_any_parents<P: AsRef<Path>>(
|
||||
&self,
|
||||
path: P,
|
||||
is_dir: bool,
|
||||
) -> Match<&Glob> {
|
||||
if self.is_empty() {
|
||||
return Match::None;
|
||||
}
|
||||
let mut path = self.strip(path.as_ref());
|
||||
debug_assert!(
|
||||
!path.has_root(),
|
||||
"path is expect to be under the root"
|
||||
);
|
||||
match self.matched_stripped(path, is_dir) {
|
||||
Match::None => (), // walk up
|
||||
a_match => return a_match,
|
||||
}
|
||||
while let Some(parent) = path.parent() {
|
||||
match self.matched_stripped(parent, /* is_dir */ true) {
|
||||
Match::None => path = parent, // walk up
|
||||
a_match => return a_match,
|
||||
}
|
||||
}
|
||||
Match::None
|
||||
}
|
||||
|
||||
/// Like matched, but takes a path that has already been stripped.
|
||||
fn matched_stripped<P: AsRef<Path>>(
|
||||
&self,
|
||||
@@ -254,6 +296,7 @@ pub struct GitignoreBuilder {
|
||||
builder: GlobSetBuilder,
|
||||
root: PathBuf,
|
||||
globs: Vec<Glob>,
|
||||
case_insensitive: bool,
|
||||
}
|
||||
|
||||
impl GitignoreBuilder {
|
||||
@@ -269,6 +312,7 @@ impl GitignoreBuilder {
|
||||
builder: GlobSetBuilder::new(),
|
||||
root: strip_prefix("./", root).unwrap_or(root).to_path_buf(),
|
||||
globs: vec![],
|
||||
case_insensitive: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -424,6 +468,7 @@ impl GitignoreBuilder {
|
||||
let parsed = try!(
|
||||
GlobBuilder::new(&glob.actual)
|
||||
.literal_separator(literal_separator)
|
||||
.case_insensitive(self.case_insensitive)
|
||||
.build()
|
||||
.map_err(|err| {
|
||||
Error::Glob {
|
||||
@@ -435,6 +480,16 @@ impl GitignoreBuilder {
|
||||
self.globs.push(glob);
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Toggle whether the globs should be matched case insensitively or not.
|
||||
///
|
||||
/// This is disabled by default.
|
||||
pub fn case_insensitive(
|
||||
&mut self, yes: bool
|
||||
) -> Result<&mut GitignoreBuilder, Error> {
|
||||
self.case_insensitive = yes;
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the file path of the current environment's global gitignore file.
|
||||
@@ -617,4 +672,21 @@ mod tests {
|
||||
fn regression_106() {
|
||||
gi_from_str("/", " ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn case_insensitive() {
|
||||
let gi = GitignoreBuilder::new(ROOT)
|
||||
.case_insensitive(true).unwrap()
|
||||
.add_str(None, "*.html").unwrap()
|
||||
.build().unwrap();
|
||||
assert!(gi.matched("foo.html", false).is_ignore());
|
||||
assert!(gi.matched("foo.HTML", false).is_ignore());
|
||||
assert!(!gi.matched("foo.htm", false).is_ignore());
|
||||
assert!(!gi.matched("foo.HTM", false).is_ignore());
|
||||
}
|
||||
|
||||
ignored!(cs1, ROOT, "*.html", "foo.html");
|
||||
not_ignored!(cs2, ROOT, "*.html", "foo.HTML");
|
||||
not_ignored!(cs3, ROOT, "*.html", "foo.htm");
|
||||
not_ignored!(cs4, ROOT, "*.html", "foo.HTM");
|
||||
}
|
||||
|
@@ -137,6 +137,16 @@ impl OverrideBuilder {
|
||||
try!(self.builder.add_line(None, glob));
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Toggle whether the globs should be matched case insensitively or not.
|
||||
///
|
||||
/// This is disabled by default.
|
||||
pub fn case_insensitive(
|
||||
&mut self, yes: bool
|
||||
) -> Result<&mut OverrideBuilder, Error> {
|
||||
try!(self.builder.case_insensitive(yes));
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -220,4 +230,27 @@ mod tests {
|
||||
let ov = ov(&["!/bar"]);
|
||||
assert!(ov.matched("./foo/bar", false).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn case_insensitive() {
|
||||
let ov = OverrideBuilder::new(ROOT)
|
||||
.case_insensitive(true).unwrap()
|
||||
.add("*.html").unwrap()
|
||||
.build().unwrap();
|
||||
assert!(ov.matched("foo.html", false).is_whitelist());
|
||||
assert!(ov.matched("foo.HTML", false).is_whitelist());
|
||||
assert!(ov.matched("foo.htm", false).is_ignore());
|
||||
assert!(ov.matched("foo.HTM", false).is_ignore());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_case_sensitive() {
|
||||
let ov = OverrideBuilder::new(ROOT)
|
||||
.add("*.html").unwrap()
|
||||
.build().unwrap();
|
||||
assert!(ov.matched("foo.html", false).is_whitelist());
|
||||
assert!(ov.matched("foo.HTML", false).is_ignore());
|
||||
assert!(ov.matched("foo.htm", false).is_ignore());
|
||||
assert!(ov.matched("foo.HTM", false).is_ignore());
|
||||
}
|
||||
}
|
||||
|
@@ -101,7 +101,9 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
|
||||
("asciidoc", &["*.adoc", "*.asc", "*.asciidoc"]),
|
||||
("asm", &["*.asm", "*.s", "*.S"]),
|
||||
("awk", &["*.awk"]),
|
||||
("bitbake", &["*.bb", "*.bbappend", "*.bbclass", "*.conf", "*.inc"]),
|
||||
("c", &["*.c", "*.h", "*.H"]),
|
||||
("cabal", &["*.cabal"]),
|
||||
("cbor", &["*.cbor"]),
|
||||
("ceylon", &["*.ceylon"]),
|
||||
("clojure", &["*.clj", "*.cljc", "*.cljs", "*.cljx"]),
|
||||
@@ -144,13 +146,14 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
|
||||
("json", &["*.json"]),
|
||||
("jsonl", &["*.jsonl"]),
|
||||
("julia", &["*.jl"]),
|
||||
("jl", &["*.jl"]),
|
||||
("kotlin", &["*.kt", "*.kts"]),
|
||||
("less", &["*.less"]),
|
||||
("lisp", &["*.el", "*.jl", "*.lisp", "*.lsp", "*.sc", "*.scm"]),
|
||||
("log", &["*.log"]),
|
||||
("lua", &["*.lua"]),
|
||||
("m4", &["*.ac", "*.m4"]),
|
||||
("make", &["gnumakefile", "Gnumakefile", "makefile", "Makefile", "*.mk", "*.mak"]),
|
||||
("make", &["gnumakefile", "Gnumakefile", "GNUmakefile", "makefile", "Makefile", "*.mk", "*.mak"]),
|
||||
("markdown", &["*.markdown", "*.md", "*.mdown", "*.mkdn"]),
|
||||
("md", &["*.markdown", "*.md", "*.mdown", "*.mkdn"]),
|
||||
("matlab", &["*.m"]),
|
||||
@@ -169,7 +172,7 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
|
||||
("pod", &["*.pod"]),
|
||||
("ps", &["*.cdxml", "*.ps1", "*.ps1xml", "*.psd1", "*.psm1"]),
|
||||
("py", &["*.py"]),
|
||||
("qmake", &["*.pro", "*.pri"]),
|
||||
("qmake", &["*.pro", "*.pri", "*.prf"]),
|
||||
("readme", &["README*", "*README"]),
|
||||
("r", &["*.R", "*.r", "*.Rmd", "*.Rnw"]),
|
||||
("rdoc", &["*.rdoc"]),
|
||||
@@ -202,7 +205,6 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
|
||||
("xml", &["*.xml"]),
|
||||
("yacc", &["*.y"]),
|
||||
("yaml", &["*.yaml", "*.yml"]),
|
||||
("yocto", &["*.bb", "*.bbappend", "*.bbclass"]),
|
||||
("zsh", &["zshenv", ".zshenv", "zprofile", ".zprofile", "zshrc", ".zshrc", "zlogin", ".zlogin", "zlogout", ".zlogout", "*.zsh"]),
|
||||
];
|
||||
|
||||
|
@@ -380,16 +380,16 @@ impl DirEntryRaw {
|
||||
/// is: `.ignore`, `.gitignore`, `.git/info/exclude`, global gitignore and
|
||||
/// finally explicitly added ignore files. Note that precedence between
|
||||
/// different types of ignore files is not impacted by the directory hierarchy;
|
||||
/// any `.ignore` file overrides all `.gitignore` files. Within each
|
||||
/// precedence level, more nested ignore files have a higher precedence over
|
||||
/// less nested ignore files.
|
||||
/// * Third, if the previous step yields an ignore match, than all matching
|
||||
/// is stopped and the path is skipped.. If it yields a whitelist match, then
|
||||
/// process continues. A whitelist match can be overridden by a later matcher.
|
||||
/// any `.ignore` file overrides all `.gitignore` files. Within each precedence
|
||||
/// level, more nested ignore files have a higher precedence than less nested
|
||||
/// ignore files.
|
||||
/// * Third, if the previous step yields an ignore match, then all matching
|
||||
/// is stopped and the path is skipped. If it yields a whitelist match, then
|
||||
/// matching continues. A whitelist match can be overridden by a later matcher.
|
||||
/// * Fourth, unless the path is a directory, the file type matcher is run on
|
||||
/// the path. As above, if it's an ignore match, then all matching is stopped
|
||||
/// and the path is skipped. If it's a whitelist match, then matching
|
||||
/// continues.
|
||||
/// the path. As above, if it yields an ignore match, then all matching is
|
||||
/// stopped and the path is skipped. If it yields a whitelist match, then
|
||||
/// matching continues.
|
||||
/// * Fifth, if the path hasn't been whitelisted and it is hidden, then the
|
||||
/// path is skipped.
|
||||
/// * Sixth, unless the path is a directory, the size of the file is compared
|
||||
@@ -610,6 +610,8 @@ impl WalkBuilder {
|
||||
/// does not exist or does not specify `core.excludesFile`, then
|
||||
/// `$XDG_CONFIG_HOME/git/ignore` is read. If `$XDG_CONFIG_HOME` is not
|
||||
/// set or is empty, then `$HOME/.config/git/ignore` is used instead.
|
||||
///
|
||||
/// This is enabled by default.
|
||||
pub fn git_global(&mut self, yes: bool) -> &mut WalkBuilder {
|
||||
self.ig_builder.git_global(yes);
|
||||
self
|
||||
|
@@ -0,0 +1,216 @@
|
||||
# Based on https://github.com/behnam/gitignore-test/blob/master/.gitignore
|
||||
|
||||
### file in root
|
||||
|
||||
# MATCH /file_root_1
|
||||
file_root_00
|
||||
|
||||
# NO_MATCH
|
||||
file_root_01/
|
||||
|
||||
# NO_MATCH
|
||||
file_root_02/*
|
||||
|
||||
# NO_MATCH
|
||||
file_root_03/**
|
||||
|
||||
|
||||
# MATCH /file_root_10
|
||||
/file_root_10
|
||||
|
||||
# NO_MATCH
|
||||
/file_root_11/
|
||||
|
||||
# NO_MATCH
|
||||
/file_root_12/*
|
||||
|
||||
# NO_MATCH
|
||||
/file_root_13/**
|
||||
|
||||
|
||||
# NO_MATCH
|
||||
*/file_root_20
|
||||
|
||||
# NO_MATCH
|
||||
*/file_root_21/
|
||||
|
||||
# NO_MATCH
|
||||
*/file_root_22/*
|
||||
|
||||
# NO_MATCH
|
||||
*/file_root_23/**
|
||||
|
||||
|
||||
# MATCH /file_root_30
|
||||
**/file_root_30
|
||||
|
||||
# NO_MATCH
|
||||
**/file_root_31/
|
||||
|
||||
# NO_MATCH
|
||||
**/file_root_32/*
|
||||
|
||||
# NO_MATCH
|
||||
**/file_root_33/**
|
||||
|
||||
|
||||
### file in sub-dir
|
||||
|
||||
# MATCH /parent_dir/file_deep_1
|
||||
file_deep_00
|
||||
|
||||
# NO_MATCH
|
||||
file_deep_01/
|
||||
|
||||
# NO_MATCH
|
||||
file_deep_02/*
|
||||
|
||||
# NO_MATCH
|
||||
file_deep_03/**
|
||||
|
||||
|
||||
# NO_MATCH
|
||||
/file_deep_10
|
||||
|
||||
# NO_MATCH
|
||||
/file_deep_11/
|
||||
|
||||
# NO_MATCH
|
||||
/file_deep_12/*
|
||||
|
||||
# NO_MATCH
|
||||
/file_deep_13/**
|
||||
|
||||
|
||||
# MATCH /parent_dir/file_deep_20
|
||||
*/file_deep_20
|
||||
|
||||
# NO_MATCH
|
||||
*/file_deep_21/
|
||||
|
||||
# NO_MATCH
|
||||
*/file_deep_22/*
|
||||
|
||||
# NO_MATCH
|
||||
*/file_deep_23/**
|
||||
|
||||
|
||||
# MATCH /parent_dir/file_deep_30
|
||||
**/file_deep_30
|
||||
|
||||
# NO_MATCH
|
||||
**/file_deep_31/
|
||||
|
||||
# NO_MATCH
|
||||
**/file_deep_32/*
|
||||
|
||||
# NO_MATCH
|
||||
**/file_deep_33/**
|
||||
|
||||
|
||||
### dir in root
|
||||
|
||||
# MATCH /dir_root_00
|
||||
dir_root_00
|
||||
|
||||
# MATCH /dir_root_01
|
||||
dir_root_01/
|
||||
|
||||
# MATCH /dir_root_02
|
||||
dir_root_02/*
|
||||
|
||||
# MATCH /dir_root_03
|
||||
dir_root_03/**
|
||||
|
||||
|
||||
# MATCH /dir_root_10
|
||||
/dir_root_10
|
||||
|
||||
# MATCH /dir_root_11
|
||||
/dir_root_11/
|
||||
|
||||
# MATCH /dir_root_12
|
||||
/dir_root_12/*
|
||||
|
||||
# MATCH /dir_root_13
|
||||
/dir_root_13/**
|
||||
|
||||
|
||||
# NO_MATCH
|
||||
*/dir_root_20
|
||||
|
||||
# NO_MATCH
|
||||
*/dir_root_21/
|
||||
|
||||
# NO_MATCH
|
||||
*/dir_root_22/*
|
||||
|
||||
# NO_MATCH
|
||||
*/dir_root_23/**
|
||||
|
||||
|
||||
# MATCH /dir_root_30
|
||||
**/dir_root_30
|
||||
|
||||
# MATCH /dir_root_31
|
||||
**/dir_root_31/
|
||||
|
||||
# MATCH /dir_root_32
|
||||
**/dir_root_32/*
|
||||
|
||||
# MATCH /dir_root_33
|
||||
**/dir_root_33/**
|
||||
|
||||
|
||||
### dir in sub-dir
|
||||
|
||||
# MATCH /parent_dir/dir_deep_00
|
||||
dir_deep_00
|
||||
|
||||
# MATCH /parent_dir/dir_deep_01
|
||||
dir_deep_01/
|
||||
|
||||
# NO_MATCH
|
||||
dir_deep_02/*
|
||||
|
||||
# NO_MATCH
|
||||
dir_deep_03/**
|
||||
|
||||
|
||||
# NO_MATCH
|
||||
/dir_deep_10
|
||||
|
||||
# NO_MATCH
|
||||
/dir_deep_11/
|
||||
|
||||
# NO_MATCH
|
||||
/dir_deep_12/*
|
||||
|
||||
# NO_MATCH
|
||||
/dir_deep_13/**
|
||||
|
||||
|
||||
# MATCH /parent_dir/dir_deep_20
|
||||
*/dir_deep_20
|
||||
|
||||
# MATCH /parent_dir/dir_deep_21
|
||||
*/dir_deep_21/
|
||||
|
||||
# MATCH /parent_dir/dir_deep_22
|
||||
*/dir_deep_22/*
|
||||
|
||||
# MATCH /parent_dir/dir_deep_23
|
||||
*/dir_deep_23/**
|
||||
|
||||
|
||||
# MATCH /parent_dir/dir_deep_30
|
||||
**/dir_deep_30
|
||||
|
||||
# MATCH /parent_dir/dir_deep_31
|
||||
**/dir_deep_31/
|
||||
|
||||
# MATCH /parent_dir/dir_deep_32
|
||||
**/dir_deep_32/*
|
||||
|
||||
# MATCH /parent_dir/dir_deep_33
|
||||
**/dir_deep_33/**
|
297
ignore/tests/gitignore_matched_path_or_any_parents_tests.rs
Normal file
297
ignore/tests/gitignore_matched_path_or_any_parents_tests.rs
Normal file
@@ -0,0 +1,297 @@
|
||||
extern crate ignore;
|
||||
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use ignore::gitignore::{Gitignore, GitignoreBuilder};
|
||||
|
||||
|
||||
const IGNORE_FILE: &'static str = "tests/gitignore_matched_path_or_any_parents_tests.gitignore";
|
||||
|
||||
|
||||
fn get_gitignore() -> Gitignore {
|
||||
let mut builder = GitignoreBuilder::new("ROOT");
|
||||
let error = builder.add(IGNORE_FILE);
|
||||
assert!(error.is_none(), "failed to open gitignore file");
|
||||
builder.build().unwrap()
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "path is expect to be under the root")]
|
||||
fn test_path_should_be_under_root() {
|
||||
let gitignore = get_gitignore();
|
||||
let path = "/tmp/some_file";
|
||||
gitignore.matched_path_or_any_parents(Path::new(path), false);
|
||||
assert!(false);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_files_in_root() {
|
||||
let gitignore = get_gitignore();
|
||||
let m = |path: &str| gitignore.matched_path_or_any_parents(Path::new(path), false);
|
||||
|
||||
// 0x
|
||||
assert!(m("ROOT/file_root_00").is_ignore());
|
||||
assert!(m("ROOT/file_root_01").is_none());
|
||||
assert!(m("ROOT/file_root_02").is_none());
|
||||
assert!(m("ROOT/file_root_03").is_none());
|
||||
|
||||
// 1x
|
||||
assert!(m("ROOT/file_root_10").is_ignore());
|
||||
assert!(m("ROOT/file_root_11").is_none());
|
||||
assert!(m("ROOT/file_root_12").is_none());
|
||||
assert!(m("ROOT/file_root_13").is_none());
|
||||
|
||||
// 2x
|
||||
assert!(m("ROOT/file_root_20").is_none());
|
||||
assert!(m("ROOT/file_root_21").is_none());
|
||||
assert!(m("ROOT/file_root_22").is_none());
|
||||
assert!(m("ROOT/file_root_23").is_none());
|
||||
|
||||
// 3x
|
||||
assert!(m("ROOT/file_root_30").is_ignore());
|
||||
assert!(m("ROOT/file_root_31").is_none());
|
||||
assert!(m("ROOT/file_root_32").is_none());
|
||||
assert!(m("ROOT/file_root_33").is_none());
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_files_in_deep() {
|
||||
let gitignore = get_gitignore();
|
||||
let m = |path: &str| gitignore.matched_path_or_any_parents(Path::new(path), false);
|
||||
|
||||
// 0x
|
||||
assert!(m("ROOT/parent_dir/file_deep_00").is_ignore());
|
||||
assert!(m("ROOT/parent_dir/file_deep_01").is_none());
|
||||
assert!(m("ROOT/parent_dir/file_deep_02").is_none());
|
||||
assert!(m("ROOT/parent_dir/file_deep_03").is_none());
|
||||
|
||||
// 1x
|
||||
assert!(m("ROOT/parent_dir/file_deep_10").is_none());
|
||||
assert!(m("ROOT/parent_dir/file_deep_11").is_none());
|
||||
assert!(m("ROOT/parent_dir/file_deep_12").is_none());
|
||||
assert!(m("ROOT/parent_dir/file_deep_13").is_none());
|
||||
|
||||
// 2x
|
||||
assert!(m("ROOT/parent_dir/file_deep_20").is_ignore());
|
||||
assert!(m("ROOT/parent_dir/file_deep_21").is_none());
|
||||
assert!(m("ROOT/parent_dir/file_deep_22").is_none());
|
||||
assert!(m("ROOT/parent_dir/file_deep_23").is_none());
|
||||
|
||||
// 3x
|
||||
assert!(m("ROOT/parent_dir/file_deep_30").is_ignore());
|
||||
assert!(m("ROOT/parent_dir/file_deep_31").is_none());
|
||||
assert!(m("ROOT/parent_dir/file_deep_32").is_none());
|
||||
assert!(m("ROOT/parent_dir/file_deep_33").is_none());
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_dirs_in_root() {
|
||||
let gitignore = get_gitignore();
|
||||
let m =
|
||||
|path: &str, is_dir: bool| gitignore.matched_path_or_any_parents(Path::new(path), is_dir);
|
||||
|
||||
// 00
|
||||
assert!(m("ROOT/dir_root_00", true).is_ignore());
|
||||
assert!(m("ROOT/dir_root_00/file", false).is_ignore());
|
||||
assert!(m("ROOT/dir_root_00/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/dir_root_00/child_dir/file", false).is_ignore());
|
||||
|
||||
// 01
|
||||
assert!(m("ROOT/dir_root_01", true).is_ignore());
|
||||
assert!(m("ROOT/dir_root_01/file", false).is_ignore());
|
||||
assert!(m("ROOT/dir_root_01/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/dir_root_01/child_dir/file", false).is_ignore());
|
||||
|
||||
// 02
|
||||
assert!(m("ROOT/dir_root_02", true).is_none()); // dir itself doesn't match
|
||||
assert!(m("ROOT/dir_root_02/file", false).is_ignore());
|
||||
assert!(m("ROOT/dir_root_02/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/dir_root_02/child_dir/file", false).is_ignore());
|
||||
|
||||
// 03
|
||||
assert!(m("ROOT/dir_root_03", true).is_none()); // dir itself doesn't match
|
||||
assert!(m("ROOT/dir_root_03/file", false).is_ignore());
|
||||
assert!(m("ROOT/dir_root_03/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/dir_root_03/child_dir/file", false).is_ignore());
|
||||
|
||||
// 10
|
||||
assert!(m("ROOT/dir_root_10", true).is_ignore());
|
||||
assert!(m("ROOT/dir_root_10/file", false).is_ignore());
|
||||
assert!(m("ROOT/dir_root_10/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/dir_root_10/child_dir/file", false).is_ignore());
|
||||
|
||||
// 11
|
||||
assert!(m("ROOT/dir_root_11", true).is_ignore());
|
||||
assert!(m("ROOT/dir_root_11/file", false).is_ignore());
|
||||
assert!(m("ROOT/dir_root_11/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/dir_root_11/child_dir/file", false).is_ignore());
|
||||
|
||||
// 12
|
||||
assert!(m("ROOT/dir_root_12", true).is_none()); // dir itself doesn't match
|
||||
assert!(m("ROOT/dir_root_12/file", false).is_ignore());
|
||||
assert!(m("ROOT/dir_root_12/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/dir_root_12/child_dir/file", false).is_ignore());
|
||||
|
||||
// 13
|
||||
assert!(m("ROOT/dir_root_13", true).is_none());
|
||||
assert!(m("ROOT/dir_root_13/file", false).is_ignore());
|
||||
assert!(m("ROOT/dir_root_13/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/dir_root_13/child_dir/file", false).is_ignore());
|
||||
|
||||
// 20
|
||||
assert!(m("ROOT/dir_root_20", true).is_none());
|
||||
assert!(m("ROOT/dir_root_20/file", false).is_none());
|
||||
assert!(m("ROOT/dir_root_20/child_dir", true).is_none());
|
||||
assert!(m("ROOT/dir_root_20/child_dir/file", false).is_none());
|
||||
|
||||
// 21
|
||||
assert!(m("ROOT/dir_root_21", true).is_none());
|
||||
assert!(m("ROOT/dir_root_21/file", false).is_none());
|
||||
assert!(m("ROOT/dir_root_21/child_dir", true).is_none());
|
||||
assert!(m("ROOT/dir_root_21/child_dir/file", false).is_none());
|
||||
|
||||
// 22
|
||||
assert!(m("ROOT/dir_root_22", true).is_none());
|
||||
assert!(m("ROOT/dir_root_22/file", false).is_none());
|
||||
assert!(m("ROOT/dir_root_22/child_dir", true).is_none());
|
||||
assert!(m("ROOT/dir_root_22/child_dir/file", false).is_none());
|
||||
|
||||
// 23
|
||||
assert!(m("ROOT/dir_root_23", true).is_none());
|
||||
assert!(m("ROOT/dir_root_23/file", false).is_none());
|
||||
assert!(m("ROOT/dir_root_23/child_dir", true).is_none());
|
||||
assert!(m("ROOT/dir_root_23/child_dir/file", false).is_none());
|
||||
|
||||
// 30
|
||||
assert!(m("ROOT/dir_root_30", true).is_ignore());
|
||||
assert!(m("ROOT/dir_root_30/file", false).is_ignore());
|
||||
assert!(m("ROOT/dir_root_30/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/dir_root_30/child_dir/file", false).is_ignore());
|
||||
|
||||
// 31
|
||||
assert!(m("ROOT/dir_root_31", true).is_ignore());
|
||||
assert!(m("ROOT/dir_root_31/file", false).is_ignore());
|
||||
assert!(m("ROOT/dir_root_31/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/dir_root_31/child_dir/file", false).is_ignore());
|
||||
|
||||
// 32
|
||||
assert!(m("ROOT/dir_root_32", true).is_none()); // dir itself doesn't match
|
||||
assert!(m("ROOT/dir_root_32/file", false).is_ignore());
|
||||
assert!(m("ROOT/dir_root_32/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/dir_root_32/child_dir/file", false).is_ignore());
|
||||
|
||||
// 33
|
||||
assert!(m("ROOT/dir_root_33", true).is_none()); // dir itself doesn't match
|
||||
assert!(m("ROOT/dir_root_33/file", false).is_ignore());
|
||||
assert!(m("ROOT/dir_root_33/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/dir_root_33/child_dir/file", false).is_ignore());
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_dirs_in_deep() {
|
||||
let gitignore = get_gitignore();
|
||||
let m =
|
||||
|path: &str, is_dir: bool| gitignore.matched_path_or_any_parents(Path::new(path), is_dir);
|
||||
|
||||
// 00
|
||||
assert!(m("ROOT/parent_dir/dir_deep_00", true).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_00/file", false).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_00/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_00/child_dir/file", false).is_ignore());
|
||||
|
||||
// 01
|
||||
assert!(m("ROOT/parent_dir/dir_deep_01", true).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_01/file", false).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_01/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_01/child_dir/file", false).is_ignore());
|
||||
|
||||
// 02
|
||||
assert!(m("ROOT/parent_dir/dir_deep_02", true).is_none()); // dir itself doesn't match
|
||||
assert!(m("ROOT/parent_dir/dir_deep_02/file", false).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_02/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_02/child_dir/file", false).is_ignore());
|
||||
|
||||
// 03
|
||||
assert!(m("ROOT/parent_dir/dir_deep_03", true).is_none()); // dir itself doesn't match
|
||||
assert!(m("ROOT/parent_dir/dir_deep_03/file", false).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_03/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_03/child_dir/file", false).is_ignore());
|
||||
|
||||
// 10
|
||||
assert!(m("ROOT/parent_dir/dir_deep_10", true).is_none());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_10/file", false).is_none());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_10/child_dir", true).is_none());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_10/child_dir/file", false).is_none());
|
||||
|
||||
// 11
|
||||
assert!(m("ROOT/parent_dir/dir_deep_11", true).is_none());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_11/file", false).is_none());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_11/child_dir", true).is_none());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_11/child_dir/file", false).is_none());
|
||||
|
||||
// 12
|
||||
assert!(m("ROOT/parent_dir/dir_deep_12", true).is_none());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_12/file", false).is_none());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_12/child_dir", true).is_none());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_12/child_dir/file", false).is_none());
|
||||
|
||||
// 13
|
||||
assert!(m("ROOT/parent_dir/dir_deep_13", true).is_none());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_13/file", false).is_none());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_13/child_dir", true).is_none());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_13/child_dir/file", false).is_none());
|
||||
|
||||
// 20
|
||||
assert!(m("ROOT/parent_dir/dir_deep_20", true).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_20/file", false).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_20/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_20/child_dir/file", false).is_ignore());
|
||||
|
||||
// 21
|
||||
assert!(m("ROOT/parent_dir/dir_deep_21", true).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_21/file", false).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_21/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_21/child_dir/file", false).is_ignore());
|
||||
|
||||
// 22
|
||||
assert!(m("ROOT/parent_dir/dir_deep_22", true).is_none()); // dir itself doesn't match
|
||||
assert!(m("ROOT/parent_dir/dir_deep_22/file", false).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_22/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_22/child_dir/file", false).is_ignore());
|
||||
|
||||
// 23
|
||||
assert!(m("ROOT/parent_dir/dir_deep_23", true).is_none()); // dir itself doesn't match
|
||||
assert!(m("ROOT/parent_dir/dir_deep_23/file", false).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_23/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_23/child_dir/file", false).is_ignore());
|
||||
|
||||
// 30
|
||||
assert!(m("ROOT/parent_dir/dir_deep_30", true).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_30/file", false).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_30/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_30/child_dir/file", false).is_ignore());
|
||||
|
||||
// 31
|
||||
assert!(m("ROOT/parent_dir/dir_deep_31", true).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_31/file", false).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_31/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_31/child_dir/file", false).is_ignore());
|
||||
|
||||
// 32
|
||||
assert!(m("ROOT/parent_dir/dir_deep_32", true).is_none()); // dir itself doesn't match
|
||||
assert!(m("ROOT/parent_dir/dir_deep_32/file", false).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_32/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_32/child_dir/file", false).is_ignore());
|
||||
|
||||
// 33
|
||||
assert!(m("ROOT/parent_dir/dir_deep_33", true).is_none()); // dir itself doesn't match
|
||||
assert!(m("ROOT/parent_dir/dir_deep_33/file", false).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_33/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_33/child_dir/file", false).is_ignore());
|
||||
}
|
@@ -1,9 +1,9 @@
|
||||
class RipgrepBin < Formula
|
||||
version '0.5.2'
|
||||
version '0.6.0'
|
||||
desc "Search tool like grep and The Silver Searcher."
|
||||
homepage "https://github.com/BurntSushi/ripgrep"
|
||||
url "https://github.com/BurntSushi/ripgrep/releases/download/#{version}/ripgrep-#{version}-x86_64-apple-darwin.tar.gz"
|
||||
sha256 "a0326a84af8517ad707d8c7cccba6e112de27822c391cc0937e4727fbb6c48f4"
|
||||
sha256 "2aeffe25322f886bcd846ac15b6574dc769865fb44b28a9b0c356f3004019685"
|
||||
|
||||
conflicts_with "ripgrep"
|
||||
|
||||
|
48
src/app.rs
48
src/app.rs
@@ -9,6 +9,10 @@ ripgrep's regex engine uses finite automata and guarantees linear time
|
||||
searching. Because of this, features like backreferences and arbitrary
|
||||
lookaround are not supported.
|
||||
|
||||
Note that ripgrep may abort unexpectedly when using default settings if it
|
||||
searches a file that is simultaneously truncated. This behavior can be avoided
|
||||
by passing the --no-mmap flag.
|
||||
|
||||
Project home page: https://github.com/BurntSushi/ripgrep
|
||||
|
||||
Use -h for short descriptions and --help for more details.";
|
||||
@@ -50,6 +54,7 @@ pub fn app() -> App<'static, 'static> {
|
||||
App::new("ripgrep")
|
||||
.author(crate_authors!())
|
||||
.version(crate_version!())
|
||||
.long_version(LONG_VERSION.as_str())
|
||||
.about(ABOUT)
|
||||
.max_term_width(100)
|
||||
.setting(AppSettings::UnifiedHelpMessage)
|
||||
@@ -89,6 +94,11 @@ pub fn app() -> App<'static, 'static> {
|
||||
.arg(flag("fixed-strings").short("F"))
|
||||
.arg(flag("glob").short("g")
|
||||
.takes_value(true).multiple(true).number_of_values(1)
|
||||
.set(ArgSettings::AllowLeadingHyphen)
|
||||
.value_name("GLOB"))
|
||||
.arg(flag("iglob")
|
||||
.takes_value(true).multiple(true).number_of_values(1)
|
||||
.set(ArgSettings::AllowLeadingHyphen)
|
||||
.value_name("GLOB"))
|
||||
.arg(flag("ignore-case").short("i"))
|
||||
.arg(flag("line-number").short("n"))
|
||||
@@ -103,7 +113,8 @@ pub fn app() -> App<'static, 'static> {
|
||||
.arg(flag("unrestricted").short("u")
|
||||
.multiple(true))
|
||||
.arg(flag("invert-match").short("v"))
|
||||
.arg(flag("word-regexp").short("w"))
|
||||
.arg(flag("word-regexp").short("w").overrides_with("line-regexp"))
|
||||
.arg(flag("line-regexp").short("x"))
|
||||
// Third, set up less common flags.
|
||||
.arg(flag("after-context").short("A")
|
||||
.value_name("NUM").takes_value(true)
|
||||
@@ -122,6 +133,7 @@ pub fn app() -> App<'static, 'static> {
|
||||
.arg(flag("debug"))
|
||||
.arg(flag("file").short("f")
|
||||
.value_name("FILE").takes_value(true)
|
||||
.set(ArgSettings::AllowLeadingHyphen)
|
||||
.multiple(true).number_of_values(1))
|
||||
.arg(flag("files-with-matches").short("l"))
|
||||
.arg(flag("files-without-match"))
|
||||
@@ -132,6 +144,7 @@ pub fn app() -> App<'static, 'static> {
|
||||
.arg(flag("hidden"))
|
||||
.arg(flag("ignore-file")
|
||||
.value_name("FILE").takes_value(true)
|
||||
.set(ArgSettings::AllowLeadingHyphen)
|
||||
.multiple(true).number_of_values(1))
|
||||
.arg(flag("follow").short("L"))
|
||||
.arg(flag("max-count")
|
||||
@@ -152,7 +165,9 @@ pub fn app() -> App<'static, 'static> {
|
||||
.arg(flag("only-matching").short("o").conflicts_with("replace"))
|
||||
.arg(flag("path-separator").value_name("SEPARATOR").takes_value(true))
|
||||
.arg(flag("pretty").short("p"))
|
||||
.arg(flag("replace").short("r").value_name("ARG").takes_value(true))
|
||||
.arg(flag("replace").short("r")
|
||||
.set(ArgSettings::AllowLeadingHyphen)
|
||||
.value_name("ARG").takes_value(true))
|
||||
.arg(flag("regex-size-limit")
|
||||
.value_name("NUM+SUFFIX?").takes_value(true))
|
||||
.arg(flag("case-sensitive").short("s"))
|
||||
@@ -191,6 +206,24 @@ macro_rules! doc {
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref LONG_VERSION: String = {
|
||||
let mut features: Vec<&str> = vec![];
|
||||
|
||||
if cfg!(feature = "avx-accel") {
|
||||
features.push("+AVX");
|
||||
} else {
|
||||
features.push("-AVX");
|
||||
}
|
||||
|
||||
if cfg!(feature = "simd-accel") {
|
||||
features.push("+SIMD");
|
||||
} else {
|
||||
features.push("-SIMD");
|
||||
}
|
||||
|
||||
format!("{}\n{}", crate_version!(), features.join(" "))
|
||||
};
|
||||
|
||||
static ref USAGES: HashMap<&'static str, Usage> = {
|
||||
let mut h = HashMap::new();
|
||||
doc!(h, "help-short",
|
||||
@@ -270,6 +303,13 @@ lazy_static! {
|
||||
ignore logic. Multiple glob flags may be used. Globbing \
|
||||
rules match .gitignore globs. Precede a glob with a ! \
|
||||
to exclude it.");
|
||||
doc!(h, "iglob",
|
||||
"Include or exclude files/directories case insensitively.",
|
||||
"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. Globs are matched case insensitively.");
|
||||
doc!(h, "ignore-case",
|
||||
"Case insensitive search.",
|
||||
"Case insensitive search. This is overridden by \
|
||||
@@ -313,6 +353,10 @@ lazy_static! {
|
||||
"Only show matches surrounded by word boundaries. This is \
|
||||
equivalent to putting \\b before and after all of the search \
|
||||
patterns.");
|
||||
doc!(h, "line-regexp",
|
||||
"Only show matches surrounded by line boundaries.",
|
||||
"Only show matches surrounded by line boundaries. This is \
|
||||
equivalent to putting ^...$ around all of the search patterns.");
|
||||
|
||||
doc!(h, "after-context",
|
||||
"Show NUM lines after each match.");
|
||||
|
32
src/args.rs
32
src/args.rs
@@ -427,7 +427,8 @@ impl<'a> ArgMatches<'a> {
|
||||
///
|
||||
/// Note that if -F/--fixed-strings is set, then all patterns will be
|
||||
/// escaped. Similarly, if -w/--word-regexp is set, then all patterns
|
||||
/// are surrounded by `\b`.
|
||||
/// are surrounded by `\b`, and if -x/--line-regexp is set, then all
|
||||
/// patterns are surrounded by `^...$`.
|
||||
///
|
||||
/// If any pattern is invalid UTF-8, then an error is returned.
|
||||
fn patterns(&self) -> Result<Vec<String>> {
|
||||
@@ -470,7 +471,7 @@ impl<'a> ArgMatches<'a> {
|
||||
Ok(pats)
|
||||
}
|
||||
|
||||
/// Converts an OsStr pattern to a String pattern, including word
|
||||
/// Converts an OsStr pattern to a String pattern, including line/word
|
||||
/// boundaries or escapes if applicable.
|
||||
///
|
||||
/// If the pattern is not valid UTF-8, then an error is returned.
|
||||
@@ -479,10 +480,12 @@ impl<'a> ArgMatches<'a> {
|
||||
Ok(self.str_pattern(s))
|
||||
}
|
||||
|
||||
/// Converts a &str pattern to a String pattern, including word
|
||||
/// Converts a &str pattern to a String pattern, including line/word
|
||||
/// boundaries or escapes if applicable.
|
||||
fn str_pattern(&self, pat: &str) -> String {
|
||||
let s = self.word_pattern(self.literal_pattern(pat.to_string()));
|
||||
let litpat = self.literal_pattern(pat.to_string());
|
||||
let s = self.line_pattern(self.word_pattern(litpat));
|
||||
|
||||
if s.is_empty() {
|
||||
self.empty_pattern()
|
||||
} else {
|
||||
@@ -511,6 +514,16 @@ impl<'a> ArgMatches<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the given pattern as a line pattern if the -x/--line-regexp
|
||||
/// flag is set. Otherwise, the pattern is returned unchanged.
|
||||
fn line_pattern(&self, pat: String) -> String {
|
||||
if self.is_present("line-regexp") {
|
||||
format!(r"^(?:{})$", pat)
|
||||
} else {
|
||||
pat
|
||||
}
|
||||
}
|
||||
|
||||
/// Empty pattern returns a pattern that is guaranteed to produce an empty
|
||||
/// regular expression that is valid in any position.
|
||||
fn empty_pattern(&self) -> String {
|
||||
@@ -692,7 +705,10 @@ impl<'a> ArgMatches<'a> {
|
||||
fn color_specs(&self) -> Result<ColorSpecs> {
|
||||
// Start with a default set of color specs.
|
||||
let mut specs = vec![
|
||||
#[cfg(unix)]
|
||||
"path:fg:magenta".parse().unwrap(),
|
||||
#[cfg(windows)]
|
||||
"path:fg:cyan".parse().unwrap(),
|
||||
"line:fg:green".parse().unwrap(),
|
||||
"match:fg:red".parse().unwrap(),
|
||||
"match:style:bold".parse().unwrap(),
|
||||
@@ -771,6 +787,14 @@ impl<'a> ArgMatches<'a> {
|
||||
for glob in self.values_of_lossy_vec("glob") {
|
||||
try!(ovr.add(&glob));
|
||||
}
|
||||
// this is smelly. In the long run it might make sense
|
||||
// to change overridebuilder to be like globsetbuilder
|
||||
// but this would be a breaking change to the ignore crate
|
||||
// so it is being shelved for now...
|
||||
try!(ovr.case_insensitive(true));
|
||||
for glob in self.values_of_lossy_vec("iglob") {
|
||||
try!(ovr.add(&glob));
|
||||
}
|
||||
ovr.build().map_err(From::from)
|
||||
}
|
||||
|
||||
|
@@ -8,7 +8,6 @@ extern crate grep;
|
||||
extern crate ignore;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate libc;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate memchr;
|
||||
|
@@ -576,7 +576,7 @@ pub struct ColorSpecs {
|
||||
/// Valid colors are `black`, `blue`, `green`, `red`, `cyan`, `magenta`,
|
||||
/// `yellow`, `white`.
|
||||
///
|
||||
/// Valid style instructions are `nobold` and `bold`.
|
||||
/// Valid style instructions are `nobold`, `bold`, `intense`, `nointense`.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Spec {
|
||||
ty: OutType,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "termcolor"
|
||||
version = "0.3.2" #:version
|
||||
version = "0.3.3" #:version
|
||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||
description = """
|
||||
A simple cross platform library for writing colored text to a terminal.
|
||||
|
@@ -202,15 +202,23 @@ enum IoStandardStream {
|
||||
impl IoStandardStream {
|
||||
fn new(sty: StandardStreamType) -> IoStandardStream {
|
||||
match sty {
|
||||
StandardStreamType::Stdout => IoStandardStream::Stdout(io::stdout()),
|
||||
StandardStreamType::Stderr => IoStandardStream::Stderr(io::stderr()),
|
||||
StandardStreamType::Stdout => {
|
||||
IoStandardStream::Stdout(io::stdout())
|
||||
}
|
||||
StandardStreamType::Stderr => {
|
||||
IoStandardStream::Stderr(io::stderr())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lock(&self) -> IoStandardStreamLock {
|
||||
match *self {
|
||||
IoStandardStream::Stdout(ref s) => IoStandardStreamLock::StdoutLock(s.lock()),
|
||||
IoStandardStream::Stderr(ref s) => IoStandardStreamLock::StderrLock(s.lock()),
|
||||
IoStandardStream::Stdout(ref s) => {
|
||||
IoStandardStreamLock::StdoutLock(s.lock())
|
||||
}
|
||||
IoStandardStream::Stderr(ref s) => {
|
||||
IoStandardStreamLock::StderrLock(s.lock())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -257,7 +265,7 @@ impl<'a> io::Write for IoStandardStreamLock<'a> {
|
||||
/// Satisfies `io::Write` and `WriteColor`, and supports optional coloring
|
||||
/// to either of the standard output streams, stdout and stderr.
|
||||
pub struct StandardStream {
|
||||
wtr: LossyStandardStream<WriterInner<'static, IoStandardStream>>,
|
||||
wtr: LossyStandardStream<WriterInner<IoStandardStream>>,
|
||||
}
|
||||
|
||||
/// `StandardStreamLock` is a locked reference to a `StandardStream`.
|
||||
@@ -265,14 +273,24 @@ pub struct StandardStream {
|
||||
/// This implements the `io::Write` and `WriteColor` traits, and is constructed
|
||||
/// via the `Write::lock` method.
|
||||
///
|
||||
/// The lifetime `'a` refers to the lifetime of the corresponding `StandardStream`.
|
||||
/// The lifetime `'a` refers to the lifetime of the corresponding
|
||||
/// `StandardStream`.
|
||||
pub struct StandardStreamLock<'a> {
|
||||
wtr: LossyStandardStream<WriterInner<'a, IoStandardStreamLock<'a>>>,
|
||||
wtr: LossyStandardStream<WriterInnerLock<'a, IoStandardStreamLock<'a>>>,
|
||||
}
|
||||
|
||||
/// WriterInner is a (limited) generic representation of a writer. It is
|
||||
/// limited because W should only ever be stdout/stderr on Windows.
|
||||
enum WriterInner<'a, W> {
|
||||
enum WriterInner<W> {
|
||||
NoColor(NoColor<W>),
|
||||
Ansi(Ansi<W>),
|
||||
#[cfg(windows)]
|
||||
Windows { wtr: W, console: Mutex<wincolor::Console> },
|
||||
}
|
||||
|
||||
/// WriterInnerLock is a (limited) generic representation of a writer. It is
|
||||
/// limited because W should only ever be stdout/stderr on Windows.
|
||||
enum WriterInnerLock<'a, W> {
|
||||
NoColor(NoColor<W>),
|
||||
Ansi(Ansi<W>),
|
||||
/// What a gross hack. On Windows, we need to specify a lifetime for the
|
||||
@@ -282,9 +300,7 @@ enum WriterInner<'a, W> {
|
||||
#[allow(dead_code)]
|
||||
Unreachable(::std::marker::PhantomData<&'a ()>),
|
||||
#[cfg(windows)]
|
||||
Windows { wtr: W, console: Mutex<wincolor::Console> },
|
||||
#[cfg(windows)]
|
||||
WindowsLocked { wtr: W, console: MutexGuard<'a, wincolor::Console> },
|
||||
Windows { wtr: W, console: MutexGuard<'a, wincolor::Console> },
|
||||
}
|
||||
|
||||
impl StandardStream {
|
||||
@@ -332,7 +348,9 @@ impl StandardStream {
|
||||
} else {
|
||||
WriterInner::NoColor(NoColor(IoStandardStream::new(sty)))
|
||||
};
|
||||
StandardStream { wtr: LossyStandardStream::new(wtr).is_console(is_win_console) }
|
||||
StandardStream {
|
||||
wtr: LossyStandardStream::new(wtr).is_console(is_win_console),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new `StandardStream` with the given color preferences that
|
||||
@@ -375,12 +393,11 @@ impl<'a> StandardStreamLock<'a> {
|
||||
#[cfg(not(windows))]
|
||||
fn from_stream(stream: &StandardStream) -> StandardStreamLock {
|
||||
let locked = match *stream.wtr.get_ref() {
|
||||
WriterInner::Unreachable(_) => unreachable!(),
|
||||
WriterInner::NoColor(ref w) => {
|
||||
WriterInner::NoColor(NoColor(w.0.lock()))
|
||||
WriterInnerLock::NoColor(NoColor(w.0.lock()))
|
||||
}
|
||||
WriterInner::Ansi(ref w) => {
|
||||
WriterInner::Ansi(Ansi(w.0.lock()))
|
||||
WriterInnerLock::Ansi(Ansi(w.0.lock()))
|
||||
}
|
||||
};
|
||||
StandardStreamLock { wtr: stream.wtr.wrap(locked) }
|
||||
@@ -389,24 +406,19 @@ impl<'a> StandardStreamLock<'a> {
|
||||
#[cfg(windows)]
|
||||
fn from_stream(stream: &StandardStream) -> StandardStreamLock {
|
||||
let locked = match *stream.wtr.get_ref() {
|
||||
WriterInner::Unreachable(_) => unreachable!(),
|
||||
WriterInner::NoColor(ref w) => {
|
||||
WriterInner::NoColor(NoColor(w.0.lock()))
|
||||
WriterInnerLock::NoColor(NoColor(w.0.lock()))
|
||||
}
|
||||
WriterInner::Ansi(ref w) => {
|
||||
WriterInner::Ansi(Ansi(w.0.lock()))
|
||||
WriterInnerLock::Ansi(Ansi(w.0.lock()))
|
||||
}
|
||||
#[cfg(windows)]
|
||||
WriterInner::Windows { ref wtr, ref console } => {
|
||||
WriterInner::WindowsLocked {
|
||||
WriterInnerLock::Windows {
|
||||
wtr: wtr.lock(),
|
||||
console: console.lock().unwrap(),
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
WriterInner::WindowsLocked{..} => {
|
||||
panic!("cannot call StandardStream.lock while a StandardStreamLock is alive");
|
||||
}
|
||||
};
|
||||
StandardStreamLock { wtr: stream.wtr.wrap(locked) }
|
||||
}
|
||||
@@ -438,48 +450,38 @@ impl<'a> WriteColor for StandardStreamLock<'a> {
|
||||
fn reset(&mut self) -> io::Result<()> { self.wtr.reset() }
|
||||
}
|
||||
|
||||
impl<'a, W: io::Write> io::Write for WriterInner<'a, W> {
|
||||
impl<W: io::Write> io::Write for WriterInner<W> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
match *self {
|
||||
WriterInner::Unreachable(_) => unreachable!(),
|
||||
WriterInner::NoColor(ref mut wtr) => wtr.write(buf),
|
||||
WriterInner::Ansi(ref mut wtr) => wtr.write(buf),
|
||||
#[cfg(windows)]
|
||||
WriterInner::Windows { ref mut wtr, .. } => wtr.write(buf),
|
||||
#[cfg(windows)]
|
||||
WriterInner::WindowsLocked { ref mut wtr, .. } => wtr.write(buf),
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
match *self {
|
||||
WriterInner::Unreachable(_) => unreachable!(),
|
||||
WriterInner::NoColor(ref mut wtr) => wtr.flush(),
|
||||
WriterInner::Ansi(ref mut wtr) => wtr.flush(),
|
||||
#[cfg(windows)]
|
||||
WriterInner::Windows { ref mut wtr, .. } => wtr.flush(),
|
||||
#[cfg(windows)]
|
||||
WriterInner::WindowsLocked { ref mut wtr, .. } => wtr.flush(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, W: io::Write> WriteColor for WriterInner<'a, W> {
|
||||
impl<W: io::Write> WriteColor for WriterInner<W> {
|
||||
fn supports_color(&self) -> bool {
|
||||
match *self {
|
||||
WriterInner::Unreachable(_) => unreachable!(),
|
||||
WriterInner::NoColor(_) => false,
|
||||
WriterInner::Ansi(_) => true,
|
||||
#[cfg(windows)]
|
||||
WriterInner::Windows { .. } => true,
|
||||
#[cfg(windows)]
|
||||
WriterInner::WindowsLocked { .. } => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
|
||||
match *self {
|
||||
WriterInner::Unreachable(_) => unreachable!(),
|
||||
WriterInner::NoColor(ref mut wtr) => wtr.set_color(spec),
|
||||
WriterInner::Ansi(ref mut wtr) => wtr.set_color(spec),
|
||||
#[cfg(windows)]
|
||||
@@ -488,17 +490,11 @@ impl<'a, W: io::Write> WriteColor for WriterInner<'a, W> {
|
||||
let mut console = console.lock().unwrap();
|
||||
spec.write_console(&mut *console)
|
||||
}
|
||||
#[cfg(windows)]
|
||||
WriterInner::WindowsLocked { ref mut wtr, ref mut console } => {
|
||||
try!(wtr.flush());
|
||||
spec.write_console(console)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn reset(&mut self) -> io::Result<()> {
|
||||
match *self {
|
||||
WriterInner::Unreachable(_) => unreachable!(),
|
||||
WriterInner::NoColor(ref mut wtr) => wtr.reset(),
|
||||
WriterInner::Ansi(ref mut wtr) => wtr.reset(),
|
||||
#[cfg(windows)]
|
||||
@@ -507,8 +503,63 @@ impl<'a, W: io::Write> WriteColor for WriterInner<'a, W> {
|
||||
try!(console.lock().unwrap().reset());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, W: io::Write> io::Write for WriterInnerLock<'a, W> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
match *self {
|
||||
WriterInnerLock::Unreachable(_) => unreachable!(),
|
||||
WriterInnerLock::NoColor(ref mut wtr) => wtr.write(buf),
|
||||
WriterInnerLock::Ansi(ref mut wtr) => wtr.write(buf),
|
||||
#[cfg(windows)]
|
||||
WriterInner::WindowsLocked { ref mut wtr, ref mut console } => {
|
||||
WriterInnerLock::Windows { ref mut wtr, .. } => wtr.write(buf),
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
match *self {
|
||||
WriterInnerLock::Unreachable(_) => unreachable!(),
|
||||
WriterInnerLock::NoColor(ref mut wtr) => wtr.flush(),
|
||||
WriterInnerLock::Ansi(ref mut wtr) => wtr.flush(),
|
||||
#[cfg(windows)]
|
||||
WriterInnerLock::Windows { ref mut wtr, .. } => wtr.flush(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, W: io::Write> WriteColor for WriterInnerLock<'a, W> {
|
||||
fn supports_color(&self) -> bool {
|
||||
match *self {
|
||||
WriterInnerLock::Unreachable(_) => unreachable!(),
|
||||
WriterInnerLock::NoColor(_) => false,
|
||||
WriterInnerLock::Ansi(_) => true,
|
||||
#[cfg(windows)]
|
||||
WriterInnerLock::Windows { .. } => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
|
||||
match *self {
|
||||
WriterInnerLock::Unreachable(_) => unreachable!(),
|
||||
WriterInnerLock::NoColor(ref mut wtr) => wtr.set_color(spec),
|
||||
WriterInnerLock::Ansi(ref mut wtr) => wtr.set_color(spec),
|
||||
#[cfg(windows)]
|
||||
WriterInnerLock::Windows { ref mut wtr, ref mut console } => {
|
||||
try!(wtr.flush());
|
||||
spec.write_console(console)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn reset(&mut self) -> io::Result<()> {
|
||||
match *self {
|
||||
WriterInnerLock::Unreachable(_) => unreachable!(),
|
||||
WriterInnerLock::NoColor(ref mut wtr) => wtr.reset(),
|
||||
WriterInnerLock::Ansi(ref mut wtr) => wtr.reset(),
|
||||
#[cfg(windows)]
|
||||
WriterInnerLock::Windows { ref mut wtr, ref mut console } => {
|
||||
try!(wtr.flush());
|
||||
try!(console.reset());
|
||||
Ok(())
|
||||
@@ -565,7 +616,8 @@ impl BufferWriter {
|
||||
StandardStreamType::Stdout => wincolor::Console::stdout(),
|
||||
StandardStreamType::Stderr => wincolor::Console::stderr(),
|
||||
}.ok().map(Mutex::new);
|
||||
let stream = LossyStandardStream::new(IoStandardStream::new(sty)).is_console(con.is_some());
|
||||
let stream = LossyStandardStream::new(IoStandardStream::new(sty))
|
||||
.is_console(con.is_some());
|
||||
BufferWriter {
|
||||
stream: stream,
|
||||
printed: AtomicBool::new(false),
|
||||
@@ -1253,7 +1305,9 @@ struct LossyStandardStream<W> {
|
||||
|
||||
impl<W: io::Write> LossyStandardStream<W> {
|
||||
#[cfg(not(windows))]
|
||||
fn new(wtr: W) -> LossyStandardStream<W> { LossyStandardStream { wtr: wtr } }
|
||||
fn new(wtr: W) -> LossyStandardStream<W> {
|
||||
LossyStandardStream { wtr: wtr }
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn new(wtr: W) -> LossyStandardStream<W> {
|
||||
@@ -1320,3 +1374,15 @@ fn write_lossy_utf8<W: io::Write>(mut w: W, buf: &[u8]) -> io::Result<usize> {
|
||||
Err(e) => w.write(&buf[..e.valid_up_to()]),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::StandardStream;
|
||||
|
||||
fn assert_is_send<T: Send>() {}
|
||||
|
||||
#[test]
|
||||
fn standard_stream_is_send() {
|
||||
assert_is_send::<StandardStream>();
|
||||
}
|
||||
}
|
||||
|
@@ -209,6 +209,16 @@ For the Doctor Watsons of this world, as opposed to the Sherlock
|
||||
assert_eq!(lines, expected);
|
||||
});
|
||||
|
||||
sherlock!(line, "Watson|and exhibited clearly, with a label attached.",
|
||||
|wd: WorkDir, mut cmd: Command| {
|
||||
cmd.arg("-x");
|
||||
let lines: String = wd.stdout(&mut cmd);
|
||||
let expected = "\
|
||||
and exhibited clearly, with a label attached.
|
||||
";
|
||||
assert_eq!(lines, expected);
|
||||
});
|
||||
|
||||
sherlock!(literal, "()", "file", |wd: WorkDir, mut cmd: Command| {
|
||||
wd.create("file", "blib\n()\nblab\n");
|
||||
cmd.arg("-F");
|
||||
@@ -336,6 +346,21 @@ sherlock!(glob_negate, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
|
||||
assert_eq!(lines, "file.py:Sherlock\n");
|
||||
});
|
||||
|
||||
sherlock!(iglob, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
|
||||
wd.create("file.HTML", "Sherlock");
|
||||
cmd.arg("--iglob").arg("*.html");
|
||||
let lines: String = wd.stdout(&mut cmd);
|
||||
assert_eq!(lines, "file.HTML:Sherlock\n");
|
||||
});
|
||||
|
||||
sherlock!(csglob, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
|
||||
wd.create("file1.HTML", "Sherlock");
|
||||
wd.create("file2.html", "Sherlock");
|
||||
cmd.arg("--glob").arg("*.html");
|
||||
let lines: String = wd.stdout(&mut cmd);
|
||||
assert_eq!(lines, "file2.html:Sherlock\n");
|
||||
});
|
||||
|
||||
sherlock!(count, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
|
||||
cmd.arg("--count");
|
||||
let lines: String = wd.stdout(&mut cmd);
|
||||
@@ -1065,16 +1090,19 @@ clean!(regression_405, "test", ".", |wd: WorkDir, mut cmd: Command| {
|
||||
});
|
||||
|
||||
// See: https://github.com/BurntSushi/ripgrep/issues/428
|
||||
clean!(regression_428_color_context_path, "foo", ".", |wd: WorkDir, mut cmd: Command| {
|
||||
#[cfg(not(windows))]
|
||||
clean!(regression_428_color_context_path, "foo", ".",
|
||||
|wd: WorkDir, mut cmd: Command| {
|
||||
wd.create("sherlock", "foo\nbar");
|
||||
cmd.arg("-A1").arg("-H").arg("--no-heading").arg("-N")
|
||||
.arg("--colors=match:none").arg("--color=always");
|
||||
|
||||
let lines: String = wd.stdout(&mut cmd);
|
||||
let expected = format!("\
|
||||
{colored_path}:foo
|
||||
{colored_path}-bar
|
||||
", colored_path=format!("\x1b\x5b\x6d\x1b\x5b\x33\x35\x6d{path}\x1b\x5b\x6d", path=path("sherlock")));
|
||||
let expected = format!(
|
||||
"{colored_path}:foo\n{colored_path}-bar\n",
|
||||
colored_path=format!(
|
||||
"\x1b\x5b\x6d\x1b\x5b\x33\x35\x6d{path}\x1b\x5b\x6d",
|
||||
path=path("sherlock")));
|
||||
assert_eq!(lines, expected);
|
||||
});
|
||||
|
||||
@@ -1690,6 +1718,7 @@ fn regression_483_non_matching_exit_code() {
|
||||
|
||||
wd.assert_err(&mut cmd);
|
||||
}
|
||||
|
||||
// See: https://github.com/BurntSushi/ripgrep/issues/506
|
||||
#[test]
|
||||
fn regression_506_word_boundaries_not_parenthesized() {
|
||||
@@ -1705,7 +1734,29 @@ fn regression_506_word_boundaries_not_parenthesized() {
|
||||
let expected = "min\nmax\n";
|
||||
|
||||
assert_eq!(lines, expected);
|
||||
}
|
||||
|
||||
// See: https://github.com/BurntSushi/ripgrep/issues/568
|
||||
#[test]
|
||||
fn regression_568_leading_hyphen_option_arguments() {
|
||||
let wd = WorkDir::new("regression_568_leading_hyphen_option_arguments");
|
||||
let path = "file";
|
||||
wd.create(path, "foo bar -baz\n");
|
||||
|
||||
let mut cmd = wd.command();
|
||||
cmd.arg("-e-baz").arg("-e").arg("-baz").arg(path);
|
||||
let lines: String = wd.stdout(&mut cmd);
|
||||
assert_eq!(lines, "foo bar -baz\n");
|
||||
|
||||
let mut cmd = wd.command();
|
||||
cmd.arg("-rni").arg("bar").arg(path);
|
||||
let lines: String = wd.stdout(&mut cmd);
|
||||
assert_eq!(lines, "foo ni -baz\n");
|
||||
|
||||
let mut cmd = wd.command();
|
||||
cmd.arg("-r").arg("-n").arg("-i").arg("bar").arg(path);
|
||||
let lines: String = wd.stdout(&mut cmd);
|
||||
assert_eq!(lines, "foo -n -baz\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
Reference in New Issue
Block a user