mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2025-07-27 02:01:58 -07:00
Compare commits
83 Commits
ignore-0.1
...
0.6.0
Author | SHA1 | Date | |
---|---|---|---|
|
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 | ||
|
9d7b6eb09a | ||
|
7763c98188 | ||
|
06393f888c | ||
|
e0989ef13b | ||
|
45e850aff7 | ||
|
f2d1c582a8 | ||
|
ab70815ea2 | ||
|
27f97db510 | ||
|
506ad1f3cf | ||
|
13235b596f | ||
|
2628c8f38e | ||
|
112b3c5e0a | ||
|
4c78ca8b70 | ||
|
ff898cd105 | ||
|
2c98e5ce1e | ||
|
1e3fc79949 | ||
|
d1bbc6956b | ||
|
cd6c54f5f4 | ||
|
44c03f58bc | ||
|
d1a6ab922e | ||
|
b860fa3acd | ||
|
229b8e3b33 | ||
|
a515c4d601 | ||
|
5a666b042d | ||
|
16109166fe | ||
|
0b685c8429 | ||
|
d2c7a76a3c | ||
|
20f7d9b3a2 | ||
|
362abed44a | ||
|
c50b8b4125 | ||
|
7ad23e5565 | ||
|
66efbad871 | ||
|
1f2a9b0306 | ||
|
a45fe94240 | ||
|
ac1c95a6d9 | ||
|
685b431d80 |
8
.gitignore
vendored
8
.gitignore
vendored
@@ -6,3 +6,11 @@ target
|
|||||||
/ignore/Cargo.lock
|
/ignore/Cargo.lock
|
||||||
/termcolor/Cargo.lock
|
/termcolor/Cargo.lock
|
||||||
/wincolor/Cargo.lock
|
/wincolor/Cargo.lock
|
||||||
|
|
||||||
|
# Snapcraft files
|
||||||
|
stage
|
||||||
|
prime
|
||||||
|
parts
|
||||||
|
*.snap
|
||||||
|
*.pyc
|
||||||
|
ripgrep*_source.tar.bz2
|
20
.travis.yml
20
.travis.yml
@@ -3,19 +3,27 @@ language: rust
|
|||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- PROJECT_NAME=ripgrep
|
- PROJECT_NAME=ripgrep
|
||||||
|
- RUST_BACKTRACE: full
|
||||||
|
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
# Needed for completion-function test
|
||||||
|
- zsh
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
# Nightly channel.
|
# Nightly channel.
|
||||||
# (All *nix releases are done on the nightly channel to take advantage
|
# (All *nix releases are done on the nightly channel to take advantage
|
||||||
# of the regex library's multiple pattern SIMD search.)
|
# of the regex library's multiple pattern SIMD search.)
|
||||||
- os: linux
|
- os: linux
|
||||||
rust: nightly-2017-03-13
|
rust: nightly
|
||||||
env: TARGET=i686-unknown-linux-musl
|
env: TARGET=i686-unknown-linux-musl
|
||||||
- os: linux
|
- os: linux
|
||||||
rust: nightly-2017-03-13
|
rust: nightly
|
||||||
env: TARGET=x86_64-unknown-linux-musl
|
env: TARGET=x86_64-unknown-linux-musl
|
||||||
- os: osx
|
- os: osx
|
||||||
rust: nightly-2017-03-13
|
rust: nightly
|
||||||
env: TARGET=x86_64-apple-darwin
|
env: TARGET=x86_64-apple-darwin
|
||||||
# Beta channel.
|
# Beta channel.
|
||||||
- os: linux
|
- os: linux
|
||||||
@@ -26,10 +34,10 @@ matrix:
|
|||||||
env: TARGET=x86_64-unknown-linux-gnu
|
env: TARGET=x86_64-unknown-linux-gnu
|
||||||
# Minimum Rust supported channel.
|
# Minimum Rust supported channel.
|
||||||
- os: linux
|
- os: linux
|
||||||
rust: 1.12.0
|
rust: 1.17.0
|
||||||
env: TARGET=x86_64-unknown-linux-gnu
|
env: TARGET=x86_64-unknown-linux-gnu
|
||||||
- os: linux
|
- os: linux
|
||||||
rust: 1.12.0
|
rust: 1.17.0
|
||||||
env: TARGET=x86_64-unknown-linux-musl
|
env: TARGET=x86_64-unknown-linux-musl
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
@@ -57,7 +65,7 @@ deploy:
|
|||||||
# channel to use to produce the release artifacts
|
# channel to use to produce the release artifacts
|
||||||
# NOTE make sure you only release *once* per target
|
# NOTE make sure you only release *once* per target
|
||||||
# TODO you may want to pick a different channel
|
# TODO you may want to pick a different channel
|
||||||
condition: $TRAVIS_RUST_VERSION = nightly-2017-03-13
|
condition: $TRAVIS_RUST_VERSION = nightly
|
||||||
tags: true
|
tags: true
|
||||||
|
|
||||||
branches:
|
branches:
|
||||||
|
88
CHANGELOG.md
88
CHANGELOG.md
@@ -1,3 +1,91 @@
|
|||||||
|
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:
|
||||||
|
|
||||||
|
* Added or improved file type filtering for Nix.
|
||||||
|
* [FEATURE #362](https://github.com/BurntSushi/ripgrep/issues/362):
|
||||||
|
Add `--regex-size-limit` and `--dfa-size-limit` flags.
|
||||||
|
* [FEATURE #444](https://github.com/BurntSushi/ripgrep/issues/444):
|
||||||
|
Improve error messages for invalid globs.
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* [BUG #442](https://github.com/BurntSushi/ripgrep/issues/442):
|
||||||
|
Fix line wrapping in `--help` output.
|
||||||
|
* [BUG #451](https://github.com/BurntSushi/ripgrep/issues/451):
|
||||||
|
Fix bug with duplicate output when using `-o/--only-matching` flag.
|
||||||
|
|
||||||
|
|
||||||
0.5.1 (2017-04-09)
|
0.5.1 (2017-04-09)
|
||||||
==================
|
==================
|
||||||
Feature enhancements:
|
Feature enhancements:
|
||||||
|
175
Cargo.lock
generated
175
Cargo.lock
generated
@@ -1,21 +1,20 @@
|
|||||||
[root]
|
[root]
|
||||||
name = "ripgrep"
|
name = "ripgrep"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"bytecount 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"clap 2.23.1 (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.5.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.2 (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",
|
"grep 0.1.6",
|
||||||
"ignore 0.1.9",
|
"ignore 0.2.2",
|
||||||
"lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"memchr 1.0.1 (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)",
|
"memmap 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num_cpus 1.3.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.1 (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)",
|
"same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"termcolor 0.3.2",
|
"termcolor 0.3.2",
|
||||||
]
|
]
|
||||||
@@ -39,41 +38,42 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kernel32-sys 0.2.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.21 (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)",
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "0.8.2"
|
version = "0.9.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytecount"
|
name = "bytecount"
|
||||||
version = "0.1.6"
|
version = "0.1.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
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]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "0.1.0"
|
version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "2.23.1"
|
version = "2.26.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"term_size 0.2.3 (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)",
|
"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]]
|
[[package]]
|
||||||
@@ -83,18 +83,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encoding_rs"
|
name = "encoding_rs"
|
||||||
version = "0.5.0"
|
version = "0.6.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
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]]
|
[[package]]
|
||||||
name = "env_logger"
|
name = "env_logger"
|
||||||
version = "0.4.2"
|
version = "0.4.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
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]]
|
[[package]]
|
||||||
@@ -104,46 +105,46 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fs2"
|
name = "fs2"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kernel32-sys 0.2.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.21 (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)",
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "globset"
|
name = "globset"
|
||||||
version = "0.1.4"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grep"
|
name = "grep"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
dependencies = [
|
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)",
|
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 0.2.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.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ignore"
|
name = "ignore"
|
||||||
version = "0.1.9"
|
version = "0.2.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"globset 0.1.4",
|
"globset 0.2.0",
|
||||||
"lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 0.2.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)",
|
"walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -158,17 +159,17 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "0.2.5"
|
version = "0.2.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.21"
|
version = "0.2.29"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.3.7"
|
version = "0.3.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -176,7 +177,7 @@ name = "memchr"
|
|||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -184,36 +185,36 @@ name = "memmap"
|
|||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
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)",
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.21 (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)",
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.3.0"
|
version = "1.6.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "0.2.1"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex-syntax 0.4.0 (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)",
|
"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)",
|
"utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.4.0"
|
version = "0.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -230,6 +231,11 @@ name = "simd"
|
|||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
@@ -237,11 +243,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "term_size"
|
name = "term_size"
|
||||||
version = "0.2.3"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kernel32-sys 0.2.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.21 (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)",
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -249,30 +255,30 @@ dependencies = [
|
|||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wincolor 0.1.3",
|
"wincolor 0.1.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thread-id"
|
name = "textwrap"
|
||||||
version = "3.0.0"
|
version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thread_local"
|
name = "thread_local"
|
||||||
version = "0.3.3"
|
version = "0.3.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-segmentation"
|
name = "unicode-segmentation"
|
||||||
version = "1.1.0"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -282,7 +288,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unreachable"
|
name = "unreachable"
|
||||||
version = "0.1.1"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "vec_map"
|
name = "vec_map"
|
||||||
version = "0.7.0"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -325,7 +331,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wincolor"
|
name = "wincolor"
|
||||||
version = "0.1.3"
|
version = "0.1.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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 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 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 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 bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
|
||||||
"checksum bytecount 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1e8f09fbc8c6726a4b616dcfbd4f54491068d6bb1b93ac03c78ac18ff9a5924a"
|
"checksum bytecount 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "4bbeb7c30341fce29f6078b4bdf876ea4779600866e98f5b2d203a534f195050"
|
||||||
"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
|
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
|
||||||
"checksum clap 2.23.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d480c39a2e5f9b3a3798c661613e1b0e7a7ae71e005102d4aa910fc3289df484"
|
"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 crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97"
|
||||||
"checksum encoding_rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a1cca0a26f904955d80d70b9bff1019e4f4cbc06f2fcbccf8bd3d889cc1c9b7"
|
"checksum encoding_rs 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e00a1b1e95eb46988805ceee6f34cd95c46a6753e290cb3ff0486931989d4a4c"
|
||||||
"checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83"
|
"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 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 kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||||
"checksum lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4732c563b9a21a406565c4747daa7b46742f082911ae4753f390dc9ec7ee1a97"
|
"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf"
|
||||||
"checksum libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "88ee81885f9f04bff991e306fea7c1c60a5f0f9e409e99f6b40e3311a3363135"
|
"checksum libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "8a014d9226c2cc402676fbe9ea2e15dd5222cd1dd57f576b5b283178c944a264"
|
||||||
"checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad"
|
"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 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 memmap 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46f3c7359028b31999287dae4e5047ddfe90a23b7dca2282ce759b491080c99b"
|
||||||
"checksum num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a18c392466409c50b87369414a2680c93e739aedeb498eb2bff7d7eb569744e2"
|
"checksum num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aec53c34f2d0247c5ca5d32cca1478762f301740468ee9ee6dcb7a0dd7a0c584"
|
||||||
"checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01"
|
"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b"
|
||||||
"checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457"
|
"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 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.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 strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
|
||||||
"checksum term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "07b6c1ac5b3fffd75073276bca1ceed01f67a28537097a2a9539e116e50fb21a"
|
"checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209"
|
||||||
"checksum thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a"
|
"checksum textwrap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f728584ea33b0ad19318e20557cb0a39097751dbb07171419673502f848c7af6"
|
||||||
"checksum thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c85048c6260d17cf486ceae3282d9fb6b90be220bf5b28c400f5485ffc29f0c7"
|
"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14"
|
||||||
"checksum unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18127285758f0e2c6cf325bb3f3d138a12fee27de4f23e146cd6a179f26c2cf3"
|
"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 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 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 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 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"
|
"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]
|
[package]
|
||||||
name = "ripgrep"
|
name = "ripgrep"
|
||||||
version = "0.5.0" #:version
|
version = "0.6.0" #:version
|
||||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||||
description = """
|
description = """
|
||||||
Line oriented search tool using Rust's regex library. Combines the raw
|
Line oriented search tool using Rust's regex library. Combines the raw
|
||||||
@@ -16,6 +16,10 @@ license = "Unlicense/MIT"
|
|||||||
exclude = ["HomebrewFormula"]
|
exclude = ["HomebrewFormula"]
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
|
[badges]
|
||||||
|
travis-ci = { repository = "BurntSushi/ripgrep" }
|
||||||
|
appveyor = { repository = "BurntSushi/ripgrep" }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
bench = false
|
bench = false
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
@@ -28,13 +32,12 @@ path = "tests/tests.rs"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
atty = "0.2.2"
|
atty = "0.2.2"
|
||||||
bytecount = "0.1.4"
|
bytecount = "0.1.4"
|
||||||
clap = "2.23.1"
|
clap = "2.26"
|
||||||
encoding_rs = "0.5.0"
|
encoding_rs = "0.6"
|
||||||
env_logger = { version = "0.4", default-features = false }
|
env_logger = { version = "0.4", default-features = false }
|
||||||
grep = { version = "0.1.5", path = "grep" }
|
grep = { version = "0.1.5", path = "grep" }
|
||||||
ignore = { version = "0.1.9", path = "ignore" }
|
ignore = { version = "0.2.2", path = "ignore" }
|
||||||
lazy_static = "0.2"
|
lazy_static = "0.2"
|
||||||
libc = "0.2"
|
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
memchr = "1"
|
memchr = "1"
|
||||||
memmap = "0.5"
|
memmap = "0.5"
|
||||||
@@ -44,12 +47,12 @@ same-file = "0.1.1"
|
|||||||
termcolor = { version = "0.3.0", path = "termcolor" }
|
termcolor = { version = "0.3.0", path = "termcolor" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
clap = "2.23.1"
|
clap = "2.26"
|
||||||
lazy_static = "0.2"
|
lazy_static = "0.2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
avx-accel = ["bytecount/avx-accel"]
|
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]
|
[profile.release]
|
||||||
debug = true
|
debug = true
|
||||||
|
61
README.md
61
README.md
@@ -187,17 +187,17 @@ If you're a **Gentoo** user, you can install `ripgrep` from the [official repo](
|
|||||||
$ emerge ripgrep
|
$ 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
|
$ 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
|
$ yum install ripgrep
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -338,10 +338,17 @@ The syntax supported is
|
|||||||
Shell completion files are included in the release tarball for Bash, Fish, Zsh
|
Shell completion files are included in the release tarball for Bash, Fish, Zsh
|
||||||
and PowerShell.
|
and PowerShell.
|
||||||
|
|
||||||
For **bash**, move `rg.bash-completion` to `$XDG_CONFIG_HOME/bash_completion`
|
For **bash**, move `complete/rg.bash-completion` to `$XDG_CONFIG_HOME/bash_completion`
|
||||||
or `/etc/bash_completion.d/`.
|
or `/etc/bash_completion.d/`.
|
||||||
|
|
||||||
For **fish**, move `rg.fish` to `$HOME/.config/fish/completions`.
|
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.
|
||||||
|
|
||||||
|
For **zsh**, move `complete/_rg` to one of your `$fpath` directories.
|
||||||
|
|
||||||
### Building
|
### Building
|
||||||
|
|
||||||
@@ -385,7 +392,7 @@ from the repository root.
|
|||||||
##### Powershell Profile
|
##### Powershell Profile
|
||||||
|
|
||||||
To customize powershell on start-up there is a special powershell script that has to be created.
|
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.
|
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.
|
Any powershell code in this file gets evaluated at the start of console.
|
||||||
@@ -423,12 +430,48 @@ Powershell special variables:
|
|||||||
This alias checks whether there is **Stdin** input and propagates only if there is some lines.
|
This alias checks whether there is **Stdin** input and propagates only if there is some lines.
|
||||||
Otherwise empty `$input` will make powershell to trigger `rg` to search empty **Stdin**
|
Otherwise empty `$input` will make powershell to trigger `rg` to search empty **Stdin**
|
||||||
|
|
||||||
|
##### Piping non-ASCII content to ripgrep
|
||||||
|
|
||||||
|
When piping input into native executables in PowerShell, the encoding of the
|
||||||
|
input is controlled by the `$OutputEncoding` variable. By default, this is set
|
||||||
|
to US-ASCII, and any characters in the pipeline that don't have encodings in
|
||||||
|
US-ASCII are converted to `?` (question mark) characters.
|
||||||
|
|
||||||
|
To change this setting, set `$OutputEncoding` to a different encoding, as
|
||||||
|
represented by a .NET encoding object. Some common examples are below. The
|
||||||
|
value of this variable is reset when PowerShell restarts, so to make this
|
||||||
|
change take effect every time PowerShell is started add a line setting the
|
||||||
|
variable into your PowerShell profile.
|
||||||
|
|
||||||
|
Example `$OutputEncoding` settings:
|
||||||
|
* UTF-8 without BOM: `$OutputEncoding = [System.Text.UTF8Encoding]::new()`
|
||||||
|
* The console's output encoding:
|
||||||
|
`$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
|
||||||
|
`[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.
|
||||||
|
|
||||||
### Known issues
|
### Known issues
|
||||||
|
|
||||||
#### I just hit Ctrl+C in the middle of ripgrep's output and now my terminal's foreground color is wrong!
|
#### I just hit Ctrl+C in the middle of ripgrep's output and now my terminal's foreground color is wrong!
|
||||||
|
|
||||||
Type in `color` on Windows and `echo -ne "\033[0m"` on Unix to restore your
|
Type in `color` in cmd.exe (Command Prompt) and `echo -ne "\033[0m"` on Unix
|
||||||
original foreground color.
|
to restore your original foreground color.
|
||||||
|
|
||||||
|
In PowerShell, you can add the following code to your profile which will
|
||||||
|
restore the original foreground color when `Reset-ForegroundColor` is called.
|
||||||
|
Including the `Set-Alias` line will allow you to call it with simply `color`.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$OrigFgColor = $Host.UI.RawUI.ForegroundColor
|
||||||
|
function Reset-ForegroundColor {
|
||||||
|
$Host.UI.RawUI.ForegroundColor = $OrigFgColor
|
||||||
|
}
|
||||||
|
Set-Alias -Name color -Value Reset-ForegroundColor
|
||||||
|
```
|
||||||
|
|
||||||
PR [#187](https://github.com/BurntSushi/ripgrep/pull/187) fixed this, and it
|
PR [#187](https://github.com/BurntSushi/ripgrep/pull/187) fixed this, and it
|
||||||
was later deprecated in
|
was later deprecated in
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
environment:
|
environment:
|
||||||
global:
|
global:
|
||||||
PROJECT_NAME: ripgrep
|
PROJECT_NAME: ripgrep
|
||||||
|
RUST_BACKTRACE: full
|
||||||
matrix:
|
matrix:
|
||||||
- TARGET: i686-pc-windows-gnu
|
- TARGET: i686-pc-windows-gnu
|
||||||
CHANNEL: stable
|
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):
|
||||||
if not os.path.exists(en_path_gz):
|
if not os.path.exists(en_path_gz):
|
||||||
run_cmd(['curl', '-LO', SUBTITLES_EN_URL], cwd=subtitle_dir)
|
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):
|
if not os.path.exists(en_path_sample):
|
||||||
# Get a sample roughly the same size as the Russian corpus so that
|
# Get a sample roughly the same size as the Russian corpus so that
|
||||||
# benchmarks finish in a reasonable time.
|
# 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):
|
||||||
if not os.path.exists(ru_path_gz):
|
if not os.path.exists(ru_path_gz):
|
||||||
run_cmd(['curl', '-LO', SUBTITLES_RU_URL], cwd=subtitle_dir)
|
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):
|
def has_subtitles_ru(suite_dir):
|
||||||
@@ -1184,6 +1184,7 @@ def collect_benchmarks(suite_dir, filter_pat=None,
|
|||||||
name,
|
name,
|
||||||
' '.join(['--download %s' % n for n in e.missing_names]),
|
' '.join(['--download %s' % n for n in e.missing_names]),
|
||||||
))
|
))
|
||||||
|
continue
|
||||||
except MissingCommands as e:
|
except MissingCommands as e:
|
||||||
fmt = 'missing commands: %s, skipping benchmark %s ' \
|
fmt = 'missing commands: %s, skipping benchmark %s ' \
|
||||||
'(run with --allow-missing to run incomplete benchmarks)'
|
'(run with --allow-missing to run incomplete benchmarks)'
|
||||||
@@ -1239,7 +1240,7 @@ def main():
|
|||||||
benchmarks = collect_benchmarks(
|
benchmarks = collect_benchmarks(
|
||||||
args.dir, filter_pat=args.bench,
|
args.dir, filter_pat=args.bench,
|
||||||
allow_missing_commands=args.allow_missing,
|
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)
|
warmup_iter=args.warmup_iter, bench_iter=args.bench_iter)
|
||||||
for b in benchmarks:
|
for b in benchmarks:
|
||||||
print(b.name)
|
print(b.name)
|
||||||
@@ -1266,7 +1267,7 @@ def main():
|
|||||||
benchmarks = collect_benchmarks(
|
benchmarks = collect_benchmarks(
|
||||||
args.dir, filter_pat=args.bench,
|
args.dir, filter_pat=args.bench,
|
||||||
allow_missing_commands=args.allow_missing,
|
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)
|
warmup_iter=args.warmup_iter, bench_iter=args.bench_iter)
|
||||||
for i, b in enumerate(benchmarks):
|
for i, b in enumerate(benchmarks):
|
||||||
result = b.run()
|
result = b.run()
|
||||||
|
1
build.rs
1
build.rs
@@ -22,6 +22,5 @@ fn main() {
|
|||||||
let mut app = app::app();
|
let mut app = app::app();
|
||||||
app.gen_completions("rg", Shell::Bash, &outdir);
|
app.gen_completions("rg", Shell::Bash, &outdir);
|
||||||
app.gen_completions("rg", Shell::Fish, &outdir);
|
app.gen_completions("rg", Shell::Fish, &outdir);
|
||||||
app.gen_completions("rg", Shell::Zsh, &outdir);
|
|
||||||
app.gen_completions("rg", Shell::PowerShell, &outdir);
|
app.gen_completions("rg", Shell::PowerShell, &outdir);
|
||||||
}
|
}
|
||||||
|
@@ -18,9 +18,13 @@ mk_tarball() {
|
|||||||
mkdir "$td/$name"
|
mkdir "$td/$name"
|
||||||
mkdir "$td/$name/complete"
|
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 {doc/rg.1,README.md,UNLICENSE,COPYING,LICENSE-MIT} "$td/$name/"
|
||||||
cp target/$TARGET/release/build/ripgrep-*/out/{_rg,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
|
pushd $td
|
||||||
tar czf "$out_dir/$name.tar.gz" *
|
tar czf "$out_dir/$name.tar.gz" *
|
||||||
|
@@ -28,6 +28,8 @@ run_test_suite() {
|
|||||||
cargo build --target $TARGET --verbose --manifest-path termcolor/Cargo.toml
|
cargo build --target $TARGET --verbose --manifest-path termcolor/Cargo.toml
|
||||||
cargo test --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
|
# sanity check the file type
|
||||||
file target/$TARGET/debug/rg
|
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 "${@}"
|
255
complete/_rg
Normal file
255
complete/_rg
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
#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.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are met:
|
||||||
|
# * Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
# * Neither the name of the zsh-users nor the
|
||||||
|
# names of its contributors may be used to endorse or promote products
|
||||||
|
# derived from this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
# DISCLAIMED. IN NO EVENT SHALL ZSH-USERS BE LIABLE FOR ANY
|
||||||
|
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Description
|
||||||
|
# -----------
|
||||||
|
#
|
||||||
|
# Completion script for ripgrep
|
||||||
|
#
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Authors
|
||||||
|
# -------
|
||||||
|
#
|
||||||
|
# * arcizan <ghostrevery@gmail.com>
|
||||||
|
# * MaskRay <i@maskray.me>
|
||||||
|
#
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Local Variables:
|
||||||
|
# mode: shell-script
|
||||||
|
# coding: utf-8-unix
|
||||||
|
# indent-tabs-mode: nil
|
||||||
|
# sh-indentation: 2
|
||||||
|
# sh-basic-offset: 2
|
||||||
|
# End:
|
||||||
|
# vim: ft=zsh sw=2 ts=2 et
|
@@ -1,4 +1,5 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh -e
|
||||||
|
|
||||||
pandoc -s -t man rg.1.md -o rg.1
|
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
|
||||||
|
112
doc/rg.1
112
doc/rg.1
@@ -7,12 +7,12 @@
|
|||||||
rg \- recursively search current directory for lines matching a pattern
|
rg \- recursively search current directory for lines matching a pattern
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.PP
|
.PP
|
||||||
rg [\f[I]options\f[]] <\f[I]pattern\f[]> [\f[I]<\f[]path\f[I]> ...\f[]]
|
rg [\f[I]options\f[]] \f[I]PATTERN\f[] [\f[I]path\f[] ...]
|
||||||
.PP
|
.PP
|
||||||
rg [\f[I]options\f[]] (\-e PATTERN | \-f FILE) ...
|
rg [\f[I]options\f[]] [\-e \f[I]PATTERN\f[] ...] [\-f \f[I]FILE\f[] ...]
|
||||||
[\f[I]<\f[]path\f[I]> ...\f[]]
|
[\f[I]path\f[] ...]
|
||||||
.PP
|
.PP
|
||||||
rg [\f[I]options\f[]] \-\-files [\f[I]<\f[]path\f[I]> ...\f[]]
|
rg [\f[I]options\f[]] \-\-files [\f[I]path\f[] ...]
|
||||||
.PP
|
.PP
|
||||||
rg [\f[I]options\f[]] \-\-type\-list
|
rg [\f[I]options\f[]] \-\-type\-list
|
||||||
.PP
|
.PP
|
||||||
@@ -29,6 +29,10 @@ time searching.
|
|||||||
Because of this, features like backreferences and arbitrary lookaround
|
Because of this, features like backreferences and arbitrary lookaround
|
||||||
are not supported.
|
are not supported.
|
||||||
.PP
|
.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
|
Project home page: https://github.com/BurntSushi/ripgrep
|
||||||
.SH COMMON OPTIONS
|
.SH COMMON OPTIONS
|
||||||
.TP
|
.TP
|
||||||
@@ -43,9 +47,12 @@ Only show count of line matches for each file.
|
|||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
.B \-\-color \f[I]WHEN\f[]
|
.B \-\-color \f[I]WHEN\f[]
|
||||||
Whether to use coloring in match.
|
Whether to use color in the output.
|
||||||
Valid values are never, always or auto.
|
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
|
.RS
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
@@ -71,22 +78,23 @@ Multiple glob flags may be used.
|
|||||||
Globbing rules match .gitignore globs.
|
Globbing rules match .gitignore globs.
|
||||||
Precede a glob with a \[aq]!\[aq] to exclude it.
|
Precede a glob with a \[aq]!\[aq] to exclude it.
|
||||||
.RS
|
.RS
|
||||||
.RE
|
|
||||||
.PP
|
.PP
|
||||||
The \-\-glob flag subsumes the functionality of both the \-\-include and
|
The \-\-glob flag subsumes the functionality of both the \-\-include and
|
||||||
\-\-exclude flags commonly found in other tools.
|
\-\-exclude flags commonly found in other tools.
|
||||||
|
.PP
|
||||||
|
Values given to \-g must be quoted or your shell will expand them and
|
||||||
|
result in unexpected behavior.
|
||||||
|
.PP
|
||||||
|
Combine with the \-\-files flag to return matched filenames (i.e., to
|
||||||
|
replicate ack/ag\[aq]s \-g flag).
|
||||||
|
For example:
|
||||||
.IP
|
.IP
|
||||||
.nf
|
.nf
|
||||||
\f[C]
|
\f[C]
|
||||||
Values\ given\ to\ \-g\ must\ be\ quoted\ or\ your\ shell\ will\ expand\ them\ and\ result
|
rg\ \-g\ \[aq]*.foo\[aq]\ \-\-files
|
||||||
in\ unexpected\ behavior.
|
|
||||||
|
|
||||||
Combine\ with\ the\ \-\-files\ flag\ to\ return\ matched\ filenames
|
|
||||||
(i.e.,\ to\ replicate\ ack/ag\[aq]s\ \-g\ flag).
|
|
||||||
|
|
||||||
For\ example:\ rg\ \-g\ \[aq]\\<glob\\>\[aq]\ \-\-files
|
|
||||||
\f[]
|
\f[]
|
||||||
.fi
|
.fi
|
||||||
|
.RE
|
||||||
.TP
|
.TP
|
||||||
.B \-h, \-\-help
|
.B \-h, \-\-help
|
||||||
Show this usage message.
|
Show this usage message.
|
||||||
@@ -134,14 +142,15 @@ Reduce the level of \[aq]smart\[aq] searching.
|
|||||||
A single \-u doesn\[aq]t respect .gitignore (etc.) files.
|
A single \-u doesn\[aq]t respect .gitignore (etc.) files.
|
||||||
Two \-u flags will search hidden files and directories.
|
Two \-u flags will search hidden files and directories.
|
||||||
Three \-u flags will search binary files.
|
Three \-u flags will search binary files.
|
||||||
\-uu is equivalent to grep \-r, and \-uuu is equivalent to grep \-a \-r.
|
\-uu is equivalent to \f[C]grep\ \-r\f[], and \-uuu is equivalent to
|
||||||
|
\f[C]grep\ \-a\ \-r\f[].
|
||||||
.RS
|
.RS
|
||||||
.PP
|
.PP
|
||||||
Note that the \-u flags are convenient aliases for other combinations of
|
Note that the \-u flags are convenient aliases for other combinations of
|
||||||
flags.
|
flags.
|
||||||
\-u aliases \[aq]\-\-no\-ignore\[aq].
|
\-u aliases \-\-no\-ignore.
|
||||||
\-uu aliases \[aq]\-\-no\-ignore \-\-hidden\[aq].
|
\-uu aliases \-\-no\-ignore \-\-hidden.
|
||||||
\-uuu aliases \[aq]\-\-no\-ignore \-\-hidden \-\-text\[aq].
|
\-uuu aliases \-\-no\-ignore \-\-hidden \-\-text.
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
.B \-v, \-\-invert\-match
|
.B \-v, \-\-invert\-match
|
||||||
@@ -154,6 +163,12 @@ Only show matches surrounded by word boundaries.
|
|||||||
This is equivalent to putting \\b before and after the search pattern.
|
This is equivalent to putting \\b before and after the search pattern.
|
||||||
.RS
|
.RS
|
||||||
.RE
|
.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
|
.SH LESS COMMON OPTIONS
|
||||||
.TP
|
.TP
|
||||||
.B \-A, \-\-after\-context \f[I]NUM\f[]
|
.B \-A, \-\-after\-context \f[I]NUM\f[]
|
||||||
@@ -188,9 +203,12 @@ A special format, {type}:none, will clear all color settings for {type}.
|
|||||||
.PP
|
.PP
|
||||||
For example, the following command will change the match color to
|
For example, the following command will change the match color to
|
||||||
magenta and the background color for line numbers to yellow:
|
magenta and the background color for line numbers to yellow:
|
||||||
.PP
|
.IP
|
||||||
rg \-\-colors \[aq]match:fg:magenta\[aq] \-\-colors
|
.nf
|
||||||
\[aq]line:bg:yellow\[aq] foo.
|
\f[C]
|
||||||
|
rg\ \-\-colors\ \[aq]match:fg:magenta\[aq]\ \-\-colors\ \[aq]line:bg:yellow\[aq]\ foo.
|
||||||
|
\f[]
|
||||||
|
.fi
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
.B \-\-column
|
.B \-\-column
|
||||||
@@ -223,7 +241,7 @@ https://encoding.spec.whatwg.org/#concept\-encoding\-get
|
|||||||
.RS
|
.RS
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
.B \-f, \-\-file FILE ...
|
.B \-f, \-\-file \f[I]FILE\f[] ...
|
||||||
Search for patterns from the given file, with one pattern per line.
|
Search for patterns from the given file, with one pattern per line.
|
||||||
When this flag is used or multiple times or in combination with the
|
When this flag is used or multiple times or in combination with the
|
||||||
\-e/\-\-regexp flag, then all patterns provided are searched.
|
\-e/\-\-regexp flag, then all patterns provided are searched.
|
||||||
@@ -237,8 +255,12 @@ Print each file that would be searched (but don\[aq]t search).
|
|||||||
.RS
|
.RS
|
||||||
.PP
|
.PP
|
||||||
Combine with the \-g flag to return matched paths, for example:
|
Combine with the \-g flag to return matched paths, for example:
|
||||||
.PP
|
.IP
|
||||||
rg \-g \[aq]<glob>\[aq] \-\-files
|
.nf
|
||||||
|
\f[C]
|
||||||
|
rg\ \-g\ \[aq]*.foo\[aq]\ \-\-files
|
||||||
|
\f[]
|
||||||
|
.fi
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
.B \-l, \-\-files\-with\-matches
|
.B \-l, \-\-files\-with\-matches
|
||||||
@@ -274,7 +296,7 @@ This is the default mode at a tty.
|
|||||||
Don\[aq]t group matches by each file.
|
Don\[aq]t group matches by each file.
|
||||||
If \-H/\-\-with\-filename is enabled, then file names will be shown for
|
If \-H/\-\-with\-filename is enabled, then file names will be shown for
|
||||||
every line matched.
|
every line matched.
|
||||||
This is the default more when not at a tty.
|
This is the default mode when not at a tty.
|
||||||
.RS
|
.RS
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
@@ -284,7 +306,18 @@ Search hidden directories and files.
|
|||||||
.RS
|
.RS
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
.B \-\-ignore\-file FILE ...
|
.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.
|
Specify additional ignore files for filtering file paths.
|
||||||
Ignore files should be in the gitignore format and are matched relative
|
Ignore files should be in the gitignore format and are matched relative
|
||||||
to the current working directory.
|
to the current working directory.
|
||||||
@@ -387,7 +420,7 @@ A path separator is limited to a single byte.
|
|||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
.B \-p, \-\-pretty
|
.B \-p, \-\-pretty
|
||||||
Alias for \-\-color=always \-\-heading \-n.
|
Alias for \-\-color=always \-\-heading \-\-line\-number.
|
||||||
.RS
|
.RS
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
@@ -446,9 +479,21 @@ Show the version number of ripgrep and exit.
|
|||||||
.B \-\-vimgrep
|
.B \-\-vimgrep
|
||||||
Show results with every match on its own line, including line numbers
|
Show results with every match on its own line, including line numbers
|
||||||
and column numbers.
|
and column numbers.
|
||||||
(With this option, a line with more than one match of the regex will be
|
With this option, a line with more than one match will be printed more
|
||||||
printed more than once.)
|
than once.
|
||||||
.RS
|
.RS
|
||||||
|
.PP
|
||||||
|
Recommended .vimrc configuration:
|
||||||
|
.IP
|
||||||
|
.nf
|
||||||
|
\f[C]
|
||||||
|
\ \ set\ grepprg=rg\\\ \-\-vimgrep
|
||||||
|
\ \ set\ grepformat^=%f:%l:%c:%m
|
||||||
|
\f[]
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
Use :grep to grep for something, then :cn and :cp to navigate through
|
||||||
|
the matches.
|
||||||
.RE
|
.RE
|
||||||
.SH FILE TYPE MANAGEMENT OPTIONS
|
.SH FILE TYPE MANAGEMENT OPTIONS
|
||||||
.TP
|
.TP
|
||||||
@@ -465,11 +510,12 @@ Unless \-\-type\-clear is used, globs are added to any existing globs
|
|||||||
inside of ripgrep.
|
inside of ripgrep.
|
||||||
Note that this must be passed to every invocation of rg.
|
Note that this must be passed to every invocation of rg.
|
||||||
Type settings are NOT persisted.
|
Type settings are NOT persisted.
|
||||||
|
Example:
|
||||||
.RS
|
.RS
|
||||||
.IP
|
.IP
|
||||||
.nf
|
.nf
|
||||||
\f[C]
|
\f[C]
|
||||||
\ \ Example:\ `rg\ \-\-type\-add\ \[aq]foo:*.foo\[aq]\ \-tfoo\ PATTERN`
|
\ \ rg\ \-\-type\-add\ \[aq]foo:*.foo\[aq]\ \-tfoo\ PATTERN
|
||||||
\f[]
|
\f[]
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
@@ -483,7 +529,7 @@ Markdown files, one can use:
|
|||||||
.IP
|
.IP
|
||||||
.nf
|
.nf
|
||||||
\f[C]
|
\f[C]
|
||||||
\ \ `\-\-type\-add\ \[aq]src:include:cpp,py,md\[aq]`
|
\ \ \-\-type\-add\ \[aq]src:include:cpp,py,md\[aq]
|
||||||
\f[]
|
\f[]
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
@@ -492,7 +538,7 @@ Additional glob rules can still be added to the src type by using the
|
|||||||
.IP
|
.IP
|
||||||
.nf
|
.nf
|
||||||
\f[C]
|
\f[C]
|
||||||
\ \ `\-\-type\-add\ \[aq]src:include:cpp,py,md\[aq]\ \-\-type\-add\ \[aq]src:*.foo\[aq]`
|
\ \ \-\-type\-add\ \[aq]src:include:cpp,py,md\[aq]\ \-\-type\-add\ \[aq]src:*.foo\[aq]
|
||||||
\f[]
|
\f[]
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
|
77
doc/rg.1.md
77
doc/rg.1.md
@@ -4,11 +4,11 @@ rg - recursively search current directory for lines matching a pattern
|
|||||||
|
|
||||||
# SYNOPSIS
|
# SYNOPSIS
|
||||||
|
|
||||||
rg [*options*] <*pattern*> [*<*path*> ...*]
|
rg [*options*] *PATTERN* [*path* ...]
|
||||||
|
|
||||||
rg [*options*] (-e PATTERN | -f FILE) ... [*<*path*> ...*]
|
rg [*options*] [-e *PATTERN* ...] [-f *FILE* ...] [*path* ...]
|
||||||
|
|
||||||
rg [*options*] --files [*<*path*> ...*]
|
rg [*options*] --files [*path* ...]
|
||||||
|
|
||||||
rg [*options*] --type-list
|
rg [*options*] --type-list
|
||||||
|
|
||||||
@@ -25,6 +25,10 @@ ripgrep's regex engine uses finite automata and guarantees linear time
|
|||||||
searching. Because of this, features like backreferences and arbitrary
|
searching. Because of this, features like backreferences and arbitrary
|
||||||
lookaround are not supported.
|
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
|
Project home page: https://github.com/BurntSushi/ripgrep
|
||||||
|
|
||||||
# COMMON OPTIONS
|
# COMMON OPTIONS
|
||||||
@@ -36,8 +40,10 @@ Project home page: https://github.com/BurntSushi/ripgrep
|
|||||||
: Only show count of line matches for each file.
|
: Only show count of line matches for each file.
|
||||||
|
|
||||||
--color *WHEN*
|
--color *WHEN*
|
||||||
: Whether to use coloring in match. Valid values are never, always or auto.
|
: Whether to use color in the output. Valid values are never, auto, always or
|
||||||
[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* ...
|
-e, --regexp *PATTERN* ...
|
||||||
: Use PATTERN to search. This option can be provided multiple times, where all
|
: Use PATTERN to search. This option can be provided multiple times, where all
|
||||||
@@ -54,16 +60,16 @@ Project home page: https://github.com/BurntSushi/ripgrep
|
|||||||
glob flags may be used. Globbing rules match .gitignore globs. Precede a
|
glob flags may be used. Globbing rules match .gitignore globs. Precede a
|
||||||
glob with a '!' to exclude it.
|
glob with a '!' to exclude it.
|
||||||
|
|
||||||
The --glob flag subsumes the functionality of both the --include and
|
The --glob flag subsumes the functionality of both the --include and
|
||||||
--exclude flags commonly found in other tools.
|
--exclude flags commonly found in other tools.
|
||||||
|
|
||||||
Values given to -g must be quoted or your shell will expand them and result
|
Values given to -g must be quoted or your shell will expand them and result
|
||||||
in unexpected behavior.
|
in unexpected behavior.
|
||||||
|
|
||||||
Combine with the --files flag to return matched filenames
|
Combine with the --files flag to return matched filenames
|
||||||
(i.e., to replicate ack/ag's -g flag).
|
(i.e., to replicate ack/ag's -g flag). For example:
|
||||||
|
|
||||||
For example: rg -g '\<glob\>' --files
|
rg -g '*.foo' --files
|
||||||
|
|
||||||
-h, --help
|
-h, --help
|
||||||
: Show this usage message.
|
: Show this usage message.
|
||||||
@@ -91,12 +97,12 @@ Project home page: https://github.com/BurntSushi/ripgrep
|
|||||||
-u, --unrestricted ...
|
-u, --unrestricted ...
|
||||||
: Reduce the level of 'smart' searching. A single -u doesn't respect .gitignore
|
: Reduce the level of 'smart' searching. A single -u doesn't respect .gitignore
|
||||||
(etc.) files. Two -u flags will search hidden files and directories. Three
|
(etc.) files. Two -u flags will search hidden files and directories. Three
|
||||||
-u flags will search binary files. -uu is equivalent to grep -r, and -uuu is
|
-u flags will search binary files. -uu is equivalent to `grep -r`, and -uuu
|
||||||
equivalent to grep -a -r.
|
is equivalent to `grep -a -r`.
|
||||||
|
|
||||||
Note that the -u flags are convenient aliases for other combinations of
|
Note that the -u flags are convenient aliases for other combinations of
|
||||||
flags. -u aliases '--no-ignore'. -uu aliases '--no-ignore --hidden'.
|
flags. -u aliases --no-ignore. -uu aliases --no-ignore --hidden.
|
||||||
-uuu aliases '--no-ignore --hidden --text'.
|
-uuu aliases --no-ignore --hidden --text.
|
||||||
|
|
||||||
-v, --invert-match
|
-v, --invert-match
|
||||||
: Invert matching.
|
: Invert matching.
|
||||||
@@ -105,6 +111,10 @@ Project home page: https://github.com/BurntSushi/ripgrep
|
|||||||
: Only show matches surrounded by word boundaries. This is equivalent to
|
: Only show matches surrounded by word boundaries. This is equivalent to
|
||||||
putting \\b before and after the search pattern.
|
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
|
# LESS COMMON OPTIONS
|
||||||
|
|
||||||
-A, --after-context *NUM*
|
-A, --after-context *NUM*
|
||||||
@@ -130,7 +140,7 @@ Project home page: https://github.com/BurntSushi/ripgrep
|
|||||||
For example, the following command will change the match color to magenta
|
For example, the following command will change the match color to magenta
|
||||||
and the background color for line numbers to yellow:
|
and the background color for line numbers to yellow:
|
||||||
|
|
||||||
rg --colors 'match:fg:magenta' --colors 'line:bg:yellow' foo.
|
rg --colors 'match:fg:magenta' --colors 'line:bg:yellow' foo.
|
||||||
|
|
||||||
--column
|
--column
|
||||||
: Show column numbers (1 based) in output. This only shows the column
|
: Show column numbers (1 based) in output. This only shows the column
|
||||||
@@ -152,7 +162,7 @@ Project home page: https://github.com/BurntSushi/ripgrep
|
|||||||
Other supported values can be found in the list of labels here:
|
Other supported values can be found in the list of labels here:
|
||||||
https://encoding.spec.whatwg.org/#concept-encoding-get
|
https://encoding.spec.whatwg.org/#concept-encoding-get
|
||||||
|
|
||||||
-f, --file FILE ...
|
-f, --file *FILE* ...
|
||||||
: Search for patterns from the given file, with one pattern per line. When this
|
: Search for patterns from the given file, with one pattern per line. When this
|
||||||
flag is used or multiple times or in combination with the -e/--regexp flag,
|
flag is used or multiple times or in combination with the -e/--regexp flag,
|
||||||
then all patterns provided are searched. Empty pattern lines will match all
|
then all patterns provided are searched. Empty pattern lines will match all
|
||||||
@@ -163,7 +173,7 @@ Project home page: https://github.com/BurntSushi/ripgrep
|
|||||||
|
|
||||||
Combine with the -g flag to return matched paths, for example:
|
Combine with the -g flag to return matched paths, for example:
|
||||||
|
|
||||||
rg -g '\<glob\>' --files
|
rg -g '*.foo' --files
|
||||||
|
|
||||||
-l, --files-with-matches
|
-l, --files-with-matches
|
||||||
: Only show path of each file with matches.
|
: Only show path of each file with matches.
|
||||||
@@ -185,14 +195,21 @@ Project home page: https://github.com/BurntSushi/ripgrep
|
|||||||
|
|
||||||
--no-heading
|
--no-heading
|
||||||
: Don't group matches by each file. If -H/--with-filename is enabled, then
|
: Don't group matches by each file. If -H/--with-filename is enabled, then
|
||||||
file names will be shown for every line matched. This is the default more
|
file names will be shown for every line matched. This is the default mode
|
||||||
when not at a tty.
|
when not at a tty.
|
||||||
|
|
||||||
--hidden
|
--hidden
|
||||||
: Search hidden directories and files. (Hidden directories and files are
|
: Search hidden directories and files. (Hidden directories and files are
|
||||||
skipped by default.)
|
skipped by default.)
|
||||||
|
|
||||||
--ignore-file FILE ...
|
--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.
|
: Specify additional ignore files for filtering file paths.
|
||||||
Ignore files should be in the gitignore format and are matched
|
Ignore files should be in the gitignore format and are matched
|
||||||
relative to the current working directory. These ignore files
|
relative to the current working directory. These ignore files
|
||||||
@@ -260,7 +277,7 @@ Project home page: https://github.com/BurntSushi/ripgrep
|
|||||||
cygwin). A path separator is limited to a single byte.
|
cygwin). A path separator is limited to a single byte.
|
||||||
|
|
||||||
-p, --pretty
|
-p, --pretty
|
||||||
: Alias for --color=always --heading -n.
|
: Alias for --color=always --heading --line-number.
|
||||||
|
|
||||||
-r, --replace *ARG*
|
-r, --replace *ARG*
|
||||||
: Replace every match with the string given when printing search results.
|
: Replace every match with the string given when printing search results.
|
||||||
@@ -295,9 +312,17 @@ Project home page: https://github.com/BurntSushi/ripgrep
|
|||||||
: Show the version number of ripgrep and exit.
|
: Show the version number of ripgrep and exit.
|
||||||
|
|
||||||
--vimgrep
|
--vimgrep
|
||||||
: Show results with every match on its own line, including line
|
: Show results with every match on its own line, including
|
||||||
numbers and column numbers. (With this option, a line with more
|
line numbers and column numbers. With this option, a line with
|
||||||
than one match of the regex will be printed more than once.)
|
more than one match will be printed more than once.
|
||||||
|
|
||||||
|
Recommended .vimrc configuration:
|
||||||
|
|
||||||
|
set grepprg=rg\ --vimgrep
|
||||||
|
set grepformat^=%f:%l:%c:%m
|
||||||
|
|
||||||
|
Use :grep to grep for something, then :cn and :cp to navigate through the
|
||||||
|
matches.
|
||||||
|
|
||||||
# FILE TYPE MANAGEMENT OPTIONS
|
# FILE TYPE MANAGEMENT OPTIONS
|
||||||
|
|
||||||
@@ -309,9 +334,9 @@ Project home page: https://github.com/BurntSushi/ripgrep
|
|||||||
at a time. Multiple --type-add flags can be provided. Unless --type-clear
|
at a time. Multiple --type-add flags can be provided. Unless --type-clear
|
||||||
is used, globs are added to any existing globs inside of ripgrep. Note that
|
is used, globs are added to any existing globs inside of ripgrep. Note that
|
||||||
this must be passed to every invocation of rg. Type settings are NOT
|
this must be passed to every invocation of rg. Type settings are NOT
|
||||||
persisted.
|
persisted. Example:
|
||||||
|
|
||||||
Example: `rg --type-add 'foo:*.foo' -tfoo PATTERN`
|
rg --type-add 'foo:*.foo' -tfoo PATTERN
|
||||||
|
|
||||||
--type-add can also be used to include rules from other types
|
--type-add can also be used to include rules from other types
|
||||||
with the special include directive. The include directive
|
with the special include directive. The include directive
|
||||||
@@ -321,12 +346,12 @@ Project home page: https://github.com/BurntSushi/ripgrep
|
|||||||
type called src that matches C++, Python and Markdown files, one
|
type called src that matches C++, Python and Markdown files, one
|
||||||
can use:
|
can use:
|
||||||
|
|
||||||
`--type-add 'src:include:cpp,py,md'`
|
--type-add 'src:include:cpp,py,md'
|
||||||
|
|
||||||
Additional glob rules can still be added to the src type by
|
Additional glob rules can still be added to the src type by
|
||||||
using the --type-add flag again:
|
using the --type-add flag again:
|
||||||
|
|
||||||
`--type-add 'src:include:cpp,py,md' --type-add 'src:*.foo'`
|
--type-add 'src:include:cpp,py,md' --type-add 'src:*.foo'
|
||||||
|
|
||||||
Note that type names must consist only of Unicode letters or
|
Note that type names must consist only of Unicode letters or
|
||||||
numbers. Punctuation characters are not allowed.
|
numbers. Punctuation characters are not allowed.
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "globset"
|
name = "globset"
|
||||||
version = "0.1.4" #:version
|
version = "0.2.0" #:version
|
||||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||||
description = """
|
description = """
|
||||||
Cross platform single glob and glob set matching. Glob set matching is the
|
Cross platform single glob and glob set matching. Glob set matching is the
|
||||||
|
@@ -9,7 +9,7 @@ use std::str;
|
|||||||
use regex;
|
use regex;
|
||||||
use regex::bytes::Regex;
|
use regex::bytes::Regex;
|
||||||
|
|
||||||
use {Candidate, Error, new_regex};
|
use {Candidate, Error, ErrorKind, new_regex};
|
||||||
|
|
||||||
/// Describes a matching strategy for a particular pattern.
|
/// Describes a matching strategy for a particular pattern.
|
||||||
///
|
///
|
||||||
@@ -544,6 +544,7 @@ impl<'a> GlobBuilder<'a> {
|
|||||||
/// Parses and builds the pattern.
|
/// Parses and builds the pattern.
|
||||||
pub fn build(&self) -> Result<Glob, Error> {
|
pub fn build(&self) -> Result<Glob, Error> {
|
||||||
let mut p = Parser {
|
let mut p = Parser {
|
||||||
|
glob: &self.glob,
|
||||||
stack: vec![Tokens::default()],
|
stack: vec![Tokens::default()],
|
||||||
chars: self.glob.chars().peekable(),
|
chars: self.glob.chars().peekable(),
|
||||||
prev: None,
|
prev: None,
|
||||||
@@ -551,9 +552,15 @@ impl<'a> GlobBuilder<'a> {
|
|||||||
};
|
};
|
||||||
try!(p.parse());
|
try!(p.parse());
|
||||||
if p.stack.is_empty() {
|
if p.stack.is_empty() {
|
||||||
Err(Error::UnopenedAlternates)
|
Err(Error {
|
||||||
|
glob: Some(self.glob.to_string()),
|
||||||
|
kind: ErrorKind::UnopenedAlternates,
|
||||||
|
})
|
||||||
} else if p.stack.len() > 1 {
|
} else if p.stack.len() > 1 {
|
||||||
Err(Error::UnclosedAlternates)
|
Err(Error {
|
||||||
|
glob: Some(self.glob.to_string()),
|
||||||
|
kind: ErrorKind::UnclosedAlternates,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
let tokens = p.stack.pop().unwrap();
|
let tokens = p.stack.pop().unwrap();
|
||||||
Ok(Glob {
|
Ok(Glob {
|
||||||
@@ -698,6 +705,7 @@ fn bytes_to_escaped_literal(bs: &[u8]) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Parser<'a> {
|
struct Parser<'a> {
|
||||||
|
glob: &'a str,
|
||||||
stack: Vec<Tokens>,
|
stack: Vec<Tokens>,
|
||||||
chars: iter::Peekable<str::Chars<'a>>,
|
chars: iter::Peekable<str::Chars<'a>>,
|
||||||
prev: Option<char>,
|
prev: Option<char>,
|
||||||
@@ -705,6 +713,10 @@ struct Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Parser<'a> {
|
impl<'a> Parser<'a> {
|
||||||
|
fn error(&self, kind: ErrorKind) -> Error {
|
||||||
|
Error { glob: Some(self.glob.to_string()), kind: kind }
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(&mut self) -> Result<(), Error> {
|
fn parse(&mut self) -> Result<(), Error> {
|
||||||
while let Some(c) = self.bump() {
|
while let Some(c) = self.bump() {
|
||||||
match c {
|
match c {
|
||||||
@@ -729,7 +741,7 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
fn push_alternate(&mut self) -> Result<(), Error> {
|
fn push_alternate(&mut self) -> Result<(), Error> {
|
||||||
if self.stack.len() > 1 {
|
if self.stack.len() > 1 {
|
||||||
return Err(Error::NestedAlternates);
|
return Err(self.error(ErrorKind::NestedAlternates));
|
||||||
}
|
}
|
||||||
Ok(self.stack.push(Tokens::default()))
|
Ok(self.stack.push(Tokens::default()))
|
||||||
}
|
}
|
||||||
@@ -743,22 +755,22 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn push_token(&mut self, tok: Token) -> Result<(), Error> {
|
fn push_token(&mut self, tok: Token) -> Result<(), Error> {
|
||||||
match self.stack.last_mut() {
|
if let Some(ref mut pat) = self.stack.last_mut() {
|
||||||
None => Err(Error::UnopenedAlternates),
|
return Ok(pat.push(tok));
|
||||||
Some(ref mut pat) => Ok(pat.push(tok)),
|
|
||||||
}
|
}
|
||||||
|
Err(self.error(ErrorKind::UnopenedAlternates))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop_token(&mut self) -> Result<Token, Error> {
|
fn pop_token(&mut self) -> Result<Token, Error> {
|
||||||
match self.stack.last_mut() {
|
if let Some(ref mut pat) = self.stack.last_mut() {
|
||||||
None => Err(Error::UnopenedAlternates),
|
return Ok(pat.pop().unwrap());
|
||||||
Some(ref mut pat) => Ok(pat.pop().unwrap()),
|
|
||||||
}
|
}
|
||||||
|
Err(self.error(ErrorKind::UnopenedAlternates))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn have_tokens(&self) -> Result<bool, Error> {
|
fn have_tokens(&self) -> Result<bool, Error> {
|
||||||
match self.stack.last() {
|
match self.stack.last() {
|
||||||
None => Err(Error::UnopenedAlternates),
|
None => Err(self.error(ErrorKind::UnopenedAlternates)),
|
||||||
Some(ref pat) => Ok(!pat.is_empty()),
|
Some(ref pat) => Ok(!pat.is_empty()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -785,7 +797,7 @@ impl<'a> Parser<'a> {
|
|||||||
try!(self.push_token(Token::RecursivePrefix));
|
try!(self.push_token(Token::RecursivePrefix));
|
||||||
let next = self.bump();
|
let next = self.bump();
|
||||||
if !next.map(is_separator).unwrap_or(true) {
|
if !next.map(is_separator).unwrap_or(true) {
|
||||||
return Err(Error::InvalidRecursive);
|
return Err(self.error(ErrorKind::InvalidRecursive));
|
||||||
}
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@@ -793,7 +805,7 @@ impl<'a> Parser<'a> {
|
|||||||
if !prev.map(is_separator).unwrap_or(false) {
|
if !prev.map(is_separator).unwrap_or(false) {
|
||||||
if self.stack.len() <= 1
|
if self.stack.len() <= 1
|
||||||
|| (prev != Some(',') && prev != Some('{')) {
|
|| (prev != Some(',') && prev != Some('{')) {
|
||||||
return Err(Error::InvalidRecursive);
|
return Err(self.error(ErrorKind::InvalidRecursive));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match self.chars.peek() {
|
match self.chars.peek() {
|
||||||
@@ -808,18 +820,22 @@ impl<'a> Parser<'a> {
|
|||||||
assert!(self.bump().map(is_separator).unwrap_or(false));
|
assert!(self.bump().map(is_separator).unwrap_or(false));
|
||||||
self.push_token(Token::RecursiveZeroOrMore)
|
self.push_token(Token::RecursiveZeroOrMore)
|
||||||
}
|
}
|
||||||
_ => Err(Error::InvalidRecursive),
|
_ => Err(self.error(ErrorKind::InvalidRecursive)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_class(&mut self) -> Result<(), Error> {
|
fn parse_class(&mut self) -> Result<(), Error> {
|
||||||
fn add_to_last_range(
|
fn add_to_last_range(
|
||||||
|
glob: &str,
|
||||||
r: &mut (char, char),
|
r: &mut (char, char),
|
||||||
add: char,
|
add: char,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
r.1 = add;
|
r.1 = add;
|
||||||
if r.1 < r.0 {
|
if r.1 < r.0 {
|
||||||
Err(Error::InvalidRange(r.0, r.1))
|
Err(Error {
|
||||||
|
glob: Some(glob.to_string()),
|
||||||
|
kind: ErrorKind::InvalidRange(r.0, r.1),
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -837,7 +853,7 @@ impl<'a> Parser<'a> {
|
|||||||
Some(c) => c,
|
Some(c) => c,
|
||||||
// The only way to successfully break this loop is to observe
|
// The only way to successfully break this loop is to observe
|
||||||
// a ']'.
|
// a ']'.
|
||||||
None => return Err(Error::UnclosedClass),
|
None => return Err(self.error(ErrorKind::UnclosedClass)),
|
||||||
};
|
};
|
||||||
match c {
|
match c {
|
||||||
']' => {
|
']' => {
|
||||||
@@ -854,7 +870,7 @@ impl<'a> Parser<'a> {
|
|||||||
// invariant: in_range is only set when there is
|
// invariant: in_range is only set when there is
|
||||||
// already at least one character seen.
|
// already at least one character seen.
|
||||||
let r = ranges.last_mut().unwrap();
|
let r = ranges.last_mut().unwrap();
|
||||||
try!(add_to_last_range(r, '-'));
|
try!(add_to_last_range(&self.glob, r, '-'));
|
||||||
in_range = false;
|
in_range = false;
|
||||||
} else {
|
} else {
|
||||||
assert!(!ranges.is_empty());
|
assert!(!ranges.is_empty());
|
||||||
@@ -865,7 +881,8 @@ impl<'a> Parser<'a> {
|
|||||||
if in_range {
|
if in_range {
|
||||||
// invariant: in_range is only set when there is
|
// invariant: in_range is only set when there is
|
||||||
// already at least one character seen.
|
// already at least one character seen.
|
||||||
try!(add_to_last_range(ranges.last_mut().unwrap(), c));
|
try!(add_to_last_range(
|
||||||
|
&self.glob, ranges.last_mut().unwrap(), c));
|
||||||
} else {
|
} else {
|
||||||
ranges.push((c, c));
|
ranges.push((c, c));
|
||||||
}
|
}
|
||||||
@@ -909,7 +926,7 @@ fn ends_with(needle: &[u8], haystack: &[u8]) -> bool {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use std::ffi::{OsStr, OsString};
|
use std::ffi::{OsStr, OsString};
|
||||||
|
|
||||||
use {GlobSetBuilder, Error};
|
use {GlobSetBuilder, ErrorKind};
|
||||||
use super::{Glob, GlobBuilder, Token};
|
use super::{Glob, GlobBuilder, Token};
|
||||||
use super::Token::*;
|
use super::Token::*;
|
||||||
|
|
||||||
@@ -934,7 +951,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn $name() {
|
fn $name() {
|
||||||
let err = Glob::new($pat).unwrap_err();
|
let err = Glob::new($pat).unwrap_err();
|
||||||
assert_eq!($err, err);
|
assert_eq!(&$err, err.kind());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1057,19 +1074,19 @@ mod tests {
|
|||||||
syntax!(cls18, "[!0-9a-z]", vec![rclassn(&[('0', '9'), ('a', 'z')])]);
|
syntax!(cls18, "[!0-9a-z]", vec![rclassn(&[('0', '9'), ('a', 'z')])]);
|
||||||
syntax!(cls19, "[!a-z0-9]", vec![rclassn(&[('a', 'z'), ('0', '9')])]);
|
syntax!(cls19, "[!a-z0-9]", vec![rclassn(&[('a', 'z'), ('0', '9')])]);
|
||||||
|
|
||||||
syntaxerr!(err_rseq1, "a**", Error::InvalidRecursive);
|
syntaxerr!(err_rseq1, "a**", ErrorKind::InvalidRecursive);
|
||||||
syntaxerr!(err_rseq2, "**a", Error::InvalidRecursive);
|
syntaxerr!(err_rseq2, "**a", ErrorKind::InvalidRecursive);
|
||||||
syntaxerr!(err_rseq3, "a**b", Error::InvalidRecursive);
|
syntaxerr!(err_rseq3, "a**b", ErrorKind::InvalidRecursive);
|
||||||
syntaxerr!(err_rseq4, "***", Error::InvalidRecursive);
|
syntaxerr!(err_rseq4, "***", ErrorKind::InvalidRecursive);
|
||||||
syntaxerr!(err_rseq5, "/a**", Error::InvalidRecursive);
|
syntaxerr!(err_rseq5, "/a**", ErrorKind::InvalidRecursive);
|
||||||
syntaxerr!(err_rseq6, "/**a", Error::InvalidRecursive);
|
syntaxerr!(err_rseq6, "/**a", ErrorKind::InvalidRecursive);
|
||||||
syntaxerr!(err_rseq7, "/a**b", Error::InvalidRecursive);
|
syntaxerr!(err_rseq7, "/a**b", ErrorKind::InvalidRecursive);
|
||||||
syntaxerr!(err_unclosed1, "[", Error::UnclosedClass);
|
syntaxerr!(err_unclosed1, "[", ErrorKind::UnclosedClass);
|
||||||
syntaxerr!(err_unclosed2, "[]", Error::UnclosedClass);
|
syntaxerr!(err_unclosed2, "[]", ErrorKind::UnclosedClass);
|
||||||
syntaxerr!(err_unclosed3, "[!", Error::UnclosedClass);
|
syntaxerr!(err_unclosed3, "[!", ErrorKind::UnclosedClass);
|
||||||
syntaxerr!(err_unclosed4, "[!]", Error::UnclosedClass);
|
syntaxerr!(err_unclosed4, "[!]", ErrorKind::UnclosedClass);
|
||||||
syntaxerr!(err_range1, "[z-a]", Error::InvalidRange('z', 'a'));
|
syntaxerr!(err_range1, "[z-a]", ErrorKind::InvalidRange('z', 'a'));
|
||||||
syntaxerr!(err_range2, "[z--]", Error::InvalidRange('z', '-'));
|
syntaxerr!(err_range2, "[z--]", ErrorKind::InvalidRange('z', '-'));
|
||||||
|
|
||||||
const CASEI: Options = Options {
|
const CASEI: Options = Options {
|
||||||
casei: true,
|
casei: true,
|
||||||
|
@@ -128,7 +128,16 @@ mod pathutil;
|
|||||||
|
|
||||||
/// Represents an error that can occur when parsing a glob pattern.
|
/// Represents an error that can occur when parsing a glob pattern.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum Error {
|
pub struct Error {
|
||||||
|
/// The original glob provided by the caller.
|
||||||
|
glob: Option<String>,
|
||||||
|
/// The kind of error.
|
||||||
|
kind: ErrorKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The kind of error that can occur when parsing a glob pattern.
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub enum ErrorKind {
|
||||||
/// Occurs when a use of `**` is invalid. Namely, `**` can only appear
|
/// Occurs when a use of `**` is invalid. Namely, `**` can only appear
|
||||||
/// adjacent to a path separator, or the beginning/end of a glob.
|
/// adjacent to a path separator, or the beginning/end of a glob.
|
||||||
InvalidRecursive,
|
InvalidRecursive,
|
||||||
@@ -150,45 +159,74 @@ pub enum Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StdError for Error {
|
impl StdError for Error {
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
self.kind.description()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error {
|
||||||
|
/// Return the glob that caused this error, if one exists.
|
||||||
|
pub fn glob(&self) -> Option<&str> {
|
||||||
|
self.glob.as_ref().map(|s| &**s)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the kind of this error.
|
||||||
|
pub fn kind(&self) -> &ErrorKind {
|
||||||
|
&self.kind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ErrorKind {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
match *self {
|
match *self {
|
||||||
Error::InvalidRecursive => {
|
ErrorKind::InvalidRecursive => {
|
||||||
"invalid use of **; must be one path component"
|
"invalid use of **; must be one path component"
|
||||||
}
|
}
|
||||||
Error::UnclosedClass => {
|
ErrorKind::UnclosedClass => {
|
||||||
"unclosed character class; missing ']'"
|
"unclosed character class; missing ']'"
|
||||||
}
|
}
|
||||||
Error::InvalidRange(_, _) => {
|
ErrorKind::InvalidRange(_, _) => {
|
||||||
"invalid character range"
|
"invalid character range"
|
||||||
}
|
}
|
||||||
Error::UnopenedAlternates => {
|
ErrorKind::UnopenedAlternates => {
|
||||||
"unopened alternate group; missing '{' \
|
"unopened alternate group; missing '{' \
|
||||||
(maybe escape '}' with '[}]'?)"
|
(maybe escape '}' with '[}]'?)"
|
||||||
}
|
}
|
||||||
Error::UnclosedAlternates => {
|
ErrorKind::UnclosedAlternates => {
|
||||||
"unclosed alternate group; missing '}' \
|
"unclosed alternate group; missing '}' \
|
||||||
(maybe escape '{' with '[{]'?)"
|
(maybe escape '{' with '[{]'?)"
|
||||||
}
|
}
|
||||||
Error::NestedAlternates => {
|
ErrorKind::NestedAlternates => {
|
||||||
"nested alternate groups are not allowed"
|
"nested alternate groups are not allowed"
|
||||||
}
|
}
|
||||||
Error::Regex(ref err) => err,
|
ErrorKind::Regex(ref err) => err,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self.glob {
|
||||||
|
None => self.kind.fmt(f),
|
||||||
|
Some(ref glob) => {
|
||||||
|
write!(f, "error parsing glob '{}': {}", glob, self.kind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ErrorKind {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Error::InvalidRecursive
|
ErrorKind::InvalidRecursive
|
||||||
| Error::UnclosedClass
|
| ErrorKind::UnclosedClass
|
||||||
| Error::UnopenedAlternates
|
| ErrorKind::UnopenedAlternates
|
||||||
| Error::UnclosedAlternates
|
| ErrorKind::UnclosedAlternates
|
||||||
| Error::NestedAlternates
|
| ErrorKind::NestedAlternates
|
||||||
| Error::Regex(_) => {
|
| ErrorKind::Regex(_) => {
|
||||||
write!(f, "{}", self.description())
|
write!(f, "{}", self.description())
|
||||||
}
|
}
|
||||||
Error::InvalidRange(s, e) => {
|
ErrorKind::InvalidRange(s, e) => {
|
||||||
write!(f, "invalid range; '{}' > '{}'", s, e)
|
write!(f, "invalid range; '{}' > '{}'", s, e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,12 +239,22 @@ fn new_regex(pat: &str) -> Result<Regex, Error> {
|
|||||||
.size_limit(10 * (1 << 20))
|
.size_limit(10 * (1 << 20))
|
||||||
.dfa_size_limit(10 * (1 << 20))
|
.dfa_size_limit(10 * (1 << 20))
|
||||||
.build()
|
.build()
|
||||||
.map_err(|err| Error::Regex(err.to_string()))
|
.map_err(|err| {
|
||||||
|
Error {
|
||||||
|
glob: Some(pat.to_string()),
|
||||||
|
kind: ErrorKind::Regex(err.to_string()),
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_regex_set<I, S>(pats: I) -> Result<RegexSet, Error>
|
fn new_regex_set<I, S>(pats: I) -> Result<RegexSet, Error>
|
||||||
where S: AsRef<str>, I: IntoIterator<Item=S> {
|
where S: AsRef<str>, I: IntoIterator<Item=S> {
|
||||||
RegexSet::new(pats).map_err(|err| Error::Regex(err.to_string()))
|
RegexSet::new(pats).map_err(|err| {
|
||||||
|
Error {
|
||||||
|
glob: None,
|
||||||
|
kind: ErrorKind::Regex(err.to_string()),
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type Fnv = hash::BuildHasherDefault<fnv::FnvHasher>;
|
type Fnv = hash::BuildHasherDefault<fnv::FnvHasher>;
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ignore"
|
name = "ignore"
|
||||||
version = "0.1.9" #:version
|
version = "0.2.2" #:version
|
||||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||||
description = """
|
description = """
|
||||||
A fast library for efficiently matching ignore files such as `.gitignore`
|
A fast library for efficiently matching ignore files such as `.gitignore`
|
||||||
@@ -19,7 +19,7 @@ bench = false
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
crossbeam = "0.2"
|
crossbeam = "0.2"
|
||||||
globset = { version = "0.1.4", path = "../globset" }
|
globset = { version = "0.2.0", path = "../globset" }
|
||||||
lazy_static = "0.2"
|
lazy_static = "0.2"
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
memchr = "1"
|
memchr = "1"
|
||||||
|
@@ -20,7 +20,7 @@ Add this to your `Cargo.toml`:
|
|||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ignore = "0.1"
|
ignore = "0.2"
|
||||||
```
|
```
|
||||||
|
|
||||||
and this to your crate root:
|
and this to your crate root:
|
||||||
|
@@ -169,8 +169,8 @@ impl Gitignore {
|
|||||||
self.num_whitelists
|
self.num_whitelists
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the given file path matched a pattern in this gitignore
|
/// Returns whether the given path (file or directory) matched a pattern in
|
||||||
/// matcher.
|
/// this gitignore matcher.
|
||||||
///
|
///
|
||||||
/// `is_dir` should be true if the path refers to a directory and false
|
/// `is_dir` should be true if the path refers to a directory and false
|
||||||
/// otherwise.
|
/// otherwise.
|
||||||
@@ -191,6 +191,48 @@ impl Gitignore {
|
|||||||
self.matched_stripped(self.strip(path.as_ref()), is_dir)
|
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.
|
/// Like matched, but takes a path that has already been stripped.
|
||||||
fn matched_stripped<P: AsRef<Path>>(
|
fn matched_stripped<P: AsRef<Path>>(
|
||||||
&self,
|
&self,
|
||||||
@@ -254,6 +296,7 @@ pub struct GitignoreBuilder {
|
|||||||
builder: GlobSetBuilder,
|
builder: GlobSetBuilder,
|
||||||
root: PathBuf,
|
root: PathBuf,
|
||||||
globs: Vec<Glob>,
|
globs: Vec<Glob>,
|
||||||
|
case_insensitive: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GitignoreBuilder {
|
impl GitignoreBuilder {
|
||||||
@@ -269,6 +312,7 @@ impl GitignoreBuilder {
|
|||||||
builder: GlobSetBuilder::new(),
|
builder: GlobSetBuilder::new(),
|
||||||
root: strip_prefix("./", root).unwrap_or(root).to_path_buf(),
|
root: strip_prefix("./", root).unwrap_or(root).to_path_buf(),
|
||||||
globs: vec![],
|
globs: vec![],
|
||||||
|
case_insensitive: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,7 +323,12 @@ impl GitignoreBuilder {
|
|||||||
let nignore = self.globs.iter().filter(|g| !g.is_whitelist()).count();
|
let nignore = self.globs.iter().filter(|g| !g.is_whitelist()).count();
|
||||||
let nwhite = self.globs.iter().filter(|g| g.is_whitelist()).count();
|
let nwhite = self.globs.iter().filter(|g| g.is_whitelist()).count();
|
||||||
let set = try!(
|
let set = try!(
|
||||||
self.builder.build().map_err(|err| Error::Glob(err.to_string())));
|
self.builder.build().map_err(|err| {
|
||||||
|
Error::Glob {
|
||||||
|
glob: None,
|
||||||
|
err: err.to_string(),
|
||||||
|
}
|
||||||
|
}));
|
||||||
Ok(Gitignore {
|
Ok(Gitignore {
|
||||||
set: set,
|
set: set,
|
||||||
root: self.root.clone(),
|
root: self.root.clone(),
|
||||||
@@ -419,12 +468,28 @@ impl GitignoreBuilder {
|
|||||||
let parsed = try!(
|
let parsed = try!(
|
||||||
GlobBuilder::new(&glob.actual)
|
GlobBuilder::new(&glob.actual)
|
||||||
.literal_separator(literal_separator)
|
.literal_separator(literal_separator)
|
||||||
|
.case_insensitive(self.case_insensitive)
|
||||||
.build()
|
.build()
|
||||||
.map_err(|err| Error::Glob(err.to_string())));
|
.map_err(|err| {
|
||||||
|
Error::Glob {
|
||||||
|
glob: Some(glob.original.clone()),
|
||||||
|
err: err.kind().to_string(),
|
||||||
|
}
|
||||||
|
}));
|
||||||
self.builder.add(parsed);
|
self.builder.add(parsed);
|
||||||
self.globs.push(glob);
|
self.globs.push(glob);
|
||||||
Ok(self)
|
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.
|
/// Return the file path of the current environment's global gitignore file.
|
||||||
@@ -607,4 +672,21 @@ mod tests {
|
|||||||
fn regression_106() {
|
fn regression_106() {
|
||||||
gi_from_str("/", " ");
|
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");
|
||||||
}
|
}
|
||||||
|
@@ -112,7 +112,17 @@ pub enum Error {
|
|||||||
/// An error that occurs when doing I/O, such as reading an ignore file.
|
/// An error that occurs when doing I/O, such as reading an ignore file.
|
||||||
Io(io::Error),
|
Io(io::Error),
|
||||||
/// An error that occurs when trying to parse a glob.
|
/// An error that occurs when trying to parse a glob.
|
||||||
Glob(String),
|
Glob {
|
||||||
|
/// The original glob that caused this error. This glob, when
|
||||||
|
/// available, always corresponds to the glob provided by an end user.
|
||||||
|
/// e.g., It is the glob as writtein in a `.gitignore` file.
|
||||||
|
///
|
||||||
|
/// (This glob may be distinct from the glob that is actually
|
||||||
|
/// compiled, after accounting for `gitignore` semantics.)
|
||||||
|
glob: Option<String>,
|
||||||
|
/// The underlying glob error as a string.
|
||||||
|
err: String,
|
||||||
|
},
|
||||||
/// A type selection for a file type that is not defined.
|
/// A type selection for a file type that is not defined.
|
||||||
UnrecognizedFileType(String),
|
UnrecognizedFileType(String),
|
||||||
/// A user specified file type definition could not be parsed.
|
/// A user specified file type definition could not be parsed.
|
||||||
@@ -144,7 +154,7 @@ impl Error {
|
|||||||
Error::WithDepth { ref err, .. } => err.is_io(),
|
Error::WithDepth { ref err, .. } => err.is_io(),
|
||||||
Error::Loop { .. } => false,
|
Error::Loop { .. } => false,
|
||||||
Error::Io(_) => true,
|
Error::Io(_) => true,
|
||||||
Error::Glob(_) => false,
|
Error::Glob { .. } => false,
|
||||||
Error::UnrecognizedFileType(_) => false,
|
Error::UnrecognizedFileType(_) => false,
|
||||||
Error::InvalidDefinition => false,
|
Error::InvalidDefinition => false,
|
||||||
}
|
}
|
||||||
@@ -199,7 +209,7 @@ impl error::Error for Error {
|
|||||||
Error::WithDepth { ref err, .. } => err.description(),
|
Error::WithDepth { ref err, .. } => err.description(),
|
||||||
Error::Loop { .. } => "file system loop found",
|
Error::Loop { .. } => "file system loop found",
|
||||||
Error::Io(ref err) => err.description(),
|
Error::Io(ref err) => err.description(),
|
||||||
Error::Glob(ref msg) => msg,
|
Error::Glob { ref err, .. } => err,
|
||||||
Error::UnrecognizedFileType(_) => "unrecognized file type",
|
Error::UnrecognizedFileType(_) => "unrecognized file type",
|
||||||
Error::InvalidDefinition => "invalid definition",
|
Error::InvalidDefinition => "invalid definition",
|
||||||
}
|
}
|
||||||
@@ -227,7 +237,10 @@ impl fmt::Display for Error {
|
|||||||
child.display(), ancestor.display())
|
child.display(), ancestor.display())
|
||||||
}
|
}
|
||||||
Error::Io(ref err) => err.fmt(f),
|
Error::Io(ref err) => err.fmt(f),
|
||||||
Error::Glob(ref msg) => write!(f, "{}", msg),
|
Error::Glob { glob: None, ref err } => write!(f, "{}", err),
|
||||||
|
Error::Glob { glob: Some(ref glob), ref err } => {
|
||||||
|
write!(f, "error parsing glob '{}': {}", glob, err)
|
||||||
|
}
|
||||||
Error::UnrecognizedFileType(ref ty) => {
|
Error::UnrecognizedFileType(ref ty) => {
|
||||||
write!(f, "unrecognized file type: {}", ty)
|
write!(f, "unrecognized file type: {}", ty)
|
||||||
}
|
}
|
||||||
|
@@ -137,6 +137,16 @@ impl OverrideBuilder {
|
|||||||
try!(self.builder.add_line(None, glob));
|
try!(self.builder.add_line(None, glob));
|
||||||
Ok(self)
|
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)]
|
#[cfg(test)]
|
||||||
@@ -220,4 +230,27 @@ mod tests {
|
|||||||
let ov = ov(&["!/bar"]);
|
let ov = ov(&["!/bar"]);
|
||||||
assert!(ov.matched("./foo/bar", false).is_none());
|
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"]),
|
("asciidoc", &["*.adoc", "*.asc", "*.asciidoc"]),
|
||||||
("asm", &["*.asm", "*.s", "*.S"]),
|
("asm", &["*.asm", "*.s", "*.S"]),
|
||||||
("awk", &["*.awk"]),
|
("awk", &["*.awk"]),
|
||||||
|
("bitbake", &["*.bb", "*.bbappend", "*.bbclass", "*.conf", "*.inc"]),
|
||||||
("c", &["*.c", "*.h", "*.H"]),
|
("c", &["*.c", "*.h", "*.H"]),
|
||||||
|
("cabal", &["*.cabal"]),
|
||||||
("cbor", &["*.cbor"]),
|
("cbor", &["*.cbor"]),
|
||||||
("ceylon", &["*.ceylon"]),
|
("ceylon", &["*.ceylon"]),
|
||||||
("clojure", &["*.clj", "*.cljc", "*.cljs", "*.cljx"]),
|
("clojure", &["*.clj", "*.cljc", "*.cljs", "*.cljx"]),
|
||||||
@@ -111,11 +113,12 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
|
|||||||
("config", &["*.config"]),
|
("config", &["*.config"]),
|
||||||
("cpp", &[
|
("cpp", &[
|
||||||
"*.C", "*.cc", "*.cpp", "*.cxx",
|
"*.C", "*.cc", "*.cpp", "*.cxx",
|
||||||
"*.h", "*.H", "*.hh", "*.hpp",
|
"*.h", "*.H", "*.hh", "*.hpp", "*.inl",
|
||||||
]),
|
]),
|
||||||
("crystal", &["Projectfile", "*.cr"]),
|
("crystal", &["Projectfile", "*.cr"]),
|
||||||
("cs", &["*.cs"]),
|
("cs", &["*.cs"]),
|
||||||
("csharp", &["*.cs"]),
|
("csharp", &["*.cs"]),
|
||||||
|
("cshtml", &["*.cshtml"]),
|
||||||
("css", &["*.css", "*.scss"]),
|
("css", &["*.css", "*.scss"]),
|
||||||
("cython", &["*.pyx"]),
|
("cython", &["*.pyx"]),
|
||||||
("dart", &["*.dart"]),
|
("dart", &["*.dart"]),
|
||||||
@@ -142,19 +145,23 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
|
|||||||
]),
|
]),
|
||||||
("json", &["*.json"]),
|
("json", &["*.json"]),
|
||||||
("jsonl", &["*.jsonl"]),
|
("jsonl", &["*.jsonl"]),
|
||||||
|
("julia", &["*.jl"]),
|
||||||
|
("jl", &["*.jl"]),
|
||||||
("kotlin", &["*.kt", "*.kts"]),
|
("kotlin", &["*.kt", "*.kts"]),
|
||||||
("less", &["*.less"]),
|
("less", &["*.less"]),
|
||||||
("lisp", &["*.el", "*.jl", "*.lisp", "*.lsp", "*.sc", "*.scm"]),
|
("lisp", &["*.el", "*.jl", "*.lisp", "*.lsp", "*.sc", "*.scm"]),
|
||||||
("log", &["*.log"]),
|
("log", &["*.log"]),
|
||||||
("lua", &["*.lua"]),
|
("lua", &["*.lua"]),
|
||||||
("m4", &["*.ac", "*.m4"]),
|
("m4", &["*.ac", "*.m4"]),
|
||||||
("make", &["gnumakefile", "Gnumakefile", "makefile", "Makefile", "*.mk", "*.mak"]),
|
("make", &["gnumakefile", "Gnumakefile", "GNUmakefile", "makefile", "Makefile", "*.mk", "*.mak"]),
|
||||||
("markdown", &["*.markdown", "*.md", "*.mdown", "*.mkdn"]),
|
("markdown", &["*.markdown", "*.md", "*.mdown", "*.mkdn"]),
|
||||||
("md", &["*.markdown", "*.md", "*.mdown", "*.mkdn"]),
|
("md", &["*.markdown", "*.md", "*.mdown", "*.mkdn"]),
|
||||||
("matlab", &["*.m"]),
|
("matlab", &["*.m"]),
|
||||||
("mk", &["mkfile"]),
|
("mk", &["mkfile"]),
|
||||||
("ml", &["*.ml"]),
|
("ml", &["*.ml"]),
|
||||||
|
("msbuild", &["*.csproj", "*.fsproj", "*.vcxproj", "*.proj", "*.props", "*.targets"]),
|
||||||
("nim", &["*.nim"]),
|
("nim", &["*.nim"]),
|
||||||
|
("nix", &["*.nix"]),
|
||||||
("objc", &["*.h", "*.m"]),
|
("objc", &["*.h", "*.m"]),
|
||||||
("objcpp", &["*.h", "*.mm"]),
|
("objcpp", &["*.h", "*.mm"]),
|
||||||
("ocaml", &["*.ml", "*.mli", "*.mll", "*.mly"]),
|
("ocaml", &["*.ml", "*.mli", "*.mll", "*.mly"]),
|
||||||
@@ -165,6 +172,7 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
|
|||||||
("pod", &["*.pod"]),
|
("pod", &["*.pod"]),
|
||||||
("ps", &["*.cdxml", "*.ps1", "*.ps1xml", "*.psd1", "*.psm1"]),
|
("ps", &["*.cdxml", "*.ps1", "*.ps1xml", "*.psd1", "*.psm1"]),
|
||||||
("py", &["*.py"]),
|
("py", &["*.py"]),
|
||||||
|
("qmake", &["*.pro", "*.pri", "*.prf"]),
|
||||||
("readme", &["README*", "*README"]),
|
("readme", &["README*", "*README"]),
|
||||||
("r", &["*.R", "*.r", "*.Rmd", "*.Rnw"]),
|
("r", &["*.R", "*.r", "*.Rmd", "*.Rnw"]),
|
||||||
("rdoc", &["*.rdoc"]),
|
("rdoc", &["*.rdoc"]),
|
||||||
@@ -447,13 +455,18 @@ impl TypesBuilder {
|
|||||||
GlobBuilder::new(glob)
|
GlobBuilder::new(glob)
|
||||||
.literal_separator(true)
|
.literal_separator(true)
|
||||||
.build()
|
.build()
|
||||||
.map_err(|err| Error::Glob(err.to_string()))));
|
.map_err(|err| {
|
||||||
|
Error::Glob {
|
||||||
|
glob: Some(glob.to_string()),
|
||||||
|
err: err.kind().to_string(),
|
||||||
|
}
|
||||||
|
})));
|
||||||
glob_to_selection.push((isel, iglob));
|
glob_to_selection.push((isel, iglob));
|
||||||
}
|
}
|
||||||
selections.push(selection.clone().map(move |_| def));
|
selections.push(selection.clone().map(move |_| def));
|
||||||
}
|
}
|
||||||
let set = try!(build_set.build().map_err(|err| {
|
let set = try!(build_set.build().map_err(|err| {
|
||||||
Error::Glob(err.to_string())
|
Error::Glob { glob: None, err: err.to_string() }
|
||||||
}));
|
}));
|
||||||
Ok(Types {
|
Ok(Types {
|
||||||
defs: defs,
|
defs: defs,
|
||||||
|
@@ -380,16 +380,16 @@ impl DirEntryRaw {
|
|||||||
/// is: `.ignore`, `.gitignore`, `.git/info/exclude`, global gitignore and
|
/// is: `.ignore`, `.gitignore`, `.git/info/exclude`, global gitignore and
|
||||||
/// finally explicitly added ignore files. Note that precedence between
|
/// finally explicitly added ignore files. Note that precedence between
|
||||||
/// different types of ignore files is not impacted by the directory hierarchy;
|
/// different types of ignore files is not impacted by the directory hierarchy;
|
||||||
/// any `.ignore` file overrides all `.gitignore` files. Within each
|
/// any `.ignore` file overrides all `.gitignore` files. Within each precedence
|
||||||
/// precedence level, more nested ignore files have a higher precedence over
|
/// level, more nested ignore files have a higher precedence than less nested
|
||||||
/// less nested ignore files.
|
/// ignore files.
|
||||||
/// * Third, if the previous step yields an ignore match, than all matching
|
/// * 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
|
/// 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.
|
/// 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
|
/// * 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
|
/// the path. As above, if it yields an ignore match, then all matching is
|
||||||
/// and the path is skipped. If it's a whitelist match, then matching
|
/// stopped and the path is skipped. If it yields a whitelist match, then
|
||||||
/// continues.
|
/// matching continues.
|
||||||
/// * Fifth, if the path hasn't been whitelisted and it is hidden, then the
|
/// * Fifth, if the path hasn't been whitelisted and it is hidden, then the
|
||||||
/// path is skipped.
|
/// path is skipped.
|
||||||
/// * Sixth, unless the path is a directory, the size of the file is compared
|
/// * Sixth, unless the path is a directory, the size of the file is compared
|
||||||
|
@@ -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
|
class RipgrepBin < Formula
|
||||||
version '0.5.0'
|
version '0.5.2'
|
||||||
desc "Search tool like grep and The Silver Searcher."
|
desc "Search tool like grep and The Silver Searcher."
|
||||||
homepage "https://github.com/BurntSushi/ripgrep"
|
homepage "https://github.com/BurntSushi/ripgrep"
|
||||||
url "https://github.com/BurntSushi/ripgrep/releases/download/#{version}/ripgrep-#{version}-x86_64-apple-darwin.tar.gz"
|
url "https://github.com/BurntSushi/ripgrep/releases/download/#{version}/ripgrep-#{version}-x86_64-apple-darwin.tar.gz"
|
||||||
sha256 "5bfa8872c4f2a5d010ddec1c213d518056e62d4dd3b3f23a0ef099b85343dbdd"
|
sha256 "a0326a84af8517ad707d8c7cccba6e112de27822c391cc0937e4727fbb6c48f4"
|
||||||
|
|
||||||
conflicts_with "ripgrep"
|
conflicts_with "ripgrep"
|
||||||
|
|
||||||
|
15
snapcraft.yaml
Normal file
15
snapcraft.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
name: ripgrep # you probably want to 'snapcraft register <name>'
|
||||||
|
version: '0.5.1' # just for humans, typically '1.2+git' or '1.3.2'
|
||||||
|
summary: Fast file searcher # 79 char long summary
|
||||||
|
description: |
|
||||||
|
ripgrep combines the usability of The Silver Searcher with the raw speed of grep.
|
||||||
|
grade: stable # must be 'stable' to release into candidate/stable channels
|
||||||
|
confinement: classic # use 'strict' once you have the right plugs and slots
|
||||||
|
parts:
|
||||||
|
ripgrep:
|
||||||
|
plugin: rust
|
||||||
|
source: .
|
||||||
|
apps:
|
||||||
|
rg:
|
||||||
|
command: env PATH=$SNAP/bin:$PATH rg
|
||||||
|
aliases: [rg]
|
124
src/app.rs
124
src/app.rs
@@ -9,15 +9,19 @@ ripgrep's regex engine uses finite automata and guarantees linear time
|
|||||||
searching. Because of this, features like backreferences and arbitrary
|
searching. Because of this, features like backreferences and arbitrary
|
||||||
lookaround are not supported.
|
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
|
Project home page: https://github.com/BurntSushi/ripgrep
|
||||||
|
|
||||||
Use -h for short descriptions and --help for more details.";
|
Use -h for short descriptions and --help for more details.";
|
||||||
|
|
||||||
const USAGE: &'static str = "
|
const USAGE: &'static str = "
|
||||||
rg [OPTIONS] <pattern> [<path> ...]
|
rg [options] PATTERN [path ...]
|
||||||
rg [OPTIONS] [-e PATTERN | -f FILE ]... [<path> ...]
|
rg [options] [-e PATTERN ...] [-f FILE ...] [path ...]
|
||||||
rg [OPTIONS] --files [<path> ...]
|
rg [options] --files [path ...]
|
||||||
rg [OPTIONS] --type-list";
|
rg [options] --type-list";
|
||||||
|
|
||||||
const TEMPLATE: &'static str = "\
|
const TEMPLATE: &'static str = "\
|
||||||
{bin} {version}
|
{bin} {version}
|
||||||
@@ -41,21 +45,24 @@ OPTIONS:
|
|||||||
/// in a `build.rs` script to build shell completion files.
|
/// in a `build.rs` script to build shell completion files.
|
||||||
pub fn app() -> App<'static, 'static> {
|
pub fn app() -> App<'static, 'static> {
|
||||||
let arg = |name| {
|
let arg = |name| {
|
||||||
Arg::with_name(name).help(USAGES[name].short).long_help(USAGES[name].long)
|
Arg::with_name(name)
|
||||||
|
.help(USAGES[name].short)
|
||||||
|
.long_help(USAGES[name].long)
|
||||||
};
|
};
|
||||||
let flag = |name| arg(name).long(name);
|
let flag = |name| arg(name).long(name);
|
||||||
|
|
||||||
App::new("ripgrep")
|
App::new("ripgrep")
|
||||||
.author(crate_authors!())
|
.author(crate_authors!())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
|
.long_version(LONG_VERSION.as_str())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
.max_term_width(100)
|
.max_term_width(100)
|
||||||
.setting(AppSettings::UnifiedHelpMessage)
|
.setting(AppSettings::UnifiedHelpMessage)
|
||||||
.usage(USAGE)
|
.usage(USAGE)
|
||||||
.template(TEMPLATE)
|
.template(TEMPLATE)
|
||||||
.help_message("Prints help information. Use --help for more details.")
|
.help_message("Prints help information. Use --help for more details.")
|
||||||
// First, set up primary positional/flag arguments.
|
// First, set up primary positional/flag arguments.
|
||||||
.arg(arg("pattern")
|
.arg(arg("PATTERN")
|
||||||
.required_unless_one(&[
|
.required_unless_one(&[
|
||||||
"file", "files", "help-short", "help", "regexp", "type-list",
|
"file", "files", "help-short", "help", "regexp", "type-list",
|
||||||
"ripgrep-version",
|
"ripgrep-version",
|
||||||
@@ -64,13 +71,13 @@ pub fn app() -> App<'static, 'static> {
|
|||||||
.arg(flag("regexp").short("e")
|
.arg(flag("regexp").short("e")
|
||||||
.takes_value(true).multiple(true).number_of_values(1)
|
.takes_value(true).multiple(true).number_of_values(1)
|
||||||
.set(ArgSettings::AllowLeadingHyphen)
|
.set(ArgSettings::AllowLeadingHyphen)
|
||||||
.value_name("pattern"))
|
.value_name("PATTERN"))
|
||||||
.arg(flag("files")
|
.arg(flag("files")
|
||||||
// This should also conflict with `pattern`, but the first file
|
// This should also conflict with `PATTERN`, but the first file
|
||||||
// path will actually be in `pattern`.
|
// path will actually be in `PATTERN`.
|
||||||
.conflicts_with_all(&["file", "regexp", "type-list"]))
|
.conflicts_with_all(&["file", "regexp", "type-list"]))
|
||||||
.arg(flag("type-list")
|
.arg(flag("type-list")
|
||||||
.conflicts_with_all(&["file", "files", "pattern", "regexp"]))
|
.conflicts_with_all(&["file", "files", "PATTERN", "regexp"]))
|
||||||
// Second, set up common flags.
|
// Second, set up common flags.
|
||||||
.arg(flag("text").short("a"))
|
.arg(flag("text").short("a"))
|
||||||
.arg(flag("count").short("c"))
|
.arg(flag("count").short("c"))
|
||||||
@@ -78,7 +85,8 @@ pub fn app() -> App<'static, 'static> {
|
|||||||
.value_name("WHEN")
|
.value_name("WHEN")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.hide_possible_values(true)
|
.hide_possible_values(true)
|
||||||
.possible_values(&["never", "auto", "always", "ansi"]))
|
.possible_values(&["never", "auto", "always", "ansi"])
|
||||||
|
.default_value_if("vimgrep", None, "never"))
|
||||||
.arg(flag("colors").value_name("SPEC")
|
.arg(flag("colors").value_name("SPEC")
|
||||||
.takes_value(true).multiple(true).number_of_values(1))
|
.takes_value(true).multiple(true).number_of_values(1))
|
||||||
.arg(flag("encoding").short("E").value_name("ENCODING")
|
.arg(flag("encoding").short("E").value_name("ENCODING")
|
||||||
@@ -86,10 +94,15 @@ pub fn app() -> App<'static, 'static> {
|
|||||||
.arg(flag("fixed-strings").short("F"))
|
.arg(flag("fixed-strings").short("F"))
|
||||||
.arg(flag("glob").short("g")
|
.arg(flag("glob").short("g")
|
||||||
.takes_value(true).multiple(true).number_of_values(1)
|
.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"))
|
.value_name("GLOB"))
|
||||||
.arg(flag("ignore-case").short("i"))
|
.arg(flag("ignore-case").short("i"))
|
||||||
.arg(flag("line-number").short("n"))
|
.arg(flag("line-number").short("n"))
|
||||||
.arg(flag("no-line-number").short("N"))
|
.arg(flag("no-line-number").short("N").overrides_with("line-number"))
|
||||||
.arg(flag("quiet").short("q"))
|
.arg(flag("quiet").short("q"))
|
||||||
.arg(flag("type").short("t")
|
.arg(flag("type").short("t")
|
||||||
.takes_value(true).multiple(true).number_of_values(1)
|
.takes_value(true).multiple(true).number_of_values(1)
|
||||||
@@ -100,7 +113,8 @@ pub fn app() -> App<'static, 'static> {
|
|||||||
.arg(flag("unrestricted").short("u")
|
.arg(flag("unrestricted").short("u")
|
||||||
.multiple(true))
|
.multiple(true))
|
||||||
.arg(flag("invert-match").short("v"))
|
.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.
|
// Third, set up less common flags.
|
||||||
.arg(flag("after-context").short("A")
|
.arg(flag("after-context").short("A")
|
||||||
.value_name("NUM").takes_value(true)
|
.value_name("NUM").takes_value(true)
|
||||||
@@ -114,19 +128,23 @@ pub fn app() -> App<'static, 'static> {
|
|||||||
.arg(flag("column"))
|
.arg(flag("column"))
|
||||||
.arg(flag("context-separator")
|
.arg(flag("context-separator")
|
||||||
.value_name("SEPARATOR").takes_value(true))
|
.value_name("SEPARATOR").takes_value(true))
|
||||||
|
.arg(flag("dfa-size-limit")
|
||||||
|
.value_name("NUM+SUFFIX?").takes_value(true))
|
||||||
.arg(flag("debug"))
|
.arg(flag("debug"))
|
||||||
.arg(flag("file").short("f")
|
.arg(flag("file").short("f")
|
||||||
.value_name("FILE").takes_value(true)
|
.value_name("FILE").takes_value(true)
|
||||||
|
.set(ArgSettings::AllowLeadingHyphen)
|
||||||
.multiple(true).number_of_values(1))
|
.multiple(true).number_of_values(1))
|
||||||
.arg(flag("files-with-matches").short("l"))
|
.arg(flag("files-with-matches").short("l"))
|
||||||
.arg(flag("files-without-match"))
|
.arg(flag("files-without-match"))
|
||||||
.arg(flag("with-filename").short("H"))
|
.arg(flag("with-filename").short("H"))
|
||||||
.arg(flag("no-filename"))
|
.arg(flag("no-filename").overrides_with("with-filename"))
|
||||||
.arg(flag("heading").overrides_with("no-heading"))
|
.arg(flag("heading"))
|
||||||
.arg(flag("no-heading").overrides_with("heading"))
|
.arg(flag("no-heading").overrides_with("heading"))
|
||||||
.arg(flag("hidden"))
|
.arg(flag("hidden"))
|
||||||
.arg(flag("ignore-file")
|
.arg(flag("ignore-file")
|
||||||
.value_name("FILE").takes_value(true)
|
.value_name("FILE").takes_value(true)
|
||||||
|
.set(ArgSettings::AllowLeadingHyphen)
|
||||||
.multiple(true).number_of_values(1))
|
.multiple(true).number_of_values(1))
|
||||||
.arg(flag("follow").short("L"))
|
.arg(flag("follow").short("L"))
|
||||||
.arg(flag("max-count")
|
.arg(flag("max-count")
|
||||||
@@ -147,14 +165,18 @@ pub fn app() -> App<'static, 'static> {
|
|||||||
.arg(flag("only-matching").short("o").conflicts_with("replace"))
|
.arg(flag("only-matching").short("o").conflicts_with("replace"))
|
||||||
.arg(flag("path-separator").value_name("SEPARATOR").takes_value(true))
|
.arg(flag("path-separator").value_name("SEPARATOR").takes_value(true))
|
||||||
.arg(flag("pretty").short("p"))
|
.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"))
|
.arg(flag("case-sensitive").short("s"))
|
||||||
.arg(flag("smart-case").short("S"))
|
.arg(flag("smart-case").short("S"))
|
||||||
.arg(flag("sort-files"))
|
.arg(flag("sort-files"))
|
||||||
.arg(flag("threads")
|
.arg(flag("threads")
|
||||||
.short("j").value_name("ARG").takes_value(true)
|
.short("j").value_name("ARG").takes_value(true)
|
||||||
.validator(validate_number))
|
.validator(validate_number))
|
||||||
.arg(flag("vimgrep"))
|
.arg(flag("vimgrep").overrides_with("count"))
|
||||||
.arg(flag("max-columns").short("M")
|
.arg(flag("max-columns").short("M")
|
||||||
.value_name("NUM").takes_value(true)
|
.value_name("NUM").takes_value(true)
|
||||||
.validator(validate_number))
|
.validator(validate_number))
|
||||||
@@ -184,6 +206,24 @@ macro_rules! doc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
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> = {
|
static ref USAGES: HashMap<&'static str, Usage> = {
|
||||||
let mut h = HashMap::new();
|
let mut h = HashMap::new();
|
||||||
doc!(h, "help-short",
|
doc!(h, "help-short",
|
||||||
@@ -195,14 +235,15 @@ lazy_static! {
|
|||||||
doc!(h, "ripgrep-version",
|
doc!(h, "ripgrep-version",
|
||||||
"Prints version information.");
|
"Prints version information.");
|
||||||
|
|
||||||
doc!(h, "pattern",
|
doc!(h, "PATTERN",
|
||||||
"A regular expression used for searching.",
|
"A regular expression used for searching.",
|
||||||
"A regular expression used for searching. Multiple patterns \
|
"A regular expression used for searching. To match a pattern \
|
||||||
may be given. To match a pattern beginning with a -, use [-].");
|
beginning with a dash, use the -e/--regexp option.");
|
||||||
doc!(h, "regexp",
|
doc!(h, "regexp",
|
||||||
"A regular expression used for searching.",
|
"Use pattern to search.",
|
||||||
"A regular expression used for searching. Multiple patterns \
|
"Use pattern to search. This option can be provided multiple \
|
||||||
may be given. To match a pattern beginning with a -, use [-].");
|
times, where all patterns given are searched. This is also \
|
||||||
|
useful when searching for patterns that start with a dash.");
|
||||||
doc!(h, "path",
|
doc!(h, "path",
|
||||||
"A file or directory to search.",
|
"A file or directory to search.",
|
||||||
"A file or directory to search. Directories are searched \
|
"A file or directory to search. Directories are searched \
|
||||||
@@ -222,11 +263,11 @@ lazy_static! {
|
|||||||
"Only show count of matches for each file.");
|
"Only show count of matches for each file.");
|
||||||
doc!(h, "color",
|
doc!(h, "color",
|
||||||
"When to use color. [default: auto]",
|
"When to use color. [default: auto]",
|
||||||
"When to use color in the output. The possible values are \
|
"When to use color in the output. The possible values are never, \
|
||||||
never, auto, always or ansi. The default is auto. When always \
|
auto, always or ansi. The default is auto. When always is used, \
|
||||||
is used, coloring is attempted based on your environment. When \
|
coloring is attempted based on your environment. When ansi is \
|
||||||
ansi used, coloring is forcefully done using ANSI escape color \
|
used, coloring is forcefully done using ANSI escape color \
|
||||||
codes.");
|
codes.");
|
||||||
doc!(h, "colors",
|
doc!(h, "colors",
|
||||||
"Configure color settings and styles.",
|
"Configure color settings and styles.",
|
||||||
"This flag specifies color settings for use in the output. \
|
"This flag specifies color settings for use in the output. \
|
||||||
@@ -262,6 +303,13 @@ lazy_static! {
|
|||||||
ignore logic. Multiple glob flags may be used. Globbing \
|
ignore logic. Multiple glob flags may be used. Globbing \
|
||||||
rules match .gitignore globs. Precede a glob with a ! \
|
rules match .gitignore globs. Precede a glob with a ! \
|
||||||
to exclude it.");
|
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",
|
doc!(h, "ignore-case",
|
||||||
"Case insensitive search.",
|
"Case insensitive search.",
|
||||||
"Case insensitive search. This is overridden by \
|
"Case insensitive search. This is overridden by \
|
||||||
@@ -305,6 +353,10 @@ lazy_static! {
|
|||||||
"Only show matches surrounded by word boundaries. This is \
|
"Only show matches surrounded by word boundaries. This is \
|
||||||
equivalent to putting \\b before and after all of the search \
|
equivalent to putting \\b before and after all of the search \
|
||||||
patterns.");
|
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",
|
doc!(h, "after-context",
|
||||||
"Show NUM lines after each match.");
|
"Show NUM lines after each match.");
|
||||||
@@ -326,6 +378,13 @@ lazy_static! {
|
|||||||
doc!(h, "debug",
|
doc!(h, "debug",
|
||||||
"Show debug messages.",
|
"Show debug messages.",
|
||||||
"Show debug messages. Please use this when filing a bug report.");
|
"Show debug messages. Please use this when filing a bug report.");
|
||||||
|
doc!(h, "dfa-size-limit",
|
||||||
|
"The upper size limit of the generated dfa.",
|
||||||
|
"The upper size limit of the generated dfa. The default limit is \
|
||||||
|
10M. This should only be changed on very large regex inputs \
|
||||||
|
where the (slower) fallback regex engine may otherwise be used. \
|
||||||
|
\n\nThe argument accepts the same size suffixes as allowed in \
|
||||||
|
the 'max-filesize' argument.");
|
||||||
doc!(h, "file",
|
doc!(h, "file",
|
||||||
"Search for patterns from the given file.",
|
"Search for patterns from the given file.",
|
||||||
"Search for patterns from the given file, with one pattern per \
|
"Search for patterns from the given file, with one pattern per \
|
||||||
@@ -434,7 +493,7 @@ lazy_static! {
|
|||||||
default when the environment demands it (e.g., cygwin). A path \
|
default when the environment demands it (e.g., cygwin). A path \
|
||||||
separator is limited to a single byte.");
|
separator is limited to a single byte.");
|
||||||
doc!(h, "pretty",
|
doc!(h, "pretty",
|
||||||
"Alias for --color always --heading -n.");
|
"Alias for --color always --heading --line-number.");
|
||||||
doc!(h, "replace",
|
doc!(h, "replace",
|
||||||
"Replace matches with string given.",
|
"Replace matches with string given.",
|
||||||
"Replace every match with the string given when printing \
|
"Replace every match with the string given when printing \
|
||||||
@@ -444,6 +503,11 @@ lazy_static! {
|
|||||||
Note that the replacement by default replaces each match, and \
|
Note that the replacement by default replaces each match, and \
|
||||||
NOT the entire line. To replace the entire line, you should \
|
NOT the entire line. To replace the entire line, you should \
|
||||||
match the entire line.");
|
match the entire line.");
|
||||||
|
doc!(h, "regex-size-limit",
|
||||||
|
"The upper size limit of the compiled regex.",
|
||||||
|
"The upper size limit of the compiled regex. The default limit \
|
||||||
|
is 10M. \n\nThe argument accepts the same size suffixes as \
|
||||||
|
allowed in the 'max-filesize' argument.");
|
||||||
doc!(h, "case-sensitive",
|
doc!(h, "case-sensitive",
|
||||||
"Search case sensitively.",
|
"Search case sensitively.",
|
||||||
"Search case sensitively. This overrides -i/--ignore-case and \
|
"Search case sensitively. This overrides -i/--ignore-case and \
|
||||||
|
168
src/args.rs
168
src/args.rs
@@ -35,7 +35,6 @@ pub struct Args {
|
|||||||
paths: Vec<PathBuf>,
|
paths: Vec<PathBuf>,
|
||||||
after_context: usize,
|
after_context: usize,
|
||||||
before_context: usize,
|
before_context: usize,
|
||||||
color: bool,
|
|
||||||
color_choice: termcolor::ColorChoice,
|
color_choice: termcolor::ColorChoice,
|
||||||
colors: ColorSpecs,
|
colors: ColorSpecs,
|
||||||
column: bool,
|
column: bool,
|
||||||
@@ -317,7 +316,6 @@ impl<'a> ArgMatches<'a> {
|
|||||||
paths: paths,
|
paths: paths,
|
||||||
after_context: after_context,
|
after_context: after_context,
|
||||||
before_context: before_context,
|
before_context: before_context,
|
||||||
color: self.color(),
|
|
||||||
color_choice: self.color_choice(),
|
color_choice: self.color_choice(),
|
||||||
colors: try!(self.color_specs()),
|
colors: try!(self.color_specs()),
|
||||||
column: self.column(),
|
column: self.column(),
|
||||||
@@ -377,7 +375,7 @@ impl<'a> ArgMatches<'a> {
|
|||||||
if self.is_present("file")
|
if self.is_present("file")
|
||||||
|| self.is_present("files")
|
|| self.is_present("files")
|
||||||
|| self.is_present("regexp") {
|
|| self.is_present("regexp") {
|
||||||
if let Some(path) = self.value_of_os("pattern") {
|
if let Some(path) = self.value_of_os("PATTERN") {
|
||||||
paths.insert(0, Path::new(path).to_path_buf());
|
paths.insert(0, Path::new(path).to_path_buf());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -429,7 +427,8 @@ impl<'a> ArgMatches<'a> {
|
|||||||
///
|
///
|
||||||
/// Note that if -F/--fixed-strings is set, then all patterns will be
|
/// Note that if -F/--fixed-strings is set, then all patterns will be
|
||||||
/// escaped. Similarly, if -w/--word-regexp is set, then all patterns
|
/// 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.
|
/// If any pattern is invalid UTF-8, then an error is returned.
|
||||||
fn patterns(&self) -> Result<Vec<String>> {
|
fn patterns(&self) -> Result<Vec<String>> {
|
||||||
@@ -440,7 +439,7 @@ impl<'a> ArgMatches<'a> {
|
|||||||
match self.values_of_os("regexp") {
|
match self.values_of_os("regexp") {
|
||||||
None => {
|
None => {
|
||||||
if self.values_of_os("file").is_none() {
|
if self.values_of_os("file").is_none() {
|
||||||
if let Some(os_pat) = self.value_of_os("pattern") {
|
if let Some(os_pat) = self.value_of_os("PATTERN") {
|
||||||
pats.push(try!(self.os_str_pattern(os_pat)));
|
pats.push(try!(self.os_str_pattern(os_pat)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -472,7 +471,7 @@ impl<'a> ArgMatches<'a> {
|
|||||||
Ok(pats)
|
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.
|
/// boundaries or escapes if applicable.
|
||||||
///
|
///
|
||||||
/// If the pattern is not valid UTF-8, then an error is returned.
|
/// If the pattern is not valid UTF-8, then an error is returned.
|
||||||
@@ -481,10 +480,12 @@ impl<'a> ArgMatches<'a> {
|
|||||||
Ok(self.str_pattern(s))
|
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.
|
/// boundaries or escapes if applicable.
|
||||||
fn str_pattern(&self, pat: &str) -> String {
|
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() {
|
if s.is_empty() {
|
||||||
self.empty_pattern()
|
self.empty_pattern()
|
||||||
} else {
|
} else {
|
||||||
@@ -507,7 +508,17 @@ impl<'a> ArgMatches<'a> {
|
|||||||
/// flag is set. Otherwise, the pattern is returned unchanged.
|
/// flag is set. Otherwise, the pattern is returned unchanged.
|
||||||
fn word_pattern(&self, pat: String) -> String {
|
fn word_pattern(&self, pat: String) -> String {
|
||||||
if self.is_present("word-regexp") {
|
if self.is_present("word-regexp") {
|
||||||
format!(r"\b{}\b", pat)
|
format!(r"\b(?:{})\b", pat)
|
||||||
|
} else {
|
||||||
|
pat
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 {
|
} else {
|
||||||
pat
|
pat
|
||||||
}
|
}
|
||||||
@@ -532,6 +543,7 @@ impl<'a> ArgMatches<'a> {
|
|||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
self.is_present("with-filename")
|
self.is_present("with-filename")
|
||||||
|
|| self.is_present("vimgrep")
|
||||||
|| paths.len() > 1
|
|| paths.len() > 1
|
||||||
|| paths.get(0).map_or(false, |p| p.is_dir())
|
|| paths.get(0).map_or(false, |p| p.is_dir())
|
||||||
}
|
}
|
||||||
@@ -590,9 +602,9 @@ impl<'a> ArgMatches<'a> {
|
|||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
let only_stdin = paths == &[Path::new("-")];
|
let only_stdin = paths == &[Path::new("-")];
|
||||||
self.is_present("line-number")
|
(atty::is(atty::Stream::Stdout) && !only_stdin)
|
||||||
|
|| self.is_present("line-number")
|
||||||
|| self.is_present("column")
|
|| self.is_present("column")
|
||||||
|| (atty::is(atty::Stream::Stdout) && !only_stdin)
|
|
||||||
|| self.is_present("pretty")
|
|| self.is_present("pretty")
|
||||||
|| self.is_present("vimgrep")
|
|| self.is_present("vimgrep")
|
||||||
}
|
}
|
||||||
@@ -606,11 +618,11 @@ impl<'a> ArgMatches<'a> {
|
|||||||
/// Returns true if and only if matches should be grouped with file name
|
/// Returns true if and only if matches should be grouped with file name
|
||||||
/// headings.
|
/// headings.
|
||||||
fn heading(&self) -> bool {
|
fn heading(&self) -> bool {
|
||||||
if self.is_present("no-heading") {
|
if self.is_present("no-heading") || self.is_present("vimgrep") {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
self.is_present("heading")
|
atty::is(atty::Stream::Stdout)
|
||||||
|| atty::is(atty::Stream::Stdout)
|
|| self.is_present("heading")
|
||||||
|| self.is_present("pretty")
|
|| self.is_present("pretty")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -664,23 +676,6 @@ impl<'a> ArgMatches<'a> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if and only if ripgrep should color its output.
|
|
||||||
fn color(&self) -> bool {
|
|
||||||
let preference = match self.0.value_of_lossy("color") {
|
|
||||||
None => "auto".to_string(),
|
|
||||||
Some(v) => v.into_owned(),
|
|
||||||
};
|
|
||||||
if preference == "always" {
|
|
||||||
true
|
|
||||||
} else if self.is_present("vimgrep") {
|
|
||||||
false
|
|
||||||
} else if preference == "auto" {
|
|
||||||
atty::is(atty::Stream::Stdout) || self.is_present("pretty")
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the user's color choice based on command line parameters and
|
/// Returns the user's color choice based on command line parameters and
|
||||||
/// environment.
|
/// environment.
|
||||||
fn color_choice(&self) -> termcolor::ColorChoice {
|
fn color_choice(&self) -> termcolor::ColorChoice {
|
||||||
@@ -692,8 +687,6 @@ impl<'a> ArgMatches<'a> {
|
|||||||
termcolor::ColorChoice::Always
|
termcolor::ColorChoice::Always
|
||||||
} else if preference == "ansi" {
|
} else if preference == "ansi" {
|
||||||
termcolor::ColorChoice::AlwaysAnsi
|
termcolor::ColorChoice::AlwaysAnsi
|
||||||
} else if self.is_present("vimgrep") {
|
|
||||||
termcolor::ColorChoice::Never
|
|
||||||
} else if preference == "auto" {
|
} else if preference == "auto" {
|
||||||
if atty::is(atty::Stream::Stdout) || self.is_present("pretty") {
|
if atty::is(atty::Stream::Stdout) || self.is_present("pretty") {
|
||||||
termcolor::ColorChoice::Auto
|
termcolor::ColorChoice::Auto
|
||||||
@@ -712,7 +705,10 @@ impl<'a> ArgMatches<'a> {
|
|||||||
fn color_specs(&self) -> Result<ColorSpecs> {
|
fn color_specs(&self) -> Result<ColorSpecs> {
|
||||||
// Start with a default set of color specs.
|
// Start with a default set of color specs.
|
||||||
let mut specs = vec![
|
let mut specs = vec![
|
||||||
|
#[cfg(unix)]
|
||||||
"path:fg:magenta".parse().unwrap(),
|
"path:fg:magenta".parse().unwrap(),
|
||||||
|
#[cfg(windows)]
|
||||||
|
"path:fg:cyan".parse().unwrap(),
|
||||||
"line:fg:green".parse().unwrap(),
|
"line:fg:green".parse().unwrap(),
|
||||||
"match:fg:red".parse().unwrap(),
|
"match:fg:red".parse().unwrap(),
|
||||||
"match:style:bold".parse().unwrap(),
|
"match:style:bold".parse().unwrap(),
|
||||||
@@ -737,7 +733,7 @@ impl<'a> ArgMatches<'a> {
|
|||||||
if label == "auto" {
|
if label == "auto" {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
match Encoding::for_label(label.as_bytes()) {
|
match Encoding::for_label_no_replacement(label.as_bytes()) {
|
||||||
Some(enc) => Ok(Some(enc)),
|
Some(enc) => Ok(Some(enc)),
|
||||||
None => Err(From::from(
|
None => Err(From::from(
|
||||||
format!("unsupported encoding: {}", label))),
|
format!("unsupported encoding: {}", label))),
|
||||||
@@ -771,12 +767,18 @@ impl<'a> ArgMatches<'a> {
|
|||||||
let casei =
|
let casei =
|
||||||
self.is_present("ignore-case")
|
self.is_present("ignore-case")
|
||||||
&& !self.is_present("case-sensitive");
|
&& !self.is_present("case-sensitive");
|
||||||
GrepBuilder::new(&try!(self.pattern()))
|
let mut gb = GrepBuilder::new(&try!(self.pattern()))
|
||||||
.case_smart(smart)
|
.case_smart(smart)
|
||||||
.case_insensitive(casei)
|
.case_insensitive(casei)
|
||||||
.line_terminator(b'\n')
|
.line_terminator(b'\n');
|
||||||
.build()
|
|
||||||
.map_err(From::from)
|
if let Some(limit) = try!(self.dfa_size_limit()) {
|
||||||
|
gb = gb.dfa_size_limit(limit);
|
||||||
|
}
|
||||||
|
if let Some(limit) = try!(self.regex_size_limit()) {
|
||||||
|
gb = gb.size_limit(limit);
|
||||||
|
}
|
||||||
|
gb.build().map_err(From::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds the set of glob overrides from the command line flags.
|
/// Builds the set of glob overrides from the command line flags.
|
||||||
@@ -785,6 +787,14 @@ impl<'a> ArgMatches<'a> {
|
|||||||
for glob in self.values_of_lossy_vec("glob") {
|
for glob in self.values_of_lossy_vec("glob") {
|
||||||
try!(ovr.add(&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)
|
ovr.build().map_err(From::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -807,31 +817,64 @@ impl<'a> ArgMatches<'a> {
|
|||||||
btypes.build().map_err(From::from)
|
btypes.build().map_err(From::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses the max-filesize argument option into a byte count.
|
/// Parses an argument of the form `[0-9]+(KMG)?`.
|
||||||
fn max_filesize(&self) -> Result<Option<u64>> {
|
///
|
||||||
use regex::Regex;
|
/// This always returns the result as a type `u64`. This must be converted
|
||||||
|
/// to the appropriate type by the caller.
|
||||||
let max_filesize = match self.value_of_lossy("max-filesize") {
|
fn parse_human_readable_size_arg(
|
||||||
|
&self,
|
||||||
|
arg_name: &str,
|
||||||
|
) -> Result<Option<u64>> {
|
||||||
|
let arg_value = match self.value_of_lossy(arg_name) {
|
||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
None => return Ok(None)
|
None => return Ok(None)
|
||||||
};
|
};
|
||||||
|
let re = regex::Regex::new("^([0-9]+)([KMG])?$").unwrap();
|
||||||
|
let caps = try!(
|
||||||
|
re.captures(&arg_value).ok_or_else(|| {
|
||||||
|
format!("invalid format for {}", arg_name)
|
||||||
|
}));
|
||||||
|
|
||||||
let re = Regex::new("^([0-9]+)([KMG])?$").unwrap();
|
let value = try!(caps[1].parse::<u64>());
|
||||||
let caps = try!(re.captures(&max_filesize)
|
|
||||||
.ok_or("invalid format for max-filesize argument"));
|
|
||||||
|
|
||||||
let value = try!(caps[1].parse::<u64>().map_err(|err|err.to_string()));
|
|
||||||
let suffix = caps.get(2).map(|x| x.as_str());
|
let suffix = caps.get(2).map(|x| x.as_str());
|
||||||
|
|
||||||
|
let v_10 = value.checked_mul(1024);
|
||||||
|
let v_20 = v_10.and_then(|x| x.checked_mul(1024));
|
||||||
|
let v_30 = v_20.and_then(|x| x.checked_mul(1024));
|
||||||
|
|
||||||
|
let try_suffix = |x: Option<u64>| {
|
||||||
|
if x.is_some() {
|
||||||
|
Ok(x)
|
||||||
|
} else {
|
||||||
|
Err(From::from(format!("number too large for {}", arg_name)))
|
||||||
|
}
|
||||||
|
};
|
||||||
match suffix {
|
match suffix {
|
||||||
None => Ok(Some(value)),
|
None => Ok(Some(value)),
|
||||||
Some("K") => Ok(Some(value * 1024)),
|
Some("K") => try_suffix(v_10),
|
||||||
Some("M") => Ok(Some(value * 1024 * 1024)),
|
Some("M") => try_suffix(v_20),
|
||||||
Some("G") => Ok(Some(value * 1024 * 1024 * 1024)),
|
Some("G") => try_suffix(v_30),
|
||||||
_ => Err(From::from("invalid suffix for max-filesize argument"))
|
_ => Err(From::from(format!("invalid suffix for {}", arg_name)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse the dfa-size-limit argument option into a byte count.
|
||||||
|
fn dfa_size_limit(&self) -> Result<Option<usize>> {
|
||||||
|
let r = try!(self.parse_human_readable_size_arg("dfa-size-limit"));
|
||||||
|
human_readable_to_usize("dfa-size-limit", r)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse the regex-size-limit argument option into a byte count.
|
||||||
|
fn regex_size_limit(&self) -> Result<Option<usize>> {
|
||||||
|
let r = try!(self.parse_human_readable_size_arg("regex-size-limit"));
|
||||||
|
human_readable_to_usize("regex-size-limit", r)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses the max-filesize argument option into a byte count.
|
||||||
|
fn max_filesize(&self) -> Result<Option<u64>> {
|
||||||
|
self.parse_human_readable_size_arg("max-filesize")
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if ignore files should be ignored.
|
/// Returns true if ignore files should be ignored.
|
||||||
fn no_ignore(&self) -> bool {
|
fn no_ignore(&self) -> bool {
|
||||||
self.is_present("no-ignore")
|
self.is_present("no-ignore")
|
||||||
@@ -926,6 +969,27 @@ impl QuietMatched {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert the result of a `parse_human_readable_size_arg` call into
|
||||||
|
/// a `usize`, failing if the type does not fit.
|
||||||
|
fn human_readable_to_usize(
|
||||||
|
arg_name: &str,
|
||||||
|
value: Option<u64>,
|
||||||
|
) -> Result<Option<usize>> {
|
||||||
|
use std::usize;
|
||||||
|
|
||||||
|
match value {
|
||||||
|
None => Ok(None),
|
||||||
|
Some(v) => {
|
||||||
|
if v <= usize::MAX as u64 {
|
||||||
|
Ok(Some(v as usize))
|
||||||
|
} else {
|
||||||
|
let msg = format!("number too large for {}", arg_name);
|
||||||
|
Err(From::from(msg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if and only if stdin is deemed searchable.
|
/// Returns true if and only if stdin is deemed searchable.
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn stdin_is_readable() -> bool {
|
fn stdin_is_readable() -> bool {
|
||||||
|
@@ -8,7 +8,6 @@ extern crate grep;
|
|||||||
extern crate ignore;
|
extern crate ignore;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
extern crate libc;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
extern crate memchr;
|
extern crate memchr;
|
||||||
@@ -192,7 +191,9 @@ fn run_files_parallel(args: Arc<Args>) -> Result<u64> {
|
|||||||
let mut printer = print_args.printer(stdout.lock());
|
let mut printer = print_args.printer(stdout.lock());
|
||||||
let mut file_count = 0;
|
let mut file_count = 0;
|
||||||
for dent in rx.iter() {
|
for dent in rx.iter() {
|
||||||
printer.path(dent.path());
|
if !print_args.quiet() {
|
||||||
|
printer.path(dent.path());
|
||||||
|
}
|
||||||
file_count += 1;
|
file_count += 1;
|
||||||
}
|
}
|
||||||
file_count
|
file_count
|
||||||
@@ -227,7 +228,9 @@ fn run_files_one_thread(args: Arc<Args>) -> Result<u64> {
|
|||||||
None => continue,
|
None => continue,
|
||||||
Some(dent) => dent,
|
Some(dent) => dent,
|
||||||
};
|
};
|
||||||
printer.path(dent.path());
|
if !args.quiet() {
|
||||||
|
printer.path(dent.path());
|
||||||
|
}
|
||||||
file_count += 1;
|
file_count += 1;
|
||||||
}
|
}
|
||||||
Ok(file_count)
|
Ok(file_count)
|
||||||
|
@@ -3,7 +3,7 @@ use std::fmt;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use regex::bytes::{Regex, Replacer, Captures};
|
use regex::bytes::{Captures, Regex, Replacer};
|
||||||
use termcolor::{Color, ColorSpec, ParseColorError, WriteColor};
|
use termcolor::{Color, ColorSpec, ParseColorError, WriteColor};
|
||||||
|
|
||||||
use pathutil::strip_prefix;
|
use pathutil::strip_prefix;
|
||||||
@@ -242,25 +242,17 @@ impl<W: WriteColor> Printer<W> {
|
|||||||
line_number: Option<u64>,
|
line_number: Option<u64>,
|
||||||
) {
|
) {
|
||||||
if !self.line_per_match && !self.only_matching {
|
if !self.line_per_match && !self.only_matching {
|
||||||
let column =
|
let mat = re
|
||||||
if self.column {
|
.find(&buf[start..end])
|
||||||
Some(re.find(&buf[start..end])
|
.map(|m| (m.start(), m.end()))
|
||||||
.map(|m| m.start()).unwrap_or(0) as u64)
|
.unwrap_or((0, 0));
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
return self.write_match(
|
return self.write_match(
|
||||||
re, path, buf, start, end, line_number, column);
|
re, path, buf, start, end, line_number, mat.0, mat.1);
|
||||||
}
|
}
|
||||||
for m in re.find_iter(&buf[start..end]) {
|
for m in re.find_iter(&buf[start..end]) {
|
||||||
let column =
|
|
||||||
if self.column {
|
|
||||||
Some(m.start() as u64)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
self.write_match(
|
self.write_match(
|
||||||
re, path.as_ref(), buf, start, end, line_number, column);
|
re, path.as_ref(), buf, start, end,
|
||||||
|
line_number, m.start(), m.end());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,7 +264,8 @@ impl<W: WriteColor> Printer<W> {
|
|||||||
start: usize,
|
start: usize,
|
||||||
end: usize,
|
end: usize,
|
||||||
line_number: Option<u64>,
|
line_number: Option<u64>,
|
||||||
column: Option<u64>,
|
match_start: usize,
|
||||||
|
match_end: usize,
|
||||||
) {
|
) {
|
||||||
if self.heading && self.with_filename && !self.has_printed {
|
if self.heading && self.with_filename && !self.has_printed {
|
||||||
self.write_file_sep();
|
self.write_file_sep();
|
||||||
@@ -285,8 +278,8 @@ impl<W: WriteColor> Printer<W> {
|
|||||||
if let Some(line_number) = line_number {
|
if let Some(line_number) = line_number {
|
||||||
self.line_number(line_number, b':');
|
self.line_number(line_number, b':');
|
||||||
}
|
}
|
||||||
if let Some(c) = column {
|
if self.column {
|
||||||
self.column_number(c + 1, b':');
|
self.column_number(match_start as u64 + 1, b':');
|
||||||
}
|
}
|
||||||
if self.replace.is_some() {
|
if self.replace.is_some() {
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
@@ -307,18 +300,21 @@ impl<W: WriteColor> Printer<W> {
|
|||||||
self.write_eol();
|
self.write_eol();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let line_buf = if self.only_matching {
|
if self.only_matching {
|
||||||
let m = re.find(&buf[start..end]).unwrap();
|
let buf = &buf[start + match_start..start + match_end];
|
||||||
&buf[start + m.start()..start + m.end()]
|
self.write_matched_line(re, buf, true);
|
||||||
} else {
|
} else {
|
||||||
&buf[start..end]
|
self.write_matched_line(re, &buf[start..end], false);
|
||||||
};
|
}
|
||||||
self.write_matched_line(re, line_buf);
|
|
||||||
// write_matched_line guarantees to write a newline.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_matched_line(&mut self, re: &Regex, buf: &[u8]) {
|
fn write_matched_line(
|
||||||
|
&mut self,
|
||||||
|
re: &Regex,
|
||||||
|
buf: &[u8],
|
||||||
|
only_match: bool,
|
||||||
|
) {
|
||||||
if self.max_columns.map_or(false, |m| buf.len() > m) {
|
if self.max_columns.map_or(false, |m| buf.len() > m) {
|
||||||
let count = re.find_iter(buf).count();
|
let count = re.find_iter(buf).count();
|
||||||
let msg = format!("[Omitted long line with {} matches]", count);
|
let msg = format!("[Omitted long line with {} matches]", count);
|
||||||
@@ -328,6 +324,8 @@ impl<W: WriteColor> Printer<W> {
|
|||||||
}
|
}
|
||||||
if !self.wtr.supports_color() || self.colors.matched().is_none() {
|
if !self.wtr.supports_color() || self.colors.matched().is_none() {
|
||||||
self.write(buf);
|
self.write(buf);
|
||||||
|
} else if only_match {
|
||||||
|
self.write_colored(buf, |colors| colors.matched());
|
||||||
} else {
|
} else {
|
||||||
let mut last_written = 0;
|
let mut last_written = 0;
|
||||||
for m in re.find_iter(buf) {
|
for m in re.find_iter(buf) {
|
||||||
@@ -578,7 +576,7 @@ pub struct ColorSpecs {
|
|||||||
/// Valid colors are `black`, `blue`, `green`, `red`, `cyan`, `magenta`,
|
/// Valid colors are `black`, `blue`, `green`, `red`, `cyan`, `magenta`,
|
||||||
/// `yellow`, `white`.
|
/// `yellow`, `white`.
|
||||||
///
|
///
|
||||||
/// Valid style instructions are `nobold` and `bold`.
|
/// Valid style instructions are `nobold`, `bold`, `intense`, `nointense`.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct Spec {
|
pub struct Spec {
|
||||||
ty: OutType,
|
ty: OutType,
|
||||||
|
223
tests/tests.rs
223
tests/tests.rs
@@ -209,6 +209,16 @@ For the Doctor Watsons of this world, as opposed to the Sherlock
|
|||||||
assert_eq!(lines, expected);
|
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| {
|
sherlock!(literal, "()", "file", |wd: WorkDir, mut cmd: Command| {
|
||||||
wd.create("file", "blib\n()\nblab\n");
|
wd.create("file", "blib\n()\nblab\n");
|
||||||
cmd.arg("-F");
|
cmd.arg("-F");
|
||||||
@@ -336,6 +346,21 @@ sherlock!(glob_negate, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
|
|||||||
assert_eq!(lines, "file.py:Sherlock\n");
|
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| {
|
sherlock!(count, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
|
||||||
cmd.arg("--count");
|
cmd.arg("--count");
|
||||||
let lines: String = wd.stdout(&mut cmd);
|
let lines: String = wd.stdout(&mut cmd);
|
||||||
@@ -455,7 +480,6 @@ sherlock!(max_filesize_parse_no_suffix, "Sherlock", ".",
|
|||||||
let expected = "\
|
let expected = "\
|
||||||
foo
|
foo
|
||||||
";
|
";
|
||||||
|
|
||||||
assert_eq!(lines, expected);
|
assert_eq!(lines, expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -470,7 +494,6 @@ sherlock!(max_filesize_parse_k_suffix, "Sherlock", ".",
|
|||||||
let expected = "\
|
let expected = "\
|
||||||
foo
|
foo
|
||||||
";
|
";
|
||||||
|
|
||||||
assert_eq!(lines, expected);
|
assert_eq!(lines, expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -485,10 +508,19 @@ sherlock!(max_filesize_parse_m_suffix, "Sherlock", ".",
|
|||||||
let expected = "\
|
let expected = "\
|
||||||
foo
|
foo
|
||||||
";
|
";
|
||||||
|
|
||||||
assert_eq!(lines, expected);
|
assert_eq!(lines, expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
sherlock!(max_filesize_suffix_overflow, "Sherlock", ".",
|
||||||
|
|wd: WorkDir, mut cmd: Command| {
|
||||||
|
wd.remove("sherlock");
|
||||||
|
wd.create_size("foo", 1000000);
|
||||||
|
|
||||||
|
// 2^35 * 2^30 would otherwise overflow
|
||||||
|
cmd.arg("--max-filesize").arg("34359738368G").arg("--files");
|
||||||
|
wd.assert_err(&mut cmd);
|
||||||
|
});
|
||||||
|
|
||||||
sherlock!(ignore_hidden, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
|
sherlock!(ignore_hidden, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
|
||||||
wd.remove("sherlock");
|
wd.remove("sherlock");
|
||||||
wd.create(".sherlock", hay::SHERLOCK);
|
wd.create(".sherlock", hay::SHERLOCK);
|
||||||
@@ -1058,21 +1090,25 @@ clean!(regression_405, "test", ".", |wd: WorkDir, mut cmd: Command| {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// See: https://github.com/BurntSushi/ripgrep/issues/428
|
// 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");
|
wd.create("sherlock", "foo\nbar");
|
||||||
cmd.arg("-A1").arg("-H").arg("--no-heading").arg("-N")
|
cmd.arg("-A1").arg("-H").arg("--no-heading").arg("-N")
|
||||||
.arg("--colors=match:none").arg("--color=always");
|
.arg("--colors=match:none").arg("--color=always");
|
||||||
|
|
||||||
let lines: String = wd.stdout(&mut cmd);
|
let lines: String = wd.stdout(&mut cmd);
|
||||||
let expected = format!("\
|
let expected = format!(
|
||||||
{colored_path}:foo
|
"{colored_path}:foo\n{colored_path}-bar\n",
|
||||||
{colored_path}-bar
|
colored_path=format!(
|
||||||
", colored_path=format!("\x1b\x5b\x6d\x1b\x5b\x33\x35\x6d{path}\x1b\x5b\x6d", path=path("sherlock")));
|
"\x1b\x5b\x6d\x1b\x5b\x33\x35\x6d{path}\x1b\x5b\x6d",
|
||||||
|
path=path("sherlock")));
|
||||||
assert_eq!(lines, expected);
|
assert_eq!(lines, expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
// See: https://github.com/BurntSushi/ripgrep/issues/428
|
// See: https://github.com/BurntSushi/ripgrep/issues/428
|
||||||
clean!(regression_428_unrecognized_style, "Sherlok", ".", |wd: WorkDir, mut cmd: Command| {
|
clean!(regression_428_unrecognized_style, "Sherlok", ".",
|
||||||
|
|wd: WorkDir, mut cmd: Command| {
|
||||||
cmd.arg("--colors=match:style:");
|
cmd.arg("--colors=match:style:");
|
||||||
wd.assert_err(&mut cmd);
|
wd.assert_err(&mut cmd);
|
||||||
|
|
||||||
@@ -1084,6 +1120,15 @@ Unrecognized style attribute ''. Choose from: nobold, bold, nointense, intense.
|
|||||||
assert_eq!(err, expected);
|
assert_eq!(err, expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// See: https://github.com/BurntSushi/ripgrep/issues/493
|
||||||
|
clean!(regression_493, " 're ", "input.txt", |wd: WorkDir, mut cmd: Command| {
|
||||||
|
wd.create("input.txt", "peshwaship 're seminomata");
|
||||||
|
cmd.arg("-o").arg("-w");
|
||||||
|
|
||||||
|
let lines: String = wd.stdout(&mut cmd);
|
||||||
|
assert_eq!(lines, " 're \n");
|
||||||
|
});
|
||||||
|
|
||||||
// See: https://github.com/BurntSushi/ripgrep/issues/1
|
// See: https://github.com/BurntSushi/ripgrep/issues/1
|
||||||
clean!(feature_1_sjis, "Шерлок Холмс", ".", |wd: WorkDir, mut cmd: Command| {
|
clean!(feature_1_sjis, "Шерлок Холмс", ".", |wd: WorkDir, mut cmd: Command| {
|
||||||
let sherlock =
|
let sherlock =
|
||||||
@@ -1130,6 +1175,21 @@ clean!(feature_1_eucjp, "Шерлок Холмс", ".",
|
|||||||
assert_eq!(lines, "foo:Шерлок Холмс\n");
|
assert_eq!(lines, "foo:Шерлок Холмс\n");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// See: https://github.com/BurntSushi/ripgrep/issues/1
|
||||||
|
sherlock!(feature_1_unknown_encoding, "Sherlock", ".",
|
||||||
|
|wd: WorkDir, mut cmd: Command| {
|
||||||
|
cmd.arg("-Efoobar");
|
||||||
|
wd.assert_non_empty_stderr(&mut cmd);
|
||||||
|
});
|
||||||
|
|
||||||
|
// See: https://github.com/BurntSushi/ripgrep/issues/1
|
||||||
|
// Specific: https://github.com/BurntSushi/ripgrep/pull/398/files#r111109265
|
||||||
|
sherlock!(feature_1_replacement_encoding, "Sherlock", ".",
|
||||||
|
|wd: WorkDir, mut cmd: Command| {
|
||||||
|
cmd.arg("-Ecsiso2022kr");
|
||||||
|
wd.assert_non_empty_stderr(&mut cmd);
|
||||||
|
});
|
||||||
|
|
||||||
// See: https://github.com/BurntSushi/ripgrep/issues/7
|
// See: https://github.com/BurntSushi/ripgrep/issues/7
|
||||||
sherlock!(feature_7, "-fpat", "sherlock", |wd: WorkDir, mut cmd: Command| {
|
sherlock!(feature_7, "-fpat", "sherlock", |wd: WorkDir, mut cmd: Command| {
|
||||||
wd.create("pat", "Sherlock\nHolmes");
|
wd.create("pat", "Sherlock\nHolmes");
|
||||||
@@ -1443,6 +1503,37 @@ clean!(feature_275_pathsep, "test", ".", |wd: WorkDir, mut cmd: Command| {
|
|||||||
assert_eq!(lines, "fooZbar:test\n");
|
assert_eq!(lines, "fooZbar:test\n");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// See: https://github.com/BurntSushi/ripgrep/issues/362
|
||||||
|
sherlock!(feature_362_dfa_size_limit, r"For\s",
|
||||||
|
|wd: WorkDir, mut cmd: Command| {
|
||||||
|
// This should fall back to the nfa engine but should still produce the
|
||||||
|
// expected result.
|
||||||
|
cmd.arg("--dfa-size-limit").arg("10");
|
||||||
|
let lines: String = wd.stdout(&mut cmd);
|
||||||
|
let expected = "\
|
||||||
|
For the Doctor Watsons of this world, as opposed to the Sherlock
|
||||||
|
";
|
||||||
|
assert_eq!(lines, expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
sherlock!(feature_362_exceeds_regex_size_limit, r"[0-9]\w+",
|
||||||
|
|wd: WorkDir, mut cmd: Command| {
|
||||||
|
cmd.arg("--regex-size-limit").arg("10K");
|
||||||
|
wd.assert_err(&mut cmd);
|
||||||
|
});
|
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "32")]
|
||||||
|
sherlock!(feature_362_u64_to_narrow_usize_suffix_overflow, "Sherlock", ".",
|
||||||
|
|wd: WorkDir, mut cmd: Command| {
|
||||||
|
wd.remove("sherlock");
|
||||||
|
wd.create_size("foo", 1000000);
|
||||||
|
|
||||||
|
// 2^35 * 2^20 is ok for u64, but not for usize
|
||||||
|
cmd.arg("--dfa-size-limit").arg("34359738368M").arg("--files");
|
||||||
|
wd.assert_err(&mut cmd);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// See: https://github.com/BurntSushi/ripgrep/issues/419
|
// See: https://github.com/BurntSushi/ripgrep/issues/419
|
||||||
sherlock!(feature_419_zero_as_shortcut_for_null, "Sherlock", ".",
|
sherlock!(feature_419_zero_as_shortcut_for_null, "Sherlock", ".",
|
||||||
|wd: WorkDir, mut cmd: Command| {
|
|wd: WorkDir, mut cmd: Command| {
|
||||||
@@ -1554,6 +1645,120 @@ fn regression_391() {
|
|||||||
assert_eq!(lines, "bar.py\n");
|
assert_eq!(lines, "bar.py\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See: https://github.com/BurntSushi/ripgrep/issues/451
|
||||||
|
#[test]
|
||||||
|
fn regression_451_only_matching_as_in_issue() {
|
||||||
|
let wd = WorkDir::new("regression_451_only_matching");
|
||||||
|
let path = "digits.txt";
|
||||||
|
wd.create(path, "1 2 3\n");
|
||||||
|
|
||||||
|
let mut cmd = wd.command();
|
||||||
|
cmd.arg("[0-9]+").arg(path).arg("--only-matching");
|
||||||
|
let lines: String = wd.stdout(&mut cmd);
|
||||||
|
|
||||||
|
let expected = "\
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
";
|
||||||
|
|
||||||
|
assert_eq!(lines, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
// See: https://github.com/BurntSushi/ripgrep/issues/451
|
||||||
|
#[test]
|
||||||
|
fn regression_451_only_matching() {
|
||||||
|
let wd = WorkDir::new("regression_451_only_matching");
|
||||||
|
let path = "digits.txt";
|
||||||
|
wd.create(path, "1 2 3\n123\n");
|
||||||
|
|
||||||
|
let mut cmd = wd.command();
|
||||||
|
cmd.arg("[0-9]").arg(path)
|
||||||
|
.arg("--only-matching")
|
||||||
|
.arg("--column");
|
||||||
|
let lines: String = wd.stdout(&mut cmd);
|
||||||
|
|
||||||
|
let expected = "\
|
||||||
|
1:1:1
|
||||||
|
1:3:2
|
||||||
|
1:5:3
|
||||||
|
2:1:1
|
||||||
|
2:2:2
|
||||||
|
2:3:3
|
||||||
|
";
|
||||||
|
|
||||||
|
assert_eq!(lines, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
// See: https://github.com/BurntSushi/ripgrep/issues/483
|
||||||
|
#[test]
|
||||||
|
fn regression_483_matching_no_stdout() {
|
||||||
|
let wd = WorkDir::new("regression_483_matching_no_stdout");
|
||||||
|
wd.create("file.py", "");
|
||||||
|
|
||||||
|
let mut cmd = wd.command();
|
||||||
|
cmd.arg("--quiet")
|
||||||
|
.arg("--files")
|
||||||
|
.arg("--glob").arg("*.py");
|
||||||
|
|
||||||
|
let lines: String = wd.stdout(&mut cmd);
|
||||||
|
assert!(lines.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
// See: https://github.com/BurntSushi/ripgrep/issues/483
|
||||||
|
#[test]
|
||||||
|
fn regression_483_non_matching_exit_code() {
|
||||||
|
let wd = WorkDir::new("regression_483_non_matching_exit_code");
|
||||||
|
wd.create("file.rs", "");
|
||||||
|
|
||||||
|
let mut cmd = wd.command();
|
||||||
|
cmd.arg("--quiet")
|
||||||
|
.arg("--files")
|
||||||
|
.arg("--glob").arg("*.py");
|
||||||
|
|
||||||
|
wd.assert_err(&mut cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// See: https://github.com/BurntSushi/ripgrep/issues/506
|
||||||
|
#[test]
|
||||||
|
fn regression_506_word_boundaries_not_parenthesized() {
|
||||||
|
let wd = WorkDir::new("regression_506_word_boundaries_not_parenthesized");
|
||||||
|
let path = "wb.txt";
|
||||||
|
wd.create(path, "min minimum amin\n\
|
||||||
|
max maximum amax");
|
||||||
|
|
||||||
|
let mut cmd = wd.command();
|
||||||
|
cmd.arg("-w").arg("min|max").arg(path).arg("--only-matching");
|
||||||
|
let lines: String = wd.stdout(&mut cmd);
|
||||||
|
|
||||||
|
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]
|
#[test]
|
||||||
fn type_list() {
|
fn type_list() {
|
||||||
let wd = WorkDir::new("type_list");
|
let wd = WorkDir::new("type_list");
|
||||||
|
@@ -256,6 +256,23 @@ impl WorkDir {
|
|||||||
String::from_utf8_lossy(&o.stderr));
|
String::from_utf8_lossy(&o.stderr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Runs the given command and asserts that something was printed to
|
||||||
|
/// stderr.
|
||||||
|
pub fn assert_non_empty_stderr(&self, cmd: &mut process::Command) {
|
||||||
|
let o = cmd.output().unwrap();
|
||||||
|
if o.status.success() || o.stderr.is_empty() {
|
||||||
|
panic!("\n\n===== {:?} =====\n\
|
||||||
|
command succeeded but expected failure!\
|
||||||
|
\n\ncwd: {}\
|
||||||
|
\n\nstatus: {}\
|
||||||
|
\n\nstdout: {}\n\nstderr: {}\
|
||||||
|
\n\n=====\n",
|
||||||
|
cmd, self.dir.display(), o.status,
|
||||||
|
String::from_utf8_lossy(&o.stdout),
|
||||||
|
String::from_utf8_lossy(&o.stderr));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nice_err<P: AsRef<Path>, T, E: error::Error>(
|
fn nice_err<P: AsRef<Path>, T, E: error::Error>(
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wincolor"
|
name = "wincolor"
|
||||||
version = "0.1.3" #:version
|
version = "0.1.4" #:version
|
||||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||||
description = """
|
description = """
|
||||||
A simple Windows specific API for controlling text color in a Windows console.
|
A simple Windows specific API for controlling text color in a Windows console.
|
||||||
|
@@ -2,7 +2,7 @@ use std::io;
|
|||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use kernel32;
|
use kernel32;
|
||||||
use winapi::{DWORD, HANDLE, WORD};
|
use winapi::{DWORD, WORD};
|
||||||
use winapi::winbase::{STD_ERROR_HANDLE, STD_OUTPUT_HANDLE};
|
use winapi::winbase::{STD_ERROR_HANDLE, STD_OUTPUT_HANDLE};
|
||||||
use winapi::wincon::{
|
use winapi::wincon::{
|
||||||
FOREGROUND_BLUE as FG_BLUE,
|
FOREGROUND_BLUE as FG_BLUE,
|
||||||
@@ -30,33 +30,25 @@ const FG_WHITE: DWORD = FG_BLUE | FG_GREEN | FG_RED;
|
|||||||
/// stdout before setting new text attributes.
|
/// stdout before setting new text attributes.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Console {
|
pub struct Console {
|
||||||
handle: HANDLE,
|
handle_id: DWORD,
|
||||||
start_attr: TextAttributes,
|
start_attr: TextAttributes,
|
||||||
cur_attr: TextAttributes,
|
cur_attr: TextAttributes,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for Console {}
|
|
||||||
|
|
||||||
impl Drop for Console {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe { kernel32::CloseHandle(self.handle); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Console {
|
impl Console {
|
||||||
/// Get a console for a standard I/O stream.
|
/// Get a console for a standard I/O stream.
|
||||||
fn create_for_stream(handle_id: DWORD) -> io::Result<Console> {
|
fn create_for_stream(handle_id: DWORD) -> io::Result<Console> {
|
||||||
let mut info = unsafe { mem::zeroed() };
|
let mut info = unsafe { mem::zeroed() };
|
||||||
let (handle, res) = unsafe {
|
let res = unsafe {
|
||||||
let handle = kernel32::GetStdHandle(handle_id);
|
let handle = kernel32::GetStdHandle(handle_id);
|
||||||
(handle, kernel32::GetConsoleScreenBufferInfo(handle, &mut info))
|
kernel32::GetConsoleScreenBufferInfo(handle, &mut info)
|
||||||
};
|
};
|
||||||
if res == 0 {
|
if res == 0 {
|
||||||
return Err(io::Error::last_os_error());
|
return Err(io::Error::last_os_error());
|
||||||
}
|
}
|
||||||
let attr = TextAttributes::from_word(info.wAttributes);
|
let attr = TextAttributes::from_word(info.wAttributes);
|
||||||
Ok(Console {
|
Ok(Console {
|
||||||
handle: handle,
|
handle_id: handle_id,
|
||||||
start_attr: attr,
|
start_attr: attr,
|
||||||
cur_attr: attr,
|
cur_attr: attr,
|
||||||
})
|
})
|
||||||
@@ -80,7 +72,8 @@ impl Console {
|
|||||||
fn set(&mut self) -> io::Result<()> {
|
fn set(&mut self) -> io::Result<()> {
|
||||||
let attr = self.cur_attr.to_word();
|
let attr = self.cur_attr.to_word();
|
||||||
let res = unsafe {
|
let res = unsafe {
|
||||||
kernel32::SetConsoleTextAttribute(self.handle, attr)
|
let handle = kernel32::GetStdHandle(self.handle_id);
|
||||||
|
kernel32::SetConsoleTextAttribute(handle, attr)
|
||||||
};
|
};
|
||||||
if res == 0 {
|
if res == 0 {
|
||||||
return Err(io::Error::last_os_error());
|
return Err(io::Error::last_os_error());
|
||||||
|
Reference in New Issue
Block a user