mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2025-08-03 05:32:04 -07:00
Compare commits
43 Commits
grep-0.1.6
...
0.5.2
Author | SHA1 | Date | |
---|---|---|---|
|
5a666b042d | ||
|
16109166fe | ||
|
0b685c8429 | ||
|
d2c7a76a3c | ||
|
20f7d9b3a2 | ||
|
362abed44a | ||
|
c50b8b4125 | ||
|
7ad23e5565 | ||
|
66efbad871 | ||
|
1f2a9b0306 | ||
|
a45fe94240 | ||
|
ac1c95a6d9 | ||
|
685b431d80 | ||
|
487713aa34 | ||
|
e300541701 | ||
|
e9df420d2f | ||
|
201b4fc757 | ||
|
90a11dec5e | ||
|
9456d95e8f | ||
|
0c298f60a6 | ||
|
79271fcb33 | ||
|
fc975af8e9 | ||
|
1425d6735e | ||
|
aed3ccb9c7 | ||
|
33c95d2919 | ||
|
01deac9427 | ||
|
b4bc3b6349 | ||
|
685cc6c562 | ||
|
08c017330f | ||
|
2f3a8c7f69 | ||
|
3ac1b68e54 | ||
|
0ebd5465b7 | ||
|
5cb4bb9ea0 | ||
|
c8a179b4da | ||
|
46f94826fd | ||
|
75f1855a91 | ||
|
fd9870d668 | ||
|
a3a2708067 | ||
|
78847b65c8 | ||
|
e962eea1cc | ||
|
95bc678403 | ||
|
68af3bbdc4 | ||
|
70b6bdb104 |
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
|
103
CHANGELOG.md
103
CHANGELOG.md
@@ -1,3 +1,106 @@
|
|||||||
|
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)
|
||||||
|
==================
|
||||||
|
Feature enhancements:
|
||||||
|
|
||||||
|
* Added or improved file type filtering for vim.
|
||||||
|
* [FEATURE #34](https://github.com/BurntSushi/ripgrep/issues/34):
|
||||||
|
Add a `-o/--only-matching` flag.
|
||||||
|
* [FEATURE #377](https://github.com/BurntSushi/ripgrep/issues/377):
|
||||||
|
Column numbers can now be customized with a color. (The default is
|
||||||
|
no color.)
|
||||||
|
* [FEATURE #419](https://github.com/BurntSushi/ripgrep/issues/419):
|
||||||
|
Added `-0` short flag option for `--null`.
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* [BUG #381](https://github.com/BurntSushi/ripgrep/issues/381):
|
||||||
|
Include license text in all subcrates.
|
||||||
|
* [BUG #418](https://github.com/BurntSushi/ripgrep/issues/418),
|
||||||
|
[BUG #426](https://github.com/BurntSushi/ripgrep/issues/426),
|
||||||
|
[BUG #439](https://github.com/BurntSushi/ripgrep/issues/439):
|
||||||
|
Fix a few bugs with `-h/--help` output.
|
||||||
|
|
||||||
|
|
||||||
|
0.5.0 (2017-03-12)
|
||||||
|
==================
|
||||||
|
This is a new minor version release of ripgrep that includes one minor breaking
|
||||||
|
change, bug fixes and several new features including support for text encodings
|
||||||
|
other than UTF-8.
|
||||||
|
|
||||||
|
A notable accomplishment with respect to Rust is that ripgrep proper now only
|
||||||
|
contains a single `unsafe` use (for accessing the contents of a memory map).
|
||||||
|
|
||||||
|
The **breaking change** is:
|
||||||
|
|
||||||
|
* [FEATURE #380](https://github.com/BurntSushi/ripgrep/issues/380):
|
||||||
|
Line numbers are now hidden by default when ripgrep is printing to a tty
|
||||||
|
**and** the only thing searched is stdin.
|
||||||
|
|
||||||
|
Feature enhancements:
|
||||||
|
|
||||||
|
* Added or improved file type filtering for Ceylon, CSS, Elixir, HTML, log,
|
||||||
|
SASS, SVG, Twig
|
||||||
|
* [FEATURE #1](https://github.com/BurntSushi/ripgrep/issues/1):
|
||||||
|
Add support for additional text encodings, including automatic detection for
|
||||||
|
UTF-16 via BOM sniffing. Explicit text encoding support with the
|
||||||
|
`-E/--encoding` flag was also added for latin-1, GBK, EUC-JP
|
||||||
|
and Shift_JIS, among others. The full list can be found here:
|
||||||
|
https://encoding.spec.whatwg.org/#concept-encoding-get
|
||||||
|
* [FEATURE #129](https://github.com/BurntSushi/ripgrep/issues/129):
|
||||||
|
Add a new `-M/--max-columns` flag that omits lines longer than the given
|
||||||
|
number of bytes. (Disabled by default!)
|
||||||
|
* [FEATURE #369](https://github.com/BurntSushi/ripgrep/issues/369):
|
||||||
|
A new flag, `--max-filesize`, was added for limiting searches to files with
|
||||||
|
a maximum file size.
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* [BUG #52](https://github.com/BurntSushi/ripgrep/issues/52),
|
||||||
|
[BUG #311](https://github.com/BurntSushi/ripgrep/issues/311):
|
||||||
|
Tweak how binary files are detected and handled. (We are slightly less
|
||||||
|
conservative and will no longer use memory without bound.)
|
||||||
|
* [BUG #326](https://github.com/BurntSushi/ripgrep/issues/326):
|
||||||
|
When --files flag is given, we should never attempt to parse positional
|
||||||
|
arguments as regexes.
|
||||||
|
* [BUG #327](https://github.com/BurntSushi/ripgrep/issues/327):
|
||||||
|
Permit the --heading flag to override the --no-heading flag.
|
||||||
|
* [BUG #340](https://github.com/BurntSushi/ripgrep/pull/340):
|
||||||
|
Clarify that the `-u/--unrestricted` flags are aliases.
|
||||||
|
* [BUG #343](https://github.com/BurntSushi/ripgrep/pull/343):
|
||||||
|
Global git ignore config should use `$HOME/.config/git/ignore` and not
|
||||||
|
`$HOME/git/ignore`.
|
||||||
|
* [BUG #345](https://github.com/BurntSushi/ripgrep/pull/345):
|
||||||
|
Clarify docs for `-g/--glob` flag.
|
||||||
|
* [BUG #381](https://github.com/BurntSushi/ripgrep/issues/381):
|
||||||
|
Add license files to each sub-crate.
|
||||||
|
* [BUG #383](https://github.com/BurntSushi/ripgrep/issues/383):
|
||||||
|
Use latest version of clap (for argv parsing).
|
||||||
|
* [BUG #392](https://github.com/BurntSushi/ripgrep/issues/391):
|
||||||
|
Fix translation of set globs (e.g., `{foo,bar,quux}`) to regexes.
|
||||||
|
* [BUG #401](https://github.com/BurntSushi/ripgrep/pull/401):
|
||||||
|
Add PowerShell completion file to Windows release.
|
||||||
|
* [BUG #405](https://github.com/BurntSushi/ripgrep/issues/405):
|
||||||
|
Fix bug when excluding absolute paths with the `-g/--glob` flag.
|
||||||
|
|
||||||
|
|
||||||
0.4.0
|
0.4.0
|
||||||
=====
|
=====
|
||||||
This is a new minor version release of ripgrep that includes a couple very
|
This is a new minor version release of ripgrep that includes a couple very
|
||||||
|
80
Cargo.lock
generated
80
Cargo.lock
generated
@@ -1,28 +1,28 @@
|
|||||||
[root]
|
[root]
|
||||||
name = "ripgrep"
|
name = "ripgrep"
|
||||||
version = "0.4.0"
|
version = "0.5.2"
|
||||||
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.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.24.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"encoding_rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"encoding_rs 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"grep 0.1.6",
|
"grep 0.1.6",
|
||||||
"ignore 0.1.8",
|
"ignore 0.2.0",
|
||||||
"lazy_static 0.2.4 (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)",
|
"libc 0.2.22 (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.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.4.0 (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.1 (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.1",
|
"termcolor 0.3.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "0.6.2"
|
version = "0.6.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"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)",
|
||||||
@@ -39,13 +39,13 @@ 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.22 (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.0"
|
version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -63,14 +63,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "2.21.1"
|
version = "2.24.1"
|
||||||
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.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 0.8.2 (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)",
|
"unicode-segmentation 1.1.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.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -83,7 +83,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encoding_rs"
|
name = "encoding_rs"
|
||||||
version = "0.5.0"
|
version = "0.5.1"
|
||||||
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.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -108,15 +108,15 @@ version = "0.4.1"
|
|||||||
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.22 (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.2 (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.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)",
|
||||||
@@ -135,11 +135,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ignore"
|
name = "ignore"
|
||||||
version = "0.1.8"
|
version = "0.2.0"
|
||||||
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.4 (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.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)",
|
||||||
"regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -158,12 +158,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "0.2.4"
|
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.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -176,7 +176,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.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -186,16 +186,16 @@ 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.1 (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.22 (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.4.0"
|
||||||
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.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -203,7 +203,7 @@ name = "regex"
|
|||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
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.2 (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.0 (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)",
|
||||||
@@ -237,17 +237,17 @@ 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.22 (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 = "termcolor"
|
name = "termcolor"
|
||||||
version = "0.3.1"
|
version = "0.3.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wincolor 0.1.3",
|
"wincolor 0.1.3",
|
||||||
]
|
]
|
||||||
@@ -258,7 +258,7 @@ version = "3.0.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.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -332,31 +332,31 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
"checksum aho-corasick 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0638fd549427caa90c499814196d1b9e3725eb4d15d7339d6de073a680ed0ca2"
|
"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.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e1ab483fc81a8143faa7203c4a3c02888ebd1a782e37e41fa34753ba9a162"
|
"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4"
|
||||||
"checksum bytecount 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1e8f09fbc8c6726a4b616dcfbd4f54491068d6bb1b93ac03c78ac18ff9a5924a"
|
"checksum bytecount 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1e8f09fbc8c6726a4b616dcfbd4f54491068d6bb1b93ac03c78ac18ff9a5924a"
|
||||||
"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
|
"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
|
||||||
"checksum clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "74a80f603221c9cd9aa27a28f52af452850051598537bb6b359c38a7d61e5cda"
|
"checksum clap 2.24.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7541069be0b8aec41030802abe8b5cdef0490070afaa55418adea93b1e431e0"
|
||||||
"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.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e4bc519d572af08cf72c4d61e0de9b05e9fa66d1fdb5e739fb5c405860b42d43"
|
||||||
"checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83"
|
"checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83"
|
||||||
"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.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34edaee07555859dc13ca387e6ae05686bb4d0364c95d649b6dab959511f4baf"
|
||||||
"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.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7291b1dd97d331f752620b02dfdbc231df7fc01bf282a00769e1cdb963c460dc"
|
"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.22 (registry+https://github.com/rust-lang/crates.io-index)" = "babb8281da88cba992fa1f4ddec7d63ed96280a1a53ec9b919fd37b53d71e502"
|
||||||
"checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad"
|
"checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad"
|
||||||
"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.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca313f1862c7ec3e0dfe8ace9fa91b1d9cb5c84ace3d00f5ec4216238e93c167"
|
||||||
"checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01"
|
"checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01"
|
||||||
"checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457"
|
"checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457"
|
||||||
"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 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 thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a"
|
||||||
"checksum thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c85048c6260d17cf486ceae3282d9fb6b90be220bf5b28c400f5485ffc29f0c7"
|
"checksum thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c85048c6260d17cf486ceae3282d9fb6b90be220bf5b28c400f5485ffc29f0c7"
|
||||||
"checksum unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18127285758f0e2c6cf325bb3f3d138a12fee27de4f23e146cd6a179f26c2cf3"
|
"checksum unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18127285758f0e2c6cf325bb3f3d138a12fee27de4f23e146cd6a179f26c2cf3"
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ripgrep"
|
name = "ripgrep"
|
||||||
version = "0.4.0" #:version
|
version = "0.5.2" #: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
|
||||||
@@ -28,11 +28,11 @@ path = "tests/tests.rs"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
atty = "0.2.2"
|
atty = "0.2.2"
|
||||||
bytecount = "0.1.4"
|
bytecount = "0.1.4"
|
||||||
clap = "2.20.5"
|
clap = "2.24.1"
|
||||||
encoding_rs = "0.5.0"
|
encoding_rs = "0.5.0"
|
||||||
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.7", path = "ignore" }
|
ignore = { version = "0.2.0", path = "ignore" }
|
||||||
lazy_static = "0.2"
|
lazy_static = "0.2"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
@@ -44,7 +44,7 @@ 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.18"
|
clap = "2.24.1"
|
||||||
lazy_static = "0.2"
|
lazy_static = "0.2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
103
README.md
103
README.md
@@ -13,6 +13,10 @@ downloads available for
|
|||||||
|
|
||||||
Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org).
|
Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org).
|
||||||
|
|
||||||
|
### CHANGELOG
|
||||||
|
|
||||||
|
Please see the [CHANGELOG](CHANGELOG.md) for a release history.
|
||||||
|
|
||||||
### Screenshot of search results
|
### Screenshot of search results
|
||||||
|
|
||||||
[](http://burntsushi.net/stuff/ripgrep1.png)
|
[](http://burntsushi.net/stuff/ripgrep1.png)
|
||||||
@@ -226,11 +230,10 @@ colorize your output and show line numbers, just like The Silver Searcher.
|
|||||||
Coloring works on Windows too! Colors can be controlled more granularly with
|
Coloring works on Windows too! Colors can be controlled more granularly with
|
||||||
the `--color` flag.
|
the `--color` flag.
|
||||||
|
|
||||||
One last thing before we get started: `ripgrep` assumes UTF-8 *everywhere*. It
|
One last thing before we get started: generally speaking, `ripgrep` assumes the
|
||||||
can still search files that are invalid UTF-8 (like, say, latin-1), but it will
|
input is reading is UTF-8. However, if ripgrep notices a file is encoded as
|
||||||
simply not work on UTF-16 encoded files or other more exotic encodings.
|
UTF-16, then it will know how to search it. For other encodings, you'll need to
|
||||||
[Support for other encodings may
|
explicitly specify them with the `-E/--encoding` flag.
|
||||||
happen.](https://github.com/BurntSushi/ripgrep/issues/1)
|
|
||||||
|
|
||||||
To recursively search the current directory, while respecting all `.gitignore`
|
To recursively search the current directory, while respecting all `.gitignore`
|
||||||
files, ignore hidden files and directories and skip binary files:
|
files, ignore hidden files and directories and skip binary files:
|
||||||
@@ -340,6 +343,11 @@ or `/etc/bash_completion.d/`.
|
|||||||
|
|
||||||
For **fish**, move `rg.fish` to `$HOME/.config/fish/completions`.
|
For **fish**, move `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.
|
||||||
|
|
||||||
### Building
|
### Building
|
||||||
|
|
||||||
`ripgrep` is written in Rust, so you'll need to grab a
|
`ripgrep` is written in Rust, so you'll need to grab a
|
||||||
@@ -375,12 +383,93 @@ $ cargo test
|
|||||||
|
|
||||||
from the repository root.
|
from the repository root.
|
||||||
|
|
||||||
|
### Tips
|
||||||
|
|
||||||
|
#### Windows Powershell
|
||||||
|
|
||||||
|
##### Powershell Profile
|
||||||
|
|
||||||
|
To customize powershell on start-up there is a special powershell script that has to be created.
|
||||||
|
In order to find its location run command `Get-Command $profile | Select-Object -ExpandProperty Definition`
|
||||||
|
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.
|
||||||
|
This way you can have own aliases to be created at start.
|
||||||
|
|
||||||
|
##### Setup function alias
|
||||||
|
|
||||||
|
Often you can find a need to make alias for the favourite utility.
|
||||||
|
|
||||||
|
But powershell function aliases do not behave like your typical linux shell alias.
|
||||||
|
|
||||||
|
You always need to propagate arguments and **Stdin** input.
|
||||||
|
But it cannot be done simply as `function grep() { $input | rg.exe --hidden $args }`
|
||||||
|
|
||||||
|
Use below example as reference to how setup alias in powershell.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
function grep {
|
||||||
|
$count = @($input).Count
|
||||||
|
$input.Reset()
|
||||||
|
|
||||||
|
if ($count) {
|
||||||
|
$input | rg.exe --hidden $args
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rg.exe --hidden $args
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Powershell special variables:
|
||||||
|
* input - is powershell **Stdin** object that allows you to access its content.
|
||||||
|
* args - is array of arguments passed to this function.
|
||||||
|
|
||||||
|
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**
|
||||||
|
|
||||||
|
##### 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
|
||||||
|
@@ -40,7 +40,7 @@ before_deploy:
|
|||||||
- cargo build --release
|
- cargo build --release
|
||||||
- mkdir staging
|
- mkdir staging
|
||||||
- copy target\release\rg.exe staging
|
- copy target\release\rg.exe staging
|
||||||
- copy target\release\build\ripgrep-*\out\_rg.ps1 staging
|
- ps: copy target\release\build\ripgrep-*\out\_rg.ps1 staging
|
||||||
- cd staging
|
- cd staging
|
||||||
# release zipfile will look like 'rust-everywhere-v1.2.3-x86_64-pc-windows-msvc'
|
# release zipfile will look like 'rust-everywhere-v1.2.3-x86_64-pc-windows-msvc'
|
||||||
- 7z a ../%PROJECT_NAME%-%APPVEYOR_REPO_TAG_NAME%-%TARGET%.zip *
|
- 7z a ../%PROJECT_NAME%-%APPVEYOR_REPO_TAG_NAME%-%TARGET%.zip *
|
||||||
|
2
build.rs
2
build.rs
@@ -19,7 +19,7 @@ fn main() {
|
|||||||
};
|
};
|
||||||
fs::create_dir_all(&outdir).unwrap();
|
fs::create_dir_all(&outdir).unwrap();
|
||||||
|
|
||||||
let mut app = app::app_short();
|
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::Zsh, &outdir);
|
||||||
|
@@ -17,9 +17,6 @@ install_c_toolchain() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
install_rustup() {
|
install_rustup() {
|
||||||
# uninstall the rust toolchain installed by travis, we are going to use rustup
|
|
||||||
sh ~/rust/lib/rustlib/uninstall.sh
|
|
||||||
|
|
||||||
curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=$TRAVIS_RUST_VERSION
|
curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=$TRAVIS_RUST_VERSION
|
||||||
|
|
||||||
rustc -V
|
rustc -V
|
||||||
|
17
doc/rg.1
17
doc/rg.1
@@ -181,7 +181,7 @@ Styles are limited to nobold, bold, nointense or intense.
|
|||||||
.RS
|
.RS
|
||||||
.PP
|
.PP
|
||||||
The format of the flag is {type}:{attribute}:{value}.
|
The format of the flag is {type}:{attribute}:{value}.
|
||||||
{type} should be one of path, line or match.
|
{type} should be one of path, line, column or match.
|
||||||
{attribute} can be fg, bg or style.
|
{attribute} can be fg, bg or style.
|
||||||
Value is either a color (for fg and bg) or a text style.
|
Value is either a color (for fg and bg) or a text style.
|
||||||
A special format, {type}:none, will clear all color settings for {type}.
|
A special format, {type}:none, will clear all color settings for {type}.
|
||||||
@@ -299,6 +299,13 @@ Follow symlinks.
|
|||||||
.RS
|
.RS
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
|
.B \-M, \-\-max\-columns \f[I]NUM\f[]
|
||||||
|
Don\[aq]t print lines longer than this limit in bytes.
|
||||||
|
Longer lines are omitted, and only the number of matches in that line is
|
||||||
|
printed.
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
.B \-m, \-\-max\-count \f[I]NUM\f[]
|
.B \-m, \-\-max\-count \f[I]NUM\f[]
|
||||||
Limit the number of matching lines per file searched to NUM.
|
Limit the number of matching lines per file searched to NUM.
|
||||||
.RS
|
.RS
|
||||||
@@ -355,7 +362,7 @@ Note that .ignore files will continue to be respected.
|
|||||||
.RS
|
.RS
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
.B \-\-null
|
.B \-0, \-\-null
|
||||||
Whenever a file name is printed, follow it with a NUL byte.
|
Whenever a file name is printed, follow it with a NUL byte.
|
||||||
This includes printing filenames before matches, and when printing a
|
This includes printing filenames before matches, and when printing a
|
||||||
list of matching files such as with \-\-count, \-\-files\-with\-matches
|
list of matching files such as with \-\-count, \-\-files\-with\-matches
|
||||||
@@ -363,6 +370,12 @@ and \-\-files.
|
|||||||
.RS
|
.RS
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
|
.B \-o, \-\-only\-matching
|
||||||
|
Print only the matched (non\-empty) parts of a matching line, with each
|
||||||
|
such part on a separate output line.
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
.B \-\-path\-separator \f[I]SEPARATOR\f[]
|
.B \-\-path\-separator \f[I]SEPARATOR\f[]
|
||||||
The path separator to use when printing file paths.
|
The path separator to use when printing file paths.
|
||||||
This defaults to your platform\[aq]s path separator, which is / on Unix
|
This defaults to your platform\[aq]s path separator, which is / on Unix
|
||||||
|
12
doc/rg.1.md
12
doc/rg.1.md
@@ -123,9 +123,9 @@ Project home page: https://github.com/BurntSushi/ripgrep
|
|||||||
black. Styles are limited to nobold, bold, nointense or intense.
|
black. Styles are limited to nobold, bold, nointense or intense.
|
||||||
|
|
||||||
The format of the flag is {type}:{attribute}:{value}. {type} should be one
|
The format of the flag is {type}:{attribute}:{value}. {type} should be one
|
||||||
of path, line or match. {attribute} can be fg, bg or style. Value is either
|
of path, line, column or match. {attribute} can be fg, bg or style. Value
|
||||||
a color (for fg and bg) or a text style. A special format, {type}:none,
|
is either a color (for fg and bg) or a text style. A special format,
|
||||||
will clear all color settings for {type}.
|
{type}:none, will clear all color settings for {type}.
|
||||||
|
|
||||||
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:
|
||||||
@@ -243,12 +243,16 @@ Project home page: https://github.com/BurntSushi/ripgrep
|
|||||||
: Don't respect version control ignore files (e.g., .gitignore).
|
: Don't respect version control ignore files (e.g., .gitignore).
|
||||||
Note that .ignore files will continue to be respected.
|
Note that .ignore files will continue to be respected.
|
||||||
|
|
||||||
--null
|
-0, --null
|
||||||
: Whenever a file name is printed, follow it with a NUL byte.
|
: Whenever a file name is printed, follow it with a NUL byte.
|
||||||
This includes printing filenames before matches, and when printing
|
This includes printing filenames before matches, and when printing
|
||||||
a list of matching files such as with --count, --files-with-matches
|
a list of matching files such as with --count, --files-with-matches
|
||||||
and --files.
|
and --files.
|
||||||
|
|
||||||
|
-o, --only-matching
|
||||||
|
: Print only the matched (non-empty) parts of a matching line, with each such
|
||||||
|
part on a separate output line.
|
||||||
|
|
||||||
--path-separator *SEPARATOR*
|
--path-separator *SEPARATOR*
|
||||||
: The path separator to use when printing file paths. This defaults to your
|
: The path separator to use when printing file paths. This defaults to your
|
||||||
platform's path separator, which is / on Unix and \\ on Windows. This flag is
|
platform's path separator, which is / on Unix and \\ on Windows. This flag is
|
||||||
|
@@ -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.8" #:version
|
version = "0.2.0" #: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"
|
||||||
|
@@ -279,7 +279,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(),
|
||||||
@@ -420,7 +425,12 @@ impl GitignoreBuilder {
|
|||||||
GlobBuilder::new(&glob.actual)
|
GlobBuilder::new(&glob.actual)
|
||||||
.literal_separator(literal_separator)
|
.literal_separator(literal_separator)
|
||||||
.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)
|
||||||
|
@@ -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)
|
||||||
}
|
}
|
||||||
|
@@ -155,6 +155,7 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
|
|||||||
("mk", &["mkfile"]),
|
("mk", &["mkfile"]),
|
||||||
("ml", &["*.ml"]),
|
("ml", &["*.ml"]),
|
||||||
("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"]),
|
||||||
@@ -191,6 +192,7 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
|
|||||||
("twig", &["*.twig"]),
|
("twig", &["*.twig"]),
|
||||||
("vala", &["*.vala"]),
|
("vala", &["*.vala"]),
|
||||||
("vb", &["*.vb"]),
|
("vb", &["*.vb"]),
|
||||||
|
("vim", &["*.vim"]),
|
||||||
("vimscript", &["*.vim"]),
|
("vimscript", &["*.vim"]),
|
||||||
("wiki", &["*.mediawiki", "*.wiki"]),
|
("wiki", &["*.mediawiki", "*.wiki"]),
|
||||||
("xml", &["*.xml"]),
|
("xml", &["*.xml"]),
|
||||||
@@ -446,13 +448,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,
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
class RipgrepBin < Formula
|
class RipgrepBin < Formula
|
||||||
version '0.4.0'
|
version '0.5.1'
|
||||||
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 "6ac71251909227f8ef7eda27d3080c954843f3665b81e455362c90b2a9c4734a"
|
sha256 "517e40823f151ceb85840c8f147206360ee093aecbe96de20be4c2d5517d51ca"
|
||||||
|
|
||||||
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]
|
73
src/app.rs
73
src/app.rs
@@ -32,16 +32,6 @@ ARGS:
|
|||||||
OPTIONS:
|
OPTIONS:
|
||||||
{unified}";
|
{unified}";
|
||||||
|
|
||||||
/// Build a clap application with short help strings.
|
|
||||||
pub fn app_short() -> App<'static, 'static> {
|
|
||||||
app(false, |k| USAGES[k].short)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Build a clap application with long help strings.
|
|
||||||
pub fn app_long() -> App<'static, 'static> {
|
|
||||||
app(true, |k| USAGES[k].long)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Build a clap application parameterized by usage strings.
|
/// Build a clap application parameterized by usage strings.
|
||||||
///
|
///
|
||||||
/// The function given should take a clap argument name and return a help
|
/// The function given should take a clap argument name and return a help
|
||||||
@@ -49,10 +39,11 @@ pub fn app_long() -> App<'static, 'static> {
|
|||||||
///
|
///
|
||||||
/// This is an intentionally stand-alone module so that it can be used easily
|
/// This is an intentionally stand-alone module so that it can be used easily
|
||||||
/// in a `build.rs` script to build shell completion files.
|
/// in a `build.rs` script to build shell completion files.
|
||||||
fn app<F>(next_line_help: bool, doc: F) -> App<'static, 'static>
|
pub fn app() -> App<'static, 'static> {
|
||||||
where F: Fn(&'static str) -> &'static str {
|
|
||||||
let arg = |name| {
|
let arg = |name| {
|
||||||
Arg::with_name(name).help(doc(name)).next_line_help(next_line_help)
|
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);
|
||||||
|
|
||||||
@@ -64,16 +55,12 @@ fn app<F>(next_line_help: bool, doc: F) -> App<'static, 'static>
|
|||||||
.setting(AppSettings::UnifiedHelpMessage)
|
.setting(AppSettings::UnifiedHelpMessage)
|
||||||
.usage(USAGE)
|
.usage(USAGE)
|
||||||
.template(TEMPLATE)
|
.template(TEMPLATE)
|
||||||
// Handle help/version manually to make their output formatting
|
.help_message("Prints help information. Use --help for more details.")
|
||||||
// consistent with short/long views.
|
|
||||||
.arg(arg("help-short").short("h"))
|
|
||||||
.arg(flag("help"))
|
|
||||||
.arg(flag("version").short("V"))
|
|
||||||
// First, set up primary positional/flag arguments.
|
// 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",
|
||||||
"version",
|
"ripgrep-version",
|
||||||
]))
|
]))
|
||||||
.arg(arg("path").multiple(true))
|
.arg(arg("path").multiple(true))
|
||||||
.arg(flag("regexp").short("e")
|
.arg(flag("regexp").short("e")
|
||||||
@@ -129,6 +116,8 @@ fn app<F>(next_line_help: bool, doc: F) -> 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)
|
||||||
@@ -158,10 +147,13 @@ fn app<F>(next_line_help: bool, doc: F) -> App<'static, 'static>
|
|||||||
.arg(flag("no-ignore"))
|
.arg(flag("no-ignore"))
|
||||||
.arg(flag("no-ignore-parent"))
|
.arg(flag("no-ignore-parent"))
|
||||||
.arg(flag("no-ignore-vcs"))
|
.arg(flag("no-ignore-vcs"))
|
||||||
.arg(flag("null"))
|
.arg(flag("null").short("0"))
|
||||||
|
.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").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"))
|
||||||
@@ -206,7 +198,7 @@ lazy_static! {
|
|||||||
doc!(h, "help",
|
doc!(h, "help",
|
||||||
"Show verbose help output.",
|
"Show verbose help output.",
|
||||||
"When given, more details about flags are provided.");
|
"When given, more details about flags are provided.");
|
||||||
doc!(h, "version",
|
doc!(h, "ripgrep-version",
|
||||||
"Prints version information.");
|
"Prints version information.");
|
||||||
|
|
||||||
doc!(h, "pattern",
|
doc!(h, "pattern",
|
||||||
@@ -249,12 +241,12 @@ lazy_static! {
|
|||||||
red, blue, green, cyan, magenta, yellow, white and black. \
|
red, blue, green, cyan, magenta, yellow, white and black. \
|
||||||
Styles are limited to nobold, bold, nointense or intense.\n\n\
|
Styles are limited to nobold, bold, nointense or intense.\n\n\
|
||||||
The format of the flag is {type}:{attribute}:{value}. {type} \
|
The format of the flag is {type}:{attribute}:{value}. {type} \
|
||||||
should be one of path, line or match. {attribute} can be fg, bg \
|
should be one of path, line, column or match. {attribute} can \
|
||||||
or style. {value} is either a color (for fg and bg) or a text \
|
be fg, bg or style. {value} is either a color (for fg and bg) \
|
||||||
style. A special format, {type}:none, will clear all color \
|
or a text style. A special format, {type}:none, will clear all \
|
||||||
settings for {type}.\n\nFor example, the following command will \
|
color settings for {type}.\n\nFor example, the following \
|
||||||
change the match color to magenta and the background color for \
|
command will change the match color to magenta and the \
|
||||||
line numbers to yellow:\n\n\
|
background color for line numbers to yellow:\n\n\
|
||||||
rg --colors 'match:fg:magenta' --colors 'line:bg:yellow' foo.");
|
rg --colors 'match:fg:magenta' --colors 'line:bg:yellow' foo.");
|
||||||
doc!(h, "encoding",
|
doc!(h, "encoding",
|
||||||
"Specify the text encoding of files to search.",
|
"Specify the text encoding of files to search.",
|
||||||
@@ -340,6 +332,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 \
|
||||||
@@ -388,10 +387,11 @@ lazy_static! {
|
|||||||
"Limit the number of matching lines per file searched to NUM.");
|
"Limit the number of matching lines per file searched to NUM.");
|
||||||
doc!(h, "max-filesize",
|
doc!(h, "max-filesize",
|
||||||
"Ignore files larger than NUM in size.",
|
"Ignore files larger than NUM in size.",
|
||||||
"Ignore files larger than NUM in size. Does not ignore directories. \
|
"Ignore files larger than NUM in size. Does not ignore \
|
||||||
|
directories. \
|
||||||
\n\nThe input format accepts suffixes of K, M or G which \
|
\n\nThe input format accepts suffixes of K, M or G which \
|
||||||
correspond to kilobytes, megabytes and gigabytes. If no suffix is \
|
correspond to kilobytes, megabytes and gigabytes. If no suffix \
|
||||||
provided the input is treated as bytes. \
|
is provided the input is treated as bytes. \
|
||||||
\n\nExample: --max-filesize 50K or --max-filesize 80M");
|
\n\nExample: --max-filesize 50K or --max-filesize 80M");
|
||||||
doc!(h, "maxdepth",
|
doc!(h, "maxdepth",
|
||||||
"Descend at most NUM directories.",
|
"Descend at most NUM directories.",
|
||||||
@@ -435,6 +435,10 @@ lazy_static! {
|
|||||||
printing a list of matching files such as with --count, \
|
printing a list of matching files such as with --count, \
|
||||||
--files-with-matches and --files. This option is useful for use \
|
--files-with-matches and --files. This option is useful for use \
|
||||||
with xargs.");
|
with xargs.");
|
||||||
|
doc!(h, "only-matching",
|
||||||
|
"Print only matched parts of a line.",
|
||||||
|
"Print only the matched (non-empty) parts of a matching line, \
|
||||||
|
with each such part on a separate output line.");
|
||||||
doc!(h, "path-separator",
|
doc!(h, "path-separator",
|
||||||
"Path separator to use when printing file paths.",
|
"Path separator to use when printing file paths.",
|
||||||
"The path separator to use when printing file paths. This \
|
"The path separator to use when printing file paths. This \
|
||||||
@@ -453,6 +457,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 \
|
||||||
@@ -496,8 +505,8 @@ lazy_static! {
|
|||||||
permits specifying one or more other type names (separated by a \
|
permits specifying one or more other type names (separated by a \
|
||||||
comma) that have been defined and its rules will automatically \
|
comma) that have been defined and its rules will automatically \
|
||||||
be imported into the type specified. For example, to create a \
|
be imported into the type specified. For example, to create a \
|
||||||
type called src that matches C++, Python and Markdown files, one \
|
type called src that matches C++, Python and Markdown files, \
|
||||||
can use:\n\n\
|
one can use:\n\n\
|
||||||
--type-add 'src:include:cpp,py,md'\n\n\
|
--type-add 'src:include:cpp,py,md'\n\n\
|
||||||
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:\n\n\
|
using the --type-add flag again:\n\n\
|
||||||
|
118
src/args.rs
118
src/args.rs
@@ -5,7 +5,6 @@ use std::fs;
|
|||||||
use std::io::{self, BufRead};
|
use std::io::{self, BufRead};
|
||||||
use std::ops;
|
use std::ops;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
@@ -66,6 +65,7 @@ pub struct Args {
|
|||||||
no_ignore_vcs: bool,
|
no_ignore_vcs: bool,
|
||||||
no_messages: bool,
|
no_messages: bool,
|
||||||
null: bool,
|
null: bool,
|
||||||
|
only_matching: bool,
|
||||||
path_separator: Option<u8>,
|
path_separator: Option<u8>,
|
||||||
quiet: bool,
|
quiet: bool,
|
||||||
quiet_matched: QuietMatched,
|
quiet_matched: QuietMatched,
|
||||||
@@ -88,21 +88,7 @@ impl Args {
|
|||||||
///
|
///
|
||||||
/// Also, initialize a global logger.
|
/// Also, initialize a global logger.
|
||||||
pub fn parse() -> Result<Args> {
|
pub fn parse() -> Result<Args> {
|
||||||
let matches = app::app_short().get_matches();
|
let matches = app::app().get_matches();
|
||||||
if matches.is_present("help-short") {
|
|
||||||
let _ = ::app::app_short().print_help();
|
|
||||||
println!("");
|
|
||||||
process::exit(0);
|
|
||||||
}
|
|
||||||
if matches.is_present("help") {
|
|
||||||
let _ = ::app::app_long().print_help();
|
|
||||||
println!("");
|
|
||||||
process::exit(0);
|
|
||||||
}
|
|
||||||
if matches.is_present("version") {
|
|
||||||
println!("ripgrep {}", crate_version!());
|
|
||||||
process::exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut logb = env_logger::LogBuilder::new();
|
let mut logb = env_logger::LogBuilder::new();
|
||||||
if matches.is_present("debug") {
|
if matches.is_present("debug") {
|
||||||
@@ -156,6 +142,7 @@ impl Args {
|
|||||||
.heading(self.heading)
|
.heading(self.heading)
|
||||||
.line_per_match(self.line_per_match)
|
.line_per_match(self.line_per_match)
|
||||||
.null(self.null)
|
.null(self.null)
|
||||||
|
.only_matching(self.only_matching)
|
||||||
.path_separator(self.path_separator)
|
.path_separator(self.path_separator)
|
||||||
.with_filename(self.with_filename)
|
.with_filename(self.with_filename)
|
||||||
.max_columns(self.max_columns);
|
.max_columns(self.max_columns);
|
||||||
@@ -360,6 +347,7 @@ impl<'a> ArgMatches<'a> {
|
|||||||
no_ignore_vcs: self.no_ignore_vcs(),
|
no_ignore_vcs: self.no_ignore_vcs(),
|
||||||
no_messages: self.is_present("no-messages"),
|
no_messages: self.is_present("no-messages"),
|
||||||
null: self.is_present("null"),
|
null: self.is_present("null"),
|
||||||
|
only_matching: self.is_present("only-matching"),
|
||||||
path_separator: try!(self.path_separator()),
|
path_separator: try!(self.path_separator()),
|
||||||
quiet: quiet,
|
quiet: quiet,
|
||||||
quiet_matched: QuietMatched::new(quiet),
|
quiet_matched: QuietMatched::new(quiet),
|
||||||
@@ -749,7 +737,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))),
|
||||||
@@ -783,12 +771,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.
|
||||||
@@ -819,31 +813,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")
|
||||||
@@ -938,6 +965,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 {
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
#![allow(dead_code)]
|
|
||||||
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::io::{self, Read};
|
use std::io::{self, Read};
|
||||||
|
|
||||||
@@ -290,10 +288,6 @@ mod tests {
|
|||||||
|
|
||||||
use super::{Bom, BomPeeker, DecodeReader};
|
use super::{Bom, BomPeeker, DecodeReader};
|
||||||
|
|
||||||
fn utf8(bytes: &[u8]) -> &str {
|
|
||||||
::std::str::from_utf8(bytes).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_to_string<R: Read>(mut rdr: R) -> String {
|
fn read_to_string<R: Read>(mut rdr: R) -> String {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
rdr.read_to_string(&mut s).unwrap();
|
rdr.read_to_string(&mut s).unwrap();
|
||||||
@@ -453,7 +447,8 @@ mod tests {
|
|||||||
test_trans_simple!(trans_simple_utf16be, "utf-16be", b"\x04\x16", "Ж");
|
test_trans_simple!(trans_simple_utf16be, "utf-16be", b"\x04\x16", "Ж");
|
||||||
test_trans_simple!(trans_simple_chinese, "chinese", b"\xA7\xA8", "Ж");
|
test_trans_simple!(trans_simple_chinese, "chinese", b"\xA7\xA8", "Ж");
|
||||||
test_trans_simple!(trans_simple_korean, "korean", b"\xAC\xA8", "Ж");
|
test_trans_simple!(trans_simple_korean, "korean", b"\xAC\xA8", "Ж");
|
||||||
test_trans_simple!(trans_simple_big5_hkscs, "big5-hkscs", b"\xC7\xFA", "Ж");
|
test_trans_simple!(
|
||||||
|
trans_simple_big5_hkscs, "big5-hkscs", b"\xC7\xFA", "Ж");
|
||||||
test_trans_simple!(trans_simple_gbk, "gbk", b"\xA7\xA8", "Ж");
|
test_trans_simple!(trans_simple_gbk, "gbk", b"\xA7\xA8", "Ж");
|
||||||
test_trans_simple!(trans_simple_sjis, "sjis", b"\x84\x47", "Ж");
|
test_trans_simple!(trans_simple_sjis, "sjis", b"\x84\x47", "Ж");
|
||||||
test_trans_simple!(trans_simple_eucjp, "euc-jp", b"\xA7\xA8", "Ж");
|
test_trans_simple!(trans_simple_eucjp, "euc-jp", b"\xA7\xA8", "Ж");
|
||||||
|
200
src/printer.rs
200
src/printer.rs
@@ -58,6 +58,8 @@ pub struct Printer<W> {
|
|||||||
/// Whether to print NUL bytes after a file path instead of new lines
|
/// Whether to print NUL bytes after a file path instead of new lines
|
||||||
/// or `:`.
|
/// or `:`.
|
||||||
null: bool,
|
null: bool,
|
||||||
|
/// Print only the matched (non-empty) parts of a matching line
|
||||||
|
only_matching: bool,
|
||||||
/// A string to use as a replacement of each match in a matching line.
|
/// A string to use as a replacement of each match in a matching line.
|
||||||
replace: Option<Vec<u8>>,
|
replace: Option<Vec<u8>>,
|
||||||
/// Whether to prefix each match with the corresponding file name.
|
/// Whether to prefix each match with the corresponding file name.
|
||||||
@@ -83,6 +85,7 @@ impl<W: WriteColor> Printer<W> {
|
|||||||
heading: false,
|
heading: false,
|
||||||
line_per_match: false,
|
line_per_match: false,
|
||||||
null: false,
|
null: false,
|
||||||
|
only_matching: false,
|
||||||
replace: None,
|
replace: None,
|
||||||
with_filename: false,
|
with_filename: false,
|
||||||
colors: ColorSpecs::default(),
|
colors: ColorSpecs::default(),
|
||||||
@@ -144,6 +147,12 @@ impl<W: WriteColor> Printer<W> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Print only the matched (non-empty) parts of a matching line
|
||||||
|
pub fn only_matching(mut self, yes: bool) -> Printer<W> {
|
||||||
|
self.only_matching = yes;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// A separator to use when printing file paths. When empty, use the
|
/// A separator to use when printing file paths. When empty, use the
|
||||||
/// default separator for the current platform. (/ on Unix, \ on Windows.)
|
/// default separator for the current platform. (/ on Unix, \ on Windows.)
|
||||||
pub fn path_separator(mut self, sep: Option<u8>) -> Printer<W> {
|
pub fn path_separator(mut self, sep: Option<u8>) -> Printer<W> {
|
||||||
@@ -153,9 +162,6 @@ impl<W: WriteColor> Printer<W> {
|
|||||||
|
|
||||||
/// Replace every match in each matching line with the replacement string
|
/// Replace every match in each matching line with the replacement string
|
||||||
/// given.
|
/// given.
|
||||||
///
|
|
||||||
/// The replacement string syntax is documented here:
|
|
||||||
/// https://doc.rust-lang.org/regex/regex/bytes/struct.Captures.html#method.expand
|
|
||||||
pub fn replace(mut self, replacement: Vec<u8>) -> Printer<W> {
|
pub fn replace(mut self, replacement: Vec<u8>) -> Printer<W> {
|
||||||
self.replace = Some(replacement);
|
self.replace = Some(replacement);
|
||||||
self
|
self
|
||||||
@@ -204,22 +210,14 @@ impl<W: WriteColor> Printer<W> {
|
|||||||
pub fn path<P: AsRef<Path>>(&mut self, path: P) {
|
pub fn path<P: AsRef<Path>>(&mut self, path: P) {
|
||||||
let path = strip_prefix("./", path.as_ref()).unwrap_or(path.as_ref());
|
let path = strip_prefix("./", path.as_ref()).unwrap_or(path.as_ref());
|
||||||
self.write_path(path);
|
self.write_path(path);
|
||||||
if self.null {
|
self.write_path_eol();
|
||||||
self.write(b"\x00");
|
|
||||||
} else {
|
|
||||||
self.write_eol();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints the given path and a count of the number of matches found.
|
/// Prints the given path and a count of the number of matches found.
|
||||||
pub fn path_count<P: AsRef<Path>>(&mut self, path: P, count: u64) {
|
pub fn path_count<P: AsRef<Path>>(&mut self, path: P, count: u64) {
|
||||||
if self.with_filename {
|
if self.with_filename {
|
||||||
self.write_path(path);
|
self.write_path(path);
|
||||||
if self.null {
|
self.write_path_sep(b':');
|
||||||
self.write(b"\x00");
|
|
||||||
} else {
|
|
||||||
self.write(b":");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.write(count.to_string().as_bytes());
|
self.write(count.to_string().as_bytes());
|
||||||
self.write_eol();
|
self.write_eol();
|
||||||
@@ -227,13 +225,11 @@ impl<W: WriteColor> Printer<W> {
|
|||||||
|
|
||||||
/// Prints the context separator.
|
/// Prints the context separator.
|
||||||
pub fn context_separate(&mut self) {
|
pub fn context_separate(&mut self) {
|
||||||
// N.B. We can't use `write` here because of borrowing restrictions.
|
|
||||||
if self.context_separator.is_empty() {
|
if self.context_separator.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.has_printed = true;
|
|
||||||
let _ = self.wtr.write_all(&self.context_separator);
|
let _ = self.wtr.write_all(&self.context_separator);
|
||||||
let _ = self.wtr.write_all(&[self.eol]);
|
self.write_eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn matched<P: AsRef<Path>>(
|
pub fn matched<P: AsRef<Path>>(
|
||||||
@@ -245,24 +241,14 @@ impl<W: WriteColor> Printer<W> {
|
|||||||
end: usize,
|
end: usize,
|
||||||
line_number: Option<u64>,
|
line_number: Option<u64>,
|
||||||
) {
|
) {
|
||||||
if !self.line_per_match {
|
if !self.line_per_match && !self.only_matching {
|
||||||
let column =
|
let column = re.find(&buf[start..end])
|
||||||
if self.column {
|
.map(|m| m.start()).unwrap_or(0);
|
||||||
Some(re.find(&buf[start..end])
|
|
||||||
.map(|m| m.start()).unwrap_or(0) as u64)
|
|
||||||
} 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, column);
|
||||||
}
|
}
|
||||||
for m in re.find_iter(&buf[start..end]) {
|
for m in re.find_iter(&buf[start..end]) {
|
||||||
let column =
|
let column = m.start();
|
||||||
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, column);
|
||||||
}
|
}
|
||||||
@@ -276,20 +262,21 @@ impl<W: WriteColor> Printer<W> {
|
|||||||
start: usize,
|
start: usize,
|
||||||
end: usize,
|
end: usize,
|
||||||
line_number: Option<u64>,
|
line_number: Option<u64>,
|
||||||
column: Option<u64>,
|
column: 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();
|
||||||
self.write_heading(path.as_ref());
|
self.write_path(path);
|
||||||
|
self.write_path_eol();
|
||||||
} else if !self.heading && self.with_filename {
|
} else if !self.heading && self.with_filename {
|
||||||
self.write_non_heading_path(path.as_ref());
|
self.write_path(path);
|
||||||
|
self.write_path_sep(b':');
|
||||||
}
|
}
|
||||||
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.write((c + 1).to_string().as_bytes());
|
self.column_number(column as u64 + 1, b':');
|
||||||
self.write(b":");
|
|
||||||
}
|
}
|
||||||
if self.replace.is_some() {
|
if self.replace.is_some() {
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
@@ -299,11 +286,9 @@ impl<W: WriteColor> Printer<W> {
|
|||||||
re.replace_all(&buf[start..end], replacer)
|
re.replace_all(&buf[start..end], replacer)
|
||||||
};
|
};
|
||||||
if self.max_columns.map_or(false, |m| line.len() > m) {
|
if self.max_columns.map_or(false, |m| line.len() > m) {
|
||||||
let _ = self.wtr.set_color(self.colors.matched());
|
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
"[Omitted long line with {} replacements]", count);
|
"[Omitted long line with {} replacements]", count);
|
||||||
self.write(msg.as_bytes());
|
self.write_colored(msg.as_bytes(), |colors| colors.matched());
|
||||||
let _ = self.wtr.reset();
|
|
||||||
self.write_eol();
|
self.write_eol();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -312,7 +297,14 @@ impl<W: WriteColor> Printer<W> {
|
|||||||
self.write_eol();
|
self.write_eol();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.write_matched_line(re, &buf[start..end]);
|
let line_buf = if self.only_matching {
|
||||||
|
let start_offset = start + column;
|
||||||
|
let m = re.find(&buf[start_offset..end]).unwrap();
|
||||||
|
&buf[start_offset + m.start()..start_offset + m.end()]
|
||||||
|
} else {
|
||||||
|
&buf[start..end]
|
||||||
|
};
|
||||||
|
self.write_matched_line(re, line_buf);
|
||||||
// write_matched_line guarantees to write a newline.
|
// write_matched_line guarantees to write a newline.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -320,10 +312,8 @@ impl<W: WriteColor> Printer<W> {
|
|||||||
fn write_matched_line(&mut self, re: &Regex, buf: &[u8]) {
|
fn write_matched_line(&mut self, re: &Regex, buf: &[u8]) {
|
||||||
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 _ = self.wtr.set_color(self.colors.matched());
|
|
||||||
let msg = format!("[Omitted long line with {} matches]", count);
|
let msg = format!("[Omitted long line with {} matches]", count);
|
||||||
self.write(msg.as_bytes());
|
self.write_colored(msg.as_bytes(), |colors| colors.matched());
|
||||||
let _ = self.wtr.reset();
|
|
||||||
self.write_eol();
|
self.write_eol();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -333,9 +323,8 @@ impl<W: WriteColor> Printer<W> {
|
|||||||
let mut last_written = 0;
|
let mut last_written = 0;
|
||||||
for m in re.find_iter(buf) {
|
for m in re.find_iter(buf) {
|
||||||
self.write(&buf[last_written..m.start()]);
|
self.write(&buf[last_written..m.start()]);
|
||||||
let _ = self.wtr.set_color(self.colors.matched());
|
self.write_colored(
|
||||||
self.write(&buf[m.start()..m.end()]);
|
&buf[m.start()..m.end()], |colors| colors.matched());
|
||||||
let _ = self.wtr.reset();
|
|
||||||
last_written = m.end();
|
last_written = m.end();
|
||||||
}
|
}
|
||||||
self.write(&buf[last_written..]);
|
self.write(&buf[last_written..]);
|
||||||
@@ -355,14 +344,11 @@ impl<W: WriteColor> Printer<W> {
|
|||||||
) {
|
) {
|
||||||
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();
|
||||||
self.write_heading(path.as_ref());
|
self.write_path(path);
|
||||||
|
self.write_path_eol();
|
||||||
} else if !self.heading && self.with_filename {
|
} else if !self.heading && self.with_filename {
|
||||||
self.write_path(path.as_ref());
|
self.write_path(path);
|
||||||
if self.null {
|
self.write_path_sep(b'-');
|
||||||
self.write(b"\x00");
|
|
||||||
} else {
|
|
||||||
self.write(b"-");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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'-');
|
||||||
@@ -378,10 +364,19 @@ impl<W: WriteColor> Printer<W> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_heading<P: AsRef<Path>>(&mut self, path: P) {
|
fn separator(&mut self, sep: &[u8]) {
|
||||||
let _ = self.wtr.set_color(self.colors.path());
|
self.write(&sep);
|
||||||
self.write_path(path.as_ref());
|
}
|
||||||
let _ = self.wtr.reset();
|
|
||||||
|
fn write_path_sep(&mut self, sep: u8) {
|
||||||
|
if self.null {
|
||||||
|
self.write(b"\x00");
|
||||||
|
} else {
|
||||||
|
self.separator(&[sep]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_path_eol(&mut self) {
|
||||||
if self.null {
|
if self.null {
|
||||||
self.write(b"\x00");
|
self.write(b"\x00");
|
||||||
} else {
|
} else {
|
||||||
@@ -389,52 +384,43 @@ impl<W: WriteColor> Printer<W> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_non_heading_path<P: AsRef<Path>>(&mut self, path: P) {
|
|
||||||
let _ = self.wtr.set_color(self.colors.path());
|
|
||||||
self.write_path(path.as_ref());
|
|
||||||
let _ = self.wtr.reset();
|
|
||||||
if self.null {
|
|
||||||
self.write(b"\x00");
|
|
||||||
} else {
|
|
||||||
self.write(b":");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn line_number(&mut self, n: u64, sep: u8) {
|
|
||||||
let _ = self.wtr.set_color(self.colors.line());
|
|
||||||
self.write(n.to_string().as_bytes());
|
|
||||||
let _ = self.wtr.reset();
|
|
||||||
self.write(&[sep]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn write_path<P: AsRef<Path>>(&mut self, path: P) {
|
fn write_path<P: AsRef<Path>>(&mut self, path: P) {
|
||||||
use std::os::unix::ffi::OsStrExt;
|
use std::os::unix::ffi::OsStrExt;
|
||||||
|
|
||||||
let path = path.as_ref().as_os_str().as_bytes();
|
let path = path.as_ref().as_os_str().as_bytes();
|
||||||
match self.path_separator {
|
self.write_path_replace_separator(path);
|
||||||
None => self.write(path),
|
|
||||||
Some(sep) => self.write_path_with_sep(path, sep),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
fn write_path<P: AsRef<Path>>(&mut self, path: P) {
|
fn write_path<P: AsRef<Path>>(&mut self, path: P) {
|
||||||
let path = path.as_ref().to_string_lossy();
|
let path = path.as_ref().to_string_lossy();
|
||||||
|
self.write_path_replace_separator(path.as_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_path_replace_separator(&mut self, path: &[u8]) {
|
||||||
match self.path_separator {
|
match self.path_separator {
|
||||||
None => self.write(path.as_bytes()),
|
None => self.write_colored(path, |colors| colors.path()),
|
||||||
Some(sep) => self.write_path_with_sep(path.as_bytes(), sep),
|
Some(sep) => {
|
||||||
|
let transformed_path: Vec<_> = path.iter().map(|&b| {
|
||||||
|
if b == b'/' || (cfg!(windows) && b == b'\\') {
|
||||||
|
sep
|
||||||
|
} else {
|
||||||
|
b
|
||||||
|
}
|
||||||
|
}).collect();
|
||||||
|
self.write_colored(&transformed_path, |colors| colors.path());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_path_with_sep(&mut self, path: &[u8], sep: u8) {
|
fn line_number(&mut self, n: u64, sep: u8) {
|
||||||
let mut path = path.to_vec();
|
self.write_colored(n.to_string().as_bytes(), |colors| colors.line());
|
||||||
for b in &mut path {
|
self.separator(&[sep]);
|
||||||
if *b == b'/' || (cfg!(windows) && *b == b'\\') {
|
|
||||||
*b = sep;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
self.write(&path);
|
fn column_number(&mut self, n: u64, sep: u8) {
|
||||||
|
self.write_colored(n.to_string().as_bytes(), |colors| colors.column());
|
||||||
|
self.separator(&[sep]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&mut self, buf: &[u8]) {
|
fn write(&mut self, buf: &[u8]) {
|
||||||
@@ -447,6 +433,14 @@ impl<W: WriteColor> Printer<W> {
|
|||||||
self.write(&[eol]);
|
self.write(&[eol]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_colored<F>(&mut self, buf: &[u8], get_color: F)
|
||||||
|
where F: Fn(&ColorSpecs) -> &ColorSpec
|
||||||
|
{
|
||||||
|
let _ = self.wtr.set_color( get_color(&self.colors) );
|
||||||
|
self.write(buf);
|
||||||
|
let _ = self.wtr.reset();
|
||||||
|
}
|
||||||
|
|
||||||
fn write_file_sep(&mut self) {
|
fn write_file_sep(&mut self) {
|
||||||
if let Some(ref sep) = self.file_separator {
|
if let Some(ref sep) = self.file_separator {
|
||||||
self.has_printed = true;
|
self.has_printed = true;
|
||||||
@@ -492,7 +486,7 @@ impl fmt::Display for Error {
|
|||||||
match *self {
|
match *self {
|
||||||
Error::UnrecognizedOutType(ref name) => {
|
Error::UnrecognizedOutType(ref name) => {
|
||||||
write!(f, "Unrecognized output type '{}'. Choose from: \
|
write!(f, "Unrecognized output type '{}'. Choose from: \
|
||||||
path, line, match.", name)
|
path, line, column, match.", name)
|
||||||
}
|
}
|
||||||
Error::UnrecognizedSpecType(ref name) => {
|
Error::UnrecognizedSpecType(ref name) => {
|
||||||
write!(f, "Unrecognized spec type '{}'. Choose from: \
|
write!(f, "Unrecognized spec type '{}'. Choose from: \
|
||||||
@@ -503,11 +497,13 @@ impl fmt::Display for Error {
|
|||||||
}
|
}
|
||||||
Error::UnrecognizedStyle(ref name) => {
|
Error::UnrecognizedStyle(ref name) => {
|
||||||
write!(f, "Unrecognized style attribute '{}'. Choose from: \
|
write!(f, "Unrecognized style attribute '{}'. Choose from: \
|
||||||
nobold, bold.", name)
|
nobold, bold, nointense, intense.", name)
|
||||||
}
|
}
|
||||||
Error::InvalidFormat(ref original) => {
|
Error::InvalidFormat(ref original) => {
|
||||||
write!(f, "Invalid color speci format: '{}'. Valid format \
|
write!(
|
||||||
is '(path|line|match):(fg|bg|style):(value)'.",
|
f,
|
||||||
|
"Invalid color speci format: '{}'. Valid format \
|
||||||
|
is '(path|line|column|match):(fg|bg|style):(value)'.",
|
||||||
original)
|
original)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -525,6 +521,7 @@ impl From<ParseColorError> for Error {
|
|||||||
pub struct ColorSpecs {
|
pub struct ColorSpecs {
|
||||||
path: ColorSpec,
|
path: ColorSpec,
|
||||||
line: ColorSpec,
|
line: ColorSpec,
|
||||||
|
column: ColorSpec,
|
||||||
matched: ColorSpec,
|
matched: ColorSpec,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -554,7 +551,7 @@ pub struct ColorSpecs {
|
|||||||
/// The format of a `Spec` is a triple: `{type}:{attribute}:{value}`. Each
|
/// The format of a `Spec` is a triple: `{type}:{attribute}:{value}`. Each
|
||||||
/// component is defined as follows:
|
/// component is defined as follows:
|
||||||
///
|
///
|
||||||
/// * `{type}` can be one of `path`, `line` or `match`.
|
/// * `{type}` can be one of `path`, `line`, `column` or `match`.
|
||||||
/// * `{attribute}` can be one of `fg`, `bg` or `style`. `{attribute}` may also
|
/// * `{attribute}` can be one of `fg`, `bg` or `style`. `{attribute}` may also
|
||||||
/// be the special value `none`, in which case, `{value}` can be omitted.
|
/// be the special value `none`, in which case, `{value}` can be omitted.
|
||||||
/// * `{value}` is either a color name (for `fg`/`bg`) or a style instruction.
|
/// * `{value}` is either a color name (for `fg`/`bg`) or a style instruction.
|
||||||
@@ -593,6 +590,7 @@ enum SpecValue {
|
|||||||
enum OutType {
|
enum OutType {
|
||||||
Path,
|
Path,
|
||||||
Line,
|
Line,
|
||||||
|
Column,
|
||||||
Match,
|
Match,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -623,6 +621,7 @@ impl ColorSpecs {
|
|||||||
match user_spec.ty {
|
match user_spec.ty {
|
||||||
OutType::Path => user_spec.merge_into(&mut specs.path),
|
OutType::Path => user_spec.merge_into(&mut specs.path),
|
||||||
OutType::Line => user_spec.merge_into(&mut specs.line),
|
OutType::Line => user_spec.merge_into(&mut specs.line),
|
||||||
|
OutType::Column => user_spec.merge_into(&mut specs.column),
|
||||||
OutType::Match => user_spec.merge_into(&mut specs.matched),
|
OutType::Match => user_spec.merge_into(&mut specs.matched),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -639,6 +638,11 @@ impl ColorSpecs {
|
|||||||
&self.line
|
&self.line
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the color specification for coloring column numbers.
|
||||||
|
fn column(&self) -> &ColorSpec {
|
||||||
|
&self.column
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the color specification for coloring matched text.
|
/// Return the color specification for coloring matched text.
|
||||||
fn matched(&self) -> &ColorSpec {
|
fn matched(&self) -> &ColorSpec {
|
||||||
&self.matched
|
&self.matched
|
||||||
@@ -714,6 +718,7 @@ impl FromStr for OutType {
|
|||||||
match &*s.to_lowercase() {
|
match &*s.to_lowercase() {
|
||||||
"path" => Ok(OutType::Path),
|
"path" => Ok(OutType::Path),
|
||||||
"line" => Ok(OutType::Line),
|
"line" => Ok(OutType::Line),
|
||||||
|
"column" => Ok(OutType::Column),
|
||||||
"match" => Ok(OutType::Match),
|
"match" => Ok(OutType::Match),
|
||||||
_ => Err(Error::UnrecognizedOutType(s.to_string())),
|
_ => Err(Error::UnrecognizedOutType(s.to_string())),
|
||||||
}
|
}
|
||||||
@@ -765,6 +770,7 @@ mod tests {
|
|||||||
assert_eq!(ColorSpecs::new(user_specs), ColorSpecs {
|
assert_eq!(ColorSpecs::new(user_specs), ColorSpecs {
|
||||||
path: ColorSpec::default(),
|
path: ColorSpec::default(),
|
||||||
line: ColorSpec::default(),
|
line: ColorSpec::default(),
|
||||||
|
column: ColorSpec::default(),
|
||||||
matched: expect_matched,
|
matched: expect_matched,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -800,6 +806,12 @@ mod tests {
|
|||||||
ty: OutType::Line,
|
ty: OutType::Line,
|
||||||
value: SpecValue::None,
|
value: SpecValue::None,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let spec: Spec = "column:bg:green".parse().unwrap();
|
||||||
|
assert_eq!(spec, Spec {
|
||||||
|
ty: OutType::Column,
|
||||||
|
value: SpecValue::Bg(Color::Green),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@@ -3,8 +3,8 @@ The `search_buffer` module is responsible for searching a single file all in a
|
|||||||
single buffer. Typically, the source of the buffer is a memory map. This can
|
single buffer. Typically, the source of the buffer is a memory map. This can
|
||||||
be useful for when memory maps are faster than streaming search.
|
be useful for when memory maps are faster than streaming search.
|
||||||
|
|
||||||
Note that this module doesn't quite support everything that `search_stream` does.
|
Note that this module doesn't quite support everything that `search_stream`
|
||||||
Notably, showing contexts.
|
does. Notably, showing contexts.
|
||||||
*/
|
*/
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
3
termcolor/COPYING
Normal file
3
termcolor/COPYING
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
This project is dual-licensed under the Unlicense and MIT licenses.
|
||||||
|
|
||||||
|
You may use this code under the terms of either license.
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "0.3.1" #:version
|
version = "0.3.2" #:version
|
||||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||||
description = """
|
description = """
|
||||||
A simple cross platform library for writing colored text to a terminal.
|
A simple cross platform library for writing colored text to a terminal.
|
||||||
|
21
termcolor/LICENSE-MIT
Normal file
21
termcolor/LICENSE-MIT
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Andrew Gallant
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
24
termcolor/UNLICENSE
Normal file
24
termcolor/UNLICENSE
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
For more information, please refer to <http://unlicense.org/>
|
166
tests/tests.rs
166
tests/tests.rs
@@ -455,7 +455,6 @@ sherlock!(max_filesize_parse_no_suffix, "Sherlock", ".",
|
|||||||
let expected = "\
|
let expected = "\
|
||||||
foo
|
foo
|
||||||
";
|
";
|
||||||
|
|
||||||
assert_eq!(lines, expected);
|
assert_eq!(lines, expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -470,7 +469,6 @@ sherlock!(max_filesize_parse_k_suffix, "Sherlock", ".",
|
|||||||
let expected = "\
|
let expected = "\
|
||||||
foo
|
foo
|
||||||
";
|
";
|
||||||
|
|
||||||
assert_eq!(lines, expected);
|
assert_eq!(lines, expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -485,10 +483,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);
|
||||||
@@ -1057,6 +1064,33 @@ clean!(regression_405, "test", ".", |wd: WorkDir, mut cmd: Command| {
|
|||||||
assert_eq!(lines, format!("{}:test\n", path("bar/foo/file2.txt")));
|
assert_eq!(lines, format!("{}:test\n", path("bar/foo/file2.txt")));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// See: https://github.com/BurntSushi/ripgrep/issues/428
|
||||||
|
clean!(regression_428_color_context_path, "foo", ".", |wd: WorkDir, mut cmd: Command| {
|
||||||
|
wd.create("sherlock", "foo\nbar");
|
||||||
|
cmd.arg("-A1").arg("-H").arg("--no-heading").arg("-N")
|
||||||
|
.arg("--colors=match:none").arg("--color=always");
|
||||||
|
|
||||||
|
let lines: String = wd.stdout(&mut cmd);
|
||||||
|
let expected = format!("\
|
||||||
|
{colored_path}:foo
|
||||||
|
{colored_path}-bar
|
||||||
|
", colored_path=format!("\x1b\x5b\x6d\x1b\x5b\x33\x35\x6d{path}\x1b\x5b\x6d", path=path("sherlock")));
|
||||||
|
assert_eq!(lines, expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
// See: https://github.com/BurntSushi/ripgrep/issues/428
|
||||||
|
clean!(regression_428_unrecognized_style, "Sherlok", ".", |wd: WorkDir, mut cmd: Command| {
|
||||||
|
cmd.arg("--colors=match:style:");
|
||||||
|
wd.assert_err(&mut cmd);
|
||||||
|
|
||||||
|
let output = cmd.output().unwrap();
|
||||||
|
let err = String::from_utf8_lossy(&output.stderr);
|
||||||
|
let expected = "\
|
||||||
|
Unrecognized style attribute ''. Choose from: nobold, bold, nointense, intense.
|
||||||
|
";
|
||||||
|
assert_eq!(err, expected);
|
||||||
|
});
|
||||||
|
|
||||||
// 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 =
|
||||||
@@ -1103,6 +1137,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");
|
||||||
@@ -1139,6 +1188,32 @@ be, to a very large extent, the result of luck. Sherlock Holmes
|
|||||||
assert_eq!(lines, expected);
|
assert_eq!(lines, expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// See: https://github.com/BurntSushi/ripgrep/issues/34
|
||||||
|
sherlock!(feature_34_only_matching, "Sherlock", ".",
|
||||||
|
|wd: WorkDir, mut cmd: Command| {
|
||||||
|
cmd.arg("--only-matching");
|
||||||
|
|
||||||
|
let lines: String = wd.stdout(&mut cmd);
|
||||||
|
let expected = "\
|
||||||
|
sherlock:Sherlock
|
||||||
|
sherlock:Sherlock
|
||||||
|
";
|
||||||
|
assert_eq!(lines, expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
// See: https://github.com/BurntSushi/ripgrep/issues/34
|
||||||
|
sherlock!(feature_34_only_matching_line_column, "Sherlock", ".",
|
||||||
|
|wd: WorkDir, mut cmd: Command| {
|
||||||
|
cmd.arg("--only-matching").arg("--column").arg("--line-number");
|
||||||
|
|
||||||
|
let lines: String = wd.stdout(&mut cmd);
|
||||||
|
let expected = "\
|
||||||
|
sherlock:1:57:Sherlock
|
||||||
|
sherlock:3:49:Sherlock
|
||||||
|
";
|
||||||
|
assert_eq!(lines, expected);
|
||||||
|
});
|
||||||
|
|
||||||
// See: https://github.com/BurntSushi/ripgrep/issues/45
|
// See: https://github.com/BurntSushi/ripgrep/issues/45
|
||||||
sherlock!(feature_45_relative_cwd, "test", ".",
|
sherlock!(feature_45_relative_cwd, "test", ".",
|
||||||
|wd: WorkDir, mut cmd: Command| {
|
|wd: WorkDir, mut cmd: Command| {
|
||||||
@@ -1390,6 +1465,46 @@ 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
|
||||||
|
sherlock!(feature_419_zero_as_shortcut_for_null, "Sherlock", ".",
|
||||||
|
|wd: WorkDir, mut cmd: Command| {
|
||||||
|
cmd.arg("-0").arg("--count");
|
||||||
|
|
||||||
|
let lines: String = wd.stdout(&mut cmd);
|
||||||
|
assert_eq!(lines, "sherlock\x002\n");
|
||||||
|
});
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn binary_nosearch() {
|
fn binary_nosearch() {
|
||||||
let wd = WorkDir::new("binary_nosearch");
|
let wd = WorkDir::new("binary_nosearch");
|
||||||
@@ -1492,6 +1607,51 @@ 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);
|
||||||
|
}
|
||||||
|
|
||||||
#[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>(
|
||||||
|
Reference in New Issue
Block a user