Compare commits

...

46 Commits
0.6.0 ... 0.7.0

Author SHA1 Message Date
Andrew Gallant
efa4de8126 cargo: bump to 0.7.0 2017-10-21 22:40:10 -04:00
Andrew Gallant
ad5fa56490 changelog 0.7.0 2017-10-21 22:40:10 -04:00
Andrew Gallant
1bf9d29259 ignore: be fastidious with file handles
This commit fixes the symlink loop checker in the parallel directory
traverser to open fewer handles at the expense of keeping handles held
open longer.

This roughly matches the corresponding change in walkdir:
5bcc5b87ee

Fixes #633
2017-10-21 22:40:10 -04:00
Andrew Gallant
2a14bf2249 printer: fix colors on empty matches
This fixes a bug where a "match" color escape was erroneously emitted
after the new line character. This is because `^` is actually allowed to
match after the end of a trailing new line, which means `^$` matches both
before and after the trailing new line when multiline mode is enabled.
The trailing match was causing the phantom escape sequence to appear,
which we don't want.

Incidentally, this is the root cause of #441 as well, although this commit
doesn't fix that issue, since the line itself is printed before we detect
the phantom match.

Fixes #599
2017-10-21 22:40:10 -04:00
Andrew Gallant
f0028a66ec style 2017-10-21 22:40:10 -04:00
Andrew Gallant
08060a2105 deps: update everything 2017-10-21 22:40:09 -04:00
Andrew Gallant
cd575d99f8 ignore: upgrade to walkdir 2
The uninteresting bits of this commit involve mechanical changes for
updates to walkdir 2. The more interesting bits of this commit are the
breaking changes, although none of them should require any significant
change on users of this library. The breaking changes are as follows:

* `DirEntry::path_is_symbolic_link` has been renamed to
  `DirEntry::path_is_symlink`. This matches the conventions in the
  standard library, and also the corresponding name change in walkdir.
* Removed the `From<walkdir::Error> for ignore::Error` impl. This was
  intended to only be used internally, but was the only thing that
  made `walkdir` a public dependency of `ignore`. Therefore, we remove
  it since it seems unnecessary.
* Renamed `WalkBuilder::sort_by` to `WalkBuilder::sort_by_file_name`,
  and changed the type of the comparator from

    Fn(&OsString, &OsString) -> cmp::Ordering + 'static

  to

    Fn(&OsStr, &OsStr) -> cmp::Ordering + Send + Sync + 'static

  The corresponding change in `walkdir` retains the `sort_by` name, but
  gives the comparator a pair of `&DirEntry` values instead of a pair
  of `&OsStr` values. Ideally, `ignore` would hand off its own pair of
  `&ignore::DirEntry` values, but this requires more design work. So for
  now, we retain previous functionality, but leave room to make a proper
  `sort_by` method.

[breaking-change]
2017-10-21 22:40:09 -04:00
Andrew Gallant
1267f01c24 deps: upgrade to memchr 2 2017-10-21 22:40:09 -04:00
Andrew Gallant
322d5515e5 style: 80 cols 2017-10-21 22:40:09 -04:00
Shubham Lagwankar
f4770c2094 Fix typos 2017-10-21 22:38:01 -04:00
Evgeny Kulikov
f887bc1f86 printer: --only-matching works with --replace
When -o/--only-matching is used with -r/--replace, the replacement works
as expected. This is not a breaking change because the flags were
previously set to conflict.
2017-10-20 20:58:27 -04:00
Sebastian Nowicki
363a4fa9b7 Fix path passed to try_create_bytes() 2017-10-20 20:51:12 -04:00
Sebastian Nowicki
712311fdc6 Don't create command until we know we can test it
For regression 210 we may not actually need to test anything if the file
system doesn't support creating files with invalid UTF-8 bytes. Don't
create the command until we know there will be an assertion.
2017-10-20 20:51:12 -04:00
Sebastian Nowicki
0d2354aca6 Wrap comments to 79 columns 2017-10-20 20:51:12 -04:00
Sebastian Nowicki
8dc513b5d2 Skip regression 210 test on APFS
APFS does not support creating filenames with invalid UTF-8 byte codes,
thus this test doesn't make sense. Skip it on file systems where this
shouldn't be possible.

Fixes #559
2017-10-20 20:51:12 -04:00
TJ Rana
a98156e71c Fix minor typos
Update name Mac OS X to macOS
2017-10-14 07:02:03 -04:00
Trent Davis
cf94072429 State the default case sensitivity 2017-10-12 20:02:33 -04:00
James Smith
db14046de4 Add purescript to built-in types
Purescript is a functional language that compiles to javascript (https://github.com/purescript/purescript)
2017-10-12 20:02:25 -04:00
dana
36091591f0 Add troubleshooting notes re: conflicting tools/aliases 2017-10-12 06:40:38 -04:00
Andrew Gallant
12ffcb4296 readme: clarify intro 2017-10-10 18:33:23 -04:00
Antti Keränen
e7c06b92fb Fix printing context after an early return from a search
Print the context if there's a context left to be printed after
returning early from a search (because of --max-count).

Fixes #402.
2017-10-08 08:10:35 -04:00
dana
353806b87a Type improvements (config, license, sh, systemd, &c.)
- Add `license` type for various copyright/licence files
- Add `systemd` type for systemd config/unit files
- Update existing `config`, `jinja`, `json`, `sh`, `sql`, `xml`, `yaml` types
- Minor formatting improvements
2017-10-08 08:05:28 -04:00
Omer Katz
aebb132a86 Addressed code reivew. 2017-10-08 08:03:00 -04:00
Omer Katz
ab4b6ab9c3 Ripgrep installs from Linuxbrew just fine and works as expected.
Mentioned it in the README file :)
2017-10-08 08:03:00 -04:00
Félix Cantournet
413178bc2c Add support for Dockerfiles filtering 2017-10-08 08:02:31 -04:00
dana
58fb4f987e Update README to be more explicit about precompiled binaries (fixes #618) 2017-10-08 08:02:19 -04:00
Benjamin Sago
4f1d6af296 globset README version bump 2017-10-08 08:01:50 -04:00
Daniel Vergeylen
6b79349f83 Rewording README
Trial to stay consistent with rest of the text.
Rewording by native english.
2017-10-08 08:01:29 -04:00
Daniel Vergeylen
f858828f61 Update README
Notify user `cargo install ripgrep` contains debug symbols and informs how to stripe them.
2017-10-08 08:01:29 -04:00
James McCoy
67b835fe2a Color --replace text using the match type
Closes #521
2017-10-08 08:01:11 -04:00
Tri Nguyen
214f2bef66 add support for terraform file type 2017-09-23 11:29:09 -04:00
Christof Marti
1136f8adab Avoid expensive check with --files (fixes #600) 2017-09-18 11:54:48 -04:00
Dan Fabulich
beb010d004 doc: clarify --with-filename behavior with --heading 2017-09-06 08:25:05 -04:00
Andrew Gallant
f9cbf7d3d4 tweak working 2017-09-04 11:15:14 -04:00
Philip Munksgaard
7eb1dd129e Add support for Standard ML file types 2017-09-04 07:26:47 -04:00
Alex Burka
a5f82e8826 ignore: add grouped toggle for standard filters 2017-09-02 12:28:59 -04:00
Jesse Claven
ca6bd648ab Add Elm file type. 2017-08-30 06:46:31 -04:00
Henri Sivonen
af77dd55a2 Update encoding_rs to 0.7.0 2017-08-28 08:14:33 -04:00
Jack O'Connor
3065a8c9c8 restore the default SIGPIPE behavior as a temporary workaround
See https://github.com/BurntSushi/ripgrep/issues/200.
2017-08-27 15:01:05 -04:00
Andrew Gallant
208c11af56 deps: bump termcolor in lock file 2017-08-27 11:34:58 -04:00
Andrew Gallant
12a78a992c termcolor-0.3.3 2017-08-27 11:05:55 -04:00
Andrew Gallant
d97c80be63 termcolor: make StandardStream be Send
This commit fixes a bug where the `StandardStream` type isn't `Send` on
Windows. This can cause some surprising compile breakage, and the only
motivation for it being non-Send was dubious. Namely, it was a result of
trying to eliminate code duplication.

This refactoring also eliminates at least one "unreachable" panic case
that was a result of trying to eliminate code reuse, so that's a nice
benefit as well.

Fixes #503
2017-08-27 11:05:02 -04:00
Andrew Gallant
5213bd30ea termcolor: 80 cols 2017-08-27 11:05:02 -04:00
Alex Burka
82d101907a ignore: document git_global enabled by default 2017-08-26 14:49:40 -04:00
Andrew Gallant
30608f2444 readme: update minimum version 2017-08-23 23:08:21 -04:00
Andrew Gallant
3d323928a0 update brew tap 2017-08-23 22:04:16 -04:00
25 changed files with 715 additions and 258 deletions

View File

@@ -1,3 +1,37 @@
0.7.0 (2017-10-20)
==================
This is a new minor version release of ripgrep that includes mostly bug fixes.
ripgrep continues to require Rust 1.17, and there are no known breaking changes
introduced in this release.
Feature enhancements:
* Added or improved file type filtering for config & license files, Elm,
Purescript, Standard ML, sh, systemd, Terraform
* [FEATURE #593](https://github.com/BurntSushi/ripgrep/pull/593):
Using both `-o/--only-matching` and `-r/--replace` does the right thing.
Bug fixes:
* [BUG #200](https://github.com/BurntSushi/ripgrep/issues/200):
ripgrep will stop when its pipe is closed.
* [BUG #402](https://github.com/BurntSushi/ripgrep/issues/402):
Fix context printing bug when the `-m/--max-count` flag is used.
* [BUG #521](https://github.com/BurntSushi/ripgrep/issues/521):
Fix interaction between `-r/--replace` and terminal colors.
* [BUG #559](https://github.com/BurntSushi/ripgrep/issues/559):
Ignore test that tried reading a non-UTF-8 file path on macOS.
* [BUG #599](https://github.com/BurntSushi/ripgrep/issues/599):
Fix color escapes on empty matches.
* [BUG #600](https://github.com/BurntSushi/ripgrep/issues/600):
Avoid expensive (on Windows) file handle check when using --files.
* [BUG #618](https://github.com/BurntSushi/ripgrep/issues/618):
Clarify installation instructions for Ubuntu users.
* [BUG #633](https://github.com/BurntSushi/ripgrep/issues/633):
Faster symlink loop checking on Windows.
0.6.0 (2017-08-23)
==================
This is a new minor version release of ripgrep that includes many bug fixes

153
Cargo.lock generated
View File

@@ -1,22 +1,23 @@
[root]
name = "ripgrep"
version = "0.6.0"
version = "0.7.0"
dependencies = [
"atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"bytecount 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding_rs 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding_rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"grep 0.1.6",
"ignore 0.2.2",
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"grep 0.1.7",
"ignore 0.3.0",
"lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.0.0 (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.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 0.3.2",
"same-file 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 0.3.3",
]
[[package]]
@@ -24,7 +25,7 @@ name = "aho-corasick"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -34,11 +35,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "atty"
version = "0.2.2"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -62,16 +64,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clap"
version = "2.26.0"
version = "2.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -83,7 +84,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "encoding_rs"
version = "0.6.11"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -109,43 +110,44 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "globset"
version = "0.2.0"
version = "0.2.1"
dependencies = [
"aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "grep"
version = "0.1.6"
version = "0.1.7"
dependencies = [
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ignore"
version = "0.2.2"
version = "0.3.0"
dependencies = [
"crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"globset 0.2.0",
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"globset 0.2.1",
"lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"same-file 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -159,12 +161,12 @@ dependencies = [
[[package]]
name = "lazy_static"
version = "0.2.8"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.29"
version = "0.2.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -174,10 +176,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memchr"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -187,16 +197,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num_cpus"
version = "1.6.2"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "redox_termios"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -205,7 +228,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"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.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"simd 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -219,7 +242,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "same-file"
version = "0.1.3"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -247,20 +270,30 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termcolor"
version = "0.3.2"
version = "0.3.3"
dependencies = [
"wincolor 0.1.4",
]
[[package]]
name = "termion"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "textwrap"
version = "0.7.0"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -272,15 +305,10 @@ name = "thread_local"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-segmentation"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-width"
version = "0.1.4"
@@ -311,12 +339,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "walkdir"
version = "1.0.7"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"same-file 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -340,38 +366,41 @@ dependencies = [
[metadata]
"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699"
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159"
"checksum atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21e50800ec991574876040fff8ee46b136a53e985286fbe6a3bdfe6421b78860"
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
"checksum bytecount 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "4bbeb7c30341fce29f6078b4bdf876ea4779600866e98f5b2d203a534f195050"
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
"checksum clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2267a8fdd4dce6956ba6649e130f62fb279026e5e84b92aa939ac8f85ce3f9f0"
"checksum clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3451e409013178663435d6f15fdb212f14ee4424a3d74f979d081d0a66b6f1f2"
"checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97"
"checksum encoding_rs 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e00a1b1e95eb46988805ceee6f34cd95c46a6753e290cb3ff0486931989d4a4c"
"checksum encoding_rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f5215aabf22b83153be3ee44dfe3f940214541b2ce13d419c55e7a115c8c51a9"
"checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
"checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
"checksum fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ab76cfd2aaa59b7bf6688ad9ba15bbae64bff97f04ea02144cfd3443e5c2866"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf"
"checksum libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "8a014d9226c2cc402676fbe9ea2e15dd5222cd1dd57f576b5b283178c944a264"
"checksum lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c9e5e58fa1a4c3b915a561a78a22ee0cac6ab97dca2504428bc1cb074375f8d5"
"checksum libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "56cce3130fd040c28df6f495c8492e5ec5808fb4c9093c310df02b0c8f030148"
"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b"
"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
"checksum memchr 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e01e64d9017d18e7fc09d8e4fe0e28ff6931019e979fb8019319db7ca827f8a6"
"checksum memmap 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46f3c7359028b31999287dae4e5047ddfe90a23b7dca2282ce759b491080c99b"
"checksum num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aec53c34f2d0247c5ca5d32cca1478762f301740468ee9ee6dcb7a0dd7a0c584"
"checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d"
"checksum redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "8dde11f18c108289bef24469638a04dce49da56084f2d50618b226e47eb04509"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b"
"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db"
"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
"checksum same-file 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "70a18720d745fb9ca6a041b37cb36d0b21066006b6cff8b5b360142d4b81fb60"
"checksum simd 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "63b5847c2d766ca7ce7227672850955802fabd779ba616aeabead4c2c3877023"
"checksum simd 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a94d14a2ae1f1f110937de5fb69e494372560181c7e1739a097fcc2cee37ba0"
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
"checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209"
"checksum textwrap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f728584ea33b0ad19318e20557cb0a39097751dbb07171419673502f848c7af6"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum textwrap 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8e08afc40ae3459e4838f303e465aa50d823df8d7f83ca88108f6d3afe7edd"
"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14"
"checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946"
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff"
"checksum walkdir 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b6d201f4f8998a837196b6de9c73e35af14c992cbb92c4ab641d2c2dce52de"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"

View File

@@ -1,6 +1,6 @@
[package]
name = "ripgrep"
version = "0.6.0" #:version
version = "0.7.0" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """
Line oriented search tool using Rust's regex library. Combines the raw
@@ -33,18 +33,19 @@ path = "tests/tests.rs"
atty = "0.2.2"
bytecount = "0.1.4"
clap = "2.26"
encoding_rs = "0.6"
encoding_rs = "0.7"
env_logger = { version = "0.4", default-features = false }
grep = { version = "0.1.5", path = "grep" }
ignore = { version = "0.2.2", path = "ignore" }
grep = { version = "0.1.7", path = "grep" }
ignore = { version = "0.3.0", path = "ignore" }
lazy_static = "0.2"
libc = "0.2"
log = "0.3"
memchr = "1"
memchr = "2"
memmap = "0.5"
num_cpus = "1"
regex = "0.2.1"
same-file = "0.1.1"
termcolor = { version = "0.3.0", path = "termcolor" }
same-file = "1"
termcolor = { version = "0.3.3", path = "termcolor" }
[build-dependencies]
clap = "2.26"
@@ -52,7 +53,11 @@ lazy_static = "0.2"
[features]
avx-accel = ["bytecount/avx-accel"]
simd-accel = ["bytecount/simd-accel", "regex/simd-accel", "encoding_rs/simd-accel"]
simd-accel = [
"bytecount/simd-accel",
"regex/simd-accel",
"encoding_rs/simd-accel",
]
[profile.release]
debug = true

View File

@@ -1,10 +1,10 @@
ripgrep (rg)
------------
`ripgrep` is a line oriented search tool that combines the usability of The
Silver Searcher (similar to `ack`) with the raw speed of GNU grep. `ripgrep`
works by recursively searching your current directory for a regex pattern.
`ripgrep` has first class support on Windows, Mac and Linux, with binary
downloads available for
`ripgrep` is a line oriented search tool that recursively searches your current
directory for a regex pattern while respecting your gitignore rules. To a first
approximation, ripgrep combines the usability of The Silver Searcher (similar
to `ack`) with the raw speed of GNU grep. `ripgrep` has first class support on
Windows, macOS and Linux, with binary downloads available for
[every release](https://github.com/BurntSushi/ripgrep/releases).
[![Linux build status](https://travis-ci.org/BurntSushi/ripgrep.svg?branch=master)](https://travis-ci.org/BurntSushi/ripgrep)
@@ -71,9 +71,9 @@ increases the times to `3.081s` for ripgrep and `11.403s` for GNU grep.
### Why should I use `ripgrep`?
* It can replace both The Silver Searcher and GNU grep because it is faster
than both. (N.B. It is not, strictly speaking, a "drop-in" replacement for
both, but the feature sets are far more similar than different.)
* It can replace both The Silver Searcher and GNU grep because it is generally
faster than both. (N.B. It is not, strictly speaking, a "drop-in" replacement
for both, but the feature sets are far more similar than different.)
* Like The Silver Searcher, `ripgrep` defaults to recursive directory search
and won't search files ignored by your `.gitignore` files. It also ignores
hidden and binary files by default. `ripgrep` also implements full support
@@ -118,7 +118,7 @@ multiline search, then `ripgrep` may not quite meet your needs (yet).
### Is it really faster than everything else?
Yes. A large number of benchmarks with detailed analysis for each is
Generally, yes. A large number of benchmarks with detailed analysis for each is
[available on my blog](http://blog.burntsushi.net/ripgrep/).
Summarizing, `ripgrep` is fast because:
@@ -146,15 +146,19 @@ Summarizing, `ripgrep` is fast because:
The binary name for `ripgrep` is `rg`.
[Binaries for `ripgrep` are available for Windows, Mac and
Linux.](https://github.com/BurntSushi/ripgrep/releases) Linux binaries are
static executables. Windows binaries are available either as built with MinGW
(GNU) or with Microsoft Visual C++ (MSVC). When possible, prefer MSVC over GNU,
but you'll need to have the
[Microsoft VC++ 2015 redistributable](https://www.microsoft.com/en-us/download/details.aspx?id=48145)
**[Archives of precompiled binaries for `ripgrep` are available for Windows,
macOS and Linux.](https://github.com/BurntSushi/ripgrep/releases)** Users of
platforms not explicitly mentioned below (such as Debian and Ubuntu) are advised
to download one of these archives.
Linux binaries are static executables. Windows binaries are available either as
built with MinGW (GNU) or with Microsoft Visual C++ (MSVC). When possible,
prefer MSVC over GNU, but you'll need to have the [Microsoft VC++ 2015
redistributable](https://www.microsoft.com/en-us/download/details.aspx?id=48145)
installed.
If you're a **Mac OS X Homebrew** user, then you can install ripgrep either
If you're a **macOS Homebrew** or a **Linuxbrew** user,
then you can install ripgrep either
from homebrew-core, (compiled with rust stable, no SIMD):
```
@@ -209,8 +213,12 @@ $ nix-env --install ripgrep
$ # (Or using the attribute name, which is also `ripgrep`.)
```
If you're a **Rust programmer**, `ripgrep` can be installed with `cargo`. Note
that this requires you to have **Rust 1.12 or newer** installed.
If you're a **Rust programmer**, `ripgrep` can be installed with `cargo`.
* Note that the minimum supported version of Rust for ripgrep is **1.17**,
although ripgrep may work with older versions.
* Note that the binary may be bigger than expected because it contains debug
symbols. This is intentional. To remove debug symbols and therefore reduce
the file size, run `strip` on the binary.
```
$ cargo install ripgrep
@@ -346,7 +354,7 @@ For **fish**, move `complete/rg.fish` to `$HOME/.config/fish/completions/`.
For **PowerShell**, add `. _rg.ps1` to your PowerShell
[profile](https://technet.microsoft.com/en-us/library/bb613488(v=vs.85).aspx)
(note the leading period). If the `_rg.ps1` file is not on your `PATH`, do
`. /path/to/_rg.ps1` instead.
`. /path/to/_rg.ps1` instead.
For **zsh**, move `complete/_rg` to one of your `$fpath` directories.
@@ -354,7 +362,7 @@ For **zsh**, move `complete/_rg` to one of your `$fpath` directories.
`ripgrep` is written in Rust, so you'll need to grab a
[Rust installation](https://www.rust-lang.org/) in order to compile it.
`ripgrep` compiles with Rust 1.12 (stable) or newer. Building is easy:
`ripgrep` compiles with Rust 1.17 (stable) or newer. Building is easy:
```
$ git clone https://github.com/BurntSushi/ripgrep
@@ -449,7 +457,7 @@ Example `$OutputEncoding` settings:
`$OutputEncoding = [System.Console]::OutputEncoding`
If you continue to have encoding problems, you can also force the encoding
that the console will use for printing to UTF-8 with
that the console will use for printing to UTF-8 with
`[System.Console]::OutputEncoding = [System.Text.Encoding]::UTF8`. This
will also reset when PowerShell is restarted, so you can add that line
to your profile as well if you want to make the setting permanent.
@@ -479,3 +487,26 @@ was later deprecated in
available [here][msys issue explanation].
[msys issue explanation]: https://github.com/BurntSushi/ripgrep/issues/281#issuecomment-269093893
#### When I run `rg` it executes some other command!
It's likely that you have a shell alias or even another tool called `rg` which
is interfering with `ripgrep` — run `which rg` to see what it is.
(Notably, the `rails` plug-in for
[Oh My Zsh](https://github.com/robbyrussell/oh-my-zsh/wiki/Plugins#rails) sets
up an `rg` alias for `rails generate`.)
Problems like this can be resolved in one of several ways:
* If you're using the OMZ `rails` plug-in, disable it by editing the `plugins`
array in your zsh configuration.
* Temporarily bypass an existing `rg` alias by calling `ripgrep` as
`command rg`, `\rg`, or `'rg'`.
* Temporarily bypass an existing alias or another tool named `rg` by calling
`ripgrep` by its full path (e.g., `/usr/bin/rg` or `/usr/local/bin/rg`).
* Permanently disable an existing `rg` alias by adding `unalias rg` to the
bottom of your shell configuration file (e.g., `.bash_profile` or `.zshrc`).
* Give `ripgrep` its own alias that doesn't conflict with other tools/aliases by
adding a line like the following to the bottom of your shell configuration
file: `alias ripgrep='command rg'`

View File

@@ -80,7 +80,7 @@ _rg() {
'*'{-u,--unrestricted}'[reduce level of "smart" searching]'
'(: -)'{-V,--version}'[display version information]'
'(-p --heading --no-heading --pretty)--vimgrep[show results in vim-compatible format]'
'(-H --no-filename --with-filename)'{-H,--with-filename}'[prefix each match with name of file that contains it]'
'(-H --no-filename --with-filename)'{-H,--with-filename}'[display the file name for matches]'
'(-w -x --line-regexp --word-regexp)'{-w,--word-regexp}'[only show matches surrounded by word boundaries]'
'(-e -f --file --files --regexp --type-list)1: :_rg_pattern'
'(--type-list)*:file:_files'

View File

@@ -274,8 +274,11 @@ Only show path of each file with no matches.
.RE
.TP
.B \-H, \-\-with\-filename
Prefix each match with the file name that contains it.
Display the file name for matches.
This is the default when more than one file is searched.
If \-\-heading is enabled, the file name will be shown above clusters of
matches from each file; otherwise, the file name will be shown on each
match.
.RS
.RE
.TP
@@ -445,8 +448,8 @@ rg\ \[aq]^.*([0\-9]{3}\-[0\-9]{3}\-[0\-9]{4}).*$\[aq]\ \-\-replace\ \[aq]$1\[aq]
.RE
.TP
.B \-s, \-\-case\-sensitive
Search case sensitively.
This overrides \-\-ignore\-case and \-\-smart\-case.
Search case sensitively (default).
Overrides \-\-ignore\-case and \-\-smart\-case.
.RS
.RE
.TP

View File

@@ -182,8 +182,10 @@ Project home page: https://github.com/BurntSushi/ripgrep
: Only show path of each file with no matches.
-H, --with-filename
: Prefix each match with the file name that contains it. This is the
default when more than one file is searched.
: Display the file name for matches. This is the default when
more than one file is searched. If --heading is enabled, the
file name will be shown above clusters of matches from each
file; otherwise, the file name will be shown on each match.
--no-filename
: Never show the filename for a match. This is the default when
@@ -293,7 +295,7 @@ Project home page: https://github.com/BurntSushi/ripgrep
rg '^.*([0-9]{3}-[0-9]{3}-[0-9]{4}).*$' --replace '$1'
-s, --case-sensitive
: Search case sensitively. This overrides --ignore-case and --smart-case.
: Search case sensitively (default). Overrides --ignore-case and --smart-case.
-S, --smart-case
: Search case insensitively if the pattern is all lowercase.

View File

@@ -1,6 +1,6 @@
[package]
name = "globset"
version = "0.2.0" #:version
version = "0.2.1" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """
Cross platform single glob and glob set matching. Glob set matching is the
@@ -22,7 +22,7 @@ bench = false
aho-corasick = "0.6.0"
fnv = "1.0"
log = "0.3"
memchr = "1"
memchr = "2"
regex = "0.2.1"
[dev-dependencies]

View File

@@ -20,7 +20,7 @@ Add this to your `Cargo.toml`:
```toml
[dependencies]
globset = "0.1"
globset = "0.2"
```
and this to your crate root:

View File

@@ -1,6 +1,6 @@
[package]
name = "grep"
version = "0.1.6" #:version
version = "0.1.7" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """
Fast line oriented regex searching as a library.
@@ -14,6 +14,6 @@ license = "Unlicense/MIT"
[dependencies]
log = "0.3"
memchr = "1"
memchr = "2"
regex = "0.2.1"
regex-syntax = "0.4.0"

View File

@@ -1,6 +1,6 @@
[package]
name = "ignore"
version = "0.2.2" #:version
version = "0.3.0" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """
A fast library for efficiently matching ignore files such as `.gitignore`
@@ -19,13 +19,14 @@ bench = false
[dependencies]
crossbeam = "0.2"
globset = { version = "0.2.0", path = "../globset" }
globset = { version = "0.2.1", path = "../globset" }
lazy_static = "0.2"
log = "0.3"
memchr = "1"
memchr = "2"
regex = "0.2.1"
same-file = "1"
thread_local = "0.3.2"
walkdir = "1.0.7"
walkdir = "2"
[dev-dependencies]
tempdir = "0.3.5"

View File

@@ -21,6 +21,7 @@ use std::sync::{Arc, RwLock};
use gitignore::{self, Gitignore, GitignoreBuilder};
use pathutil::{is_hidden, strip_prefix};
use overrides::{self, Override};
use same_file::Handle;
use types::{self, Types};
use {Error, Match, PartialErrorBuilder};
@@ -95,6 +96,9 @@ struct IgnoreInner {
compiled: Arc<RwLock<HashMap<OsString, Ignore>>>,
/// The path to the directory that this matcher was built from.
dir: PathBuf,
/// An open handle to the directory, for checking symlink loops in the
/// parallel iterator.
handle: Arc<Option<Handle>>,
/// An override matcher (default is empty).
overrides: Arc<Override>,
/// A file type matcher.
@@ -127,11 +131,15 @@ struct IgnoreInner {
impl Ignore {
/// Return the directory path of this matcher.
#[allow(dead_code)]
pub fn path(&self) -> &Path {
&self.0.dir
}
/// Return a handle to the directory of this matcher.
pub fn handle(&self) -> Option<&Handle> {
(*self.0.handle).as_ref()
}
/// Return true if this matcher has no parent.
pub fn is_root(&self) -> bool {
self.0.parent.is_none()
@@ -238,9 +246,17 @@ impl Ignore {
errs.maybe_push(err);
m
};
let handle = match Handle::from_path(dir) {
Ok(handle) => Some(handle),
Err(err) => {
errs.push(Error::from(err).with_path(dir));
None
}
};
let ig = IgnoreInner {
compiled: self.0.compiled.clone(),
dir: dir.to_path_buf(),
handle: Arc::new(handle),
overrides: self.0.overrides.clone(),
types: self.0.types.clone(),
parent: Some(self.clone()),
@@ -451,9 +467,14 @@ impl IgnoreBuilder {
}
gi
};
let handle = match Handle::from_path(&self.dir) {
Ok(handle) => Some(handle),
Err(_) => None,
};
Ignore(Arc::new(IgnoreInner {
compiled: Arc::new(RwLock::new(HashMap::new())),
dir: self.dir.clone(),
handle: Arc::new(handle),
overrides: self.overrides.clone(),
types: self.types.clone(),
parent: None,

View File

@@ -54,6 +54,7 @@ extern crate lazy_static;
extern crate log;
extern crate memchr;
extern crate regex;
extern crate same_file;
#[cfg(test)]
extern crate tempdir;
extern crate thread_local;
@@ -198,6 +199,29 @@ impl Error {
}
errline.with_path(path)
}
/// Build an error from a walkdir error.
fn from_walkdir(err: walkdir::Error) -> Error {
let depth = err.depth();
if let (Some(anc), Some(child)) = (err.loop_ancestor(), err.path()) {
return Error::WithDepth {
depth: depth,
err: Box::new(Error::Loop {
ancestor: anc.to_path_buf(),
child: child.to_path_buf(),
}),
};
}
let path = err.path().map(|p| p.to_path_buf());
let mut ig_err = Error::Io(io::Error::from(err));
if let Some(path) = path {
ig_err = Error::WithPath {
path: path,
err: Box::new(ig_err),
};
}
ig_err
}
}
impl error::Error for Error {
@@ -258,30 +282,6 @@ impl From<io::Error> for Error {
}
}
impl From<walkdir::Error> for Error {
fn from(err: walkdir::Error) -> Error {
let depth = err.depth();
if let (Some(anc), Some(child)) = (err.loop_ancestor(), err.path()) {
return Error::WithDepth {
depth: depth,
err: Box::new(Error::Loop {
ancestor: anc.to_path_buf(),
child: child.to_path_buf(),
}),
};
}
let path = err.path().map(|p| p.to_path_buf());
let mut ig_err = Error::Io(io::Error::from(err));
if let Some(path) = path {
ig_err = Error::WithPath {
path: path,
err: Box::new(ig_err),
};
}
ig_err
}
}
#[derive(Debug, Default)]
struct PartialErrorBuilder(Vec<Error>);

View File

@@ -110,7 +110,7 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
("cmake", &["*.cmake", "CMakeLists.txt"]),
("coffeescript", &["*.coffee"]),
("creole", &["*.creole"]),
("config", &["*.config"]),
("config", &["*.cfg", "*.conf", "*.config", "*.ini"]),
("cpp", &[
"*.C", "*.cc", "*.cpp", "*.cxx",
"*.h", "*.H", "*.hh", "*.hpp", "*.inl",
@@ -123,8 +123,10 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
("cython", &["*.pyx"]),
("dart", &["*.dart"]),
("d", &["*.d"]),
("docker", &["*Dockerfile*"]),
("elisp", &["*.el"]),
("elixir", &["*.ex", "*.eex", "*.exs"]),
("elm", &["*.elm"]),
("erlang", &["*.erl", "*.hrl"]),
("fish", &["*.fish"]),
("fortran", &[
@@ -139,27 +141,60 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
("haskell", &["*.hs", "*.lhs"]),
("html", &["*.htm", "*.html", "*.ejs"]),
("java", &["*.java"]),
("jinja", &["*.jinja", "*.jinja2"]),
("jinja", &["*.j2", "*.jinja", "*.jinja2"]),
("js", &[
"*.js", "*.jsx", "*.vue",
]),
("json", &["*.json"]),
("json", &["*.json", "composer.lock"]),
("jsonl", &["*.jsonl"]),
("julia", &["*.jl"]),
("jl", &["*.jl"]),
("kotlin", &["*.kt", "*.kts"]),
("less", &["*.less"]),
("license", &[
// General
"COPYING", "COPYING[.-]*",
"COPYRIGHT", "COPYRIGHT[.-]*",
"EULA", "EULA[.-]*",
"licen[cs]e", "licen[cs]e.*",
"LICEN[CS]E", "LICEN[CS]E[.-]*", "*[.-]LICEN[CS]E*",
"NOTICE", "NOTICE[.-]*",
"PATENTS", "PATENTS[.-]*",
"UNLICEN[CS]E", "UNLICEN[CS]E[.-]*",
// GPL (gpl.txt, etc.)
"agpl[.-]*",
"gpl[.-]*",
"lgpl[.-]*",
// Other license-specific (APACHE-2.0.txt, etc.)
"AGPL-*[0-9]*",
"APACHE-*[0-9]*",
"BSD-*[0-9]*",
"CC-BY-*",
"GFDL-*[0-9]*",
"GNU-*[0-9]*",
"GPL-*[0-9]*",
"LGPL-*[0-9]*",
"MIT-*[0-9]*",
"MPL-*[0-9]*",
"OFL-*[0-9]*",
]),
("lisp", &["*.el", "*.jl", "*.lisp", "*.lsp", "*.sc", "*.scm"]),
("log", &["*.log"]),
("lua", &["*.lua"]),
("m4", &["*.ac", "*.m4"]),
("make", &["gnumakefile", "Gnumakefile", "GNUmakefile", "makefile", "Makefile", "*.mk", "*.mak"]),
("make", &[
"gnumakefile", "Gnumakefile", "GNUmakefile",
"makefile", "Makefile",
"*.mk", "*.mak"
]),
("markdown", &["*.markdown", "*.md", "*.mdown", "*.mkdn"]),
("md", &["*.markdown", "*.md", "*.mdown", "*.mkdn"]),
("matlab", &["*.m"]),
("mk", &["mkfile"]),
("ml", &["*.ml"]),
("msbuild", &["*.csproj", "*.fsproj", "*.vcxproj", "*.proj", "*.props", "*.targets"]),
("msbuild", &[
"*.csproj", "*.fsproj", "*.vcxproj", "*.proj", "*.props", "*.targets"
]),
("nim", &["*.nim"]),
("nix", &["*.nix"]),
("objc", &["*.h", "*.m"]),
@@ -171,6 +206,7 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
("php", &["*.php", "*.php3", "*.php4", "*.php5", "*.phtml"]),
("pod", &["*.pod"]),
("ps", &["*.cdxml", "*.ps1", "*.ps1xml", "*.psd1", "*.psm1"]),
("purs", &["*.purs"]),
("py", &["*.py"]),
("qmake", &["*.pro", "*.pri", "*.prf"]),
("readme", &["README*", "*README"]),
@@ -181,18 +217,47 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
("rust", &["*.rs"]),
("sass", &["*.sass", "*.scss"]),
("scala", &["*.scala"]),
("sh", &["*.bash", "*.csh", "*.ksh", "*.sh", "*.tcsh"]),
("sh", &[
// Portable/misc. init files
".login", ".logout", ".profile", "profile",
// bash-specific init files
".bash_login", "bash_login",
".bash_logout", "bash_logout",
".bash_profile", "bash_profile",
".bashrc", "bashrc", "*.bashrc",
// csh-specific init files
".cshrc", "*.cshrc",
// ksh-specific init files
".kshrc", "*.kshrc",
// tcsh-specific init files
".tcshrc",
// zsh-specific init files
".zshenv", "zshenv",
".zlogin", "zlogin",
".zlogout", "zlogout",
".zprofile", "zprofile",
".zshrc", "zshrc",
// Extensions
"*.bash", "*.csh", "*.ksh", "*.sh", "*.tcsh", "*.zsh",
]),
("sml", &["*.sml", "*.sig"]),
("spark", &["*.spark"]),
("sql", &["*.sql", "*.psql"]),
("stylus", &["*.styl"]),
("sql", &["*.sql"]),
("sv", &["*.v", "*.vg", "*.sv", "*.svh", "*.h"]),
("svg", &["*.svg"]),
("swift", &["*.swift"]),
("swig", &["*.def", "*.i"]),
("systemd", &[
"*.automount", "*.conf", "*.device", "*.link", "*.mount", "*.path",
"*.scope", "*.service", "*.slice", "*.socket", "*.swap", "*.target",
"*.timer",
]),
("taskpaper", &["*.taskpaper"]),
("tcl", &["*.tcl"]),
("tex", &["*.tex", "*.ltx", "*.cls", "*.sty", "*.bib"]),
("textile", &["*.textile"]),
("tf", &["*.tf"]),
("ts", &["*.ts", "*.tsx"]),
("txt", &["*.txt"]),
("toml", &["*.toml", "Cargo.lock"]),
@@ -202,10 +267,17 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
("vim", &["*.vim"]),
("vimscript", &["*.vim"]),
("wiki", &["*.mediawiki", "*.wiki"]),
("xml", &["*.xml"]),
("xml", &["*.xml", "*.xml.dist"]),
("yacc", &["*.y"]),
("yaml", &["*.yaml", "*.yml"]),
("zsh", &["zshenv", ".zshenv", "zprofile", ".zprofile", "zshrc", ".zshrc", "zlogin", ".zlogin", "zlogout", ".zlogout", "*.zsh"]),
("yaml", &["*.yaml", "*.yml", "yarn.lock"]),
("zsh", &[
".zshenv", "zshenv",
".zlogin", "zlogin",
".zlogout", "zlogout",
".zprofile", "zprofile",
".zshrc", "zshrc",
"*.zsh",
]),
];
/// Glob represents a single glob in a set of file type definitions.

View File

@@ -1,5 +1,5 @@
use std::cmp;
use std::ffi::{OsStr, OsString};
use std::ffi::OsStr;
use std::fmt;
use std::fs::{self, FileType, Metadata};
use std::io;
@@ -11,7 +11,8 @@ use std::time::Duration;
use std::vec;
use crossbeam::sync::MsQueue;
use walkdir::{self, WalkDir, WalkDirIterator, is_same_file};
use same_file::Handle;
use walkdir::{self, WalkDir};
use dir::{Ignore, IgnoreBuilder};
use gitignore::GitignoreBuilder;
@@ -36,8 +37,8 @@ impl DirEntry {
}
/// Whether this entry corresponds to a symbolic link or not.
pub fn path_is_symbolic_link(&self) -> bool {
self.dent.path_is_symbolic_link()
pub fn path_is_symlink(&self) -> bool {
self.dent.path_is_symlink()
}
/// Returns true if and only if this entry corresponds to stdin.
@@ -137,12 +138,12 @@ impl DirEntryInner {
}
}
fn path_is_symbolic_link(&self) -> bool {
fn path_is_symlink(&self) -> bool {
use self::DirEntryInner::*;
match *self {
Stdin => false,
Walkdir(ref x) => x.path_is_symbolic_link(),
Raw(ref x) => x.path_is_symbolic_link(),
Walkdir(ref x) => x.path_is_symlink(),
Raw(ref x) => x.path_is_symlink(),
}
}
@@ -199,6 +200,7 @@ impl DirEntryInner {
#[cfg(unix)]
fn ino(&self) -> Option<u64> {
use walkdir::DirEntryExt;
use self::DirEntryInner::*;
match *self {
Stdin => None,
@@ -244,7 +246,7 @@ impl DirEntryRaw {
&self.path
}
fn path_is_symbolic_link(&self) -> bool {
fn path_is_symlink(&self) -> bool {
self.ty.is_symlink() || self.follow_link
}
@@ -404,7 +406,9 @@ pub struct WalkBuilder {
max_depth: Option<usize>,
max_filesize: Option<u64>,
follow_links: bool,
sorter: Option<Arc<Fn(&OsString, &OsString) -> cmp::Ordering + 'static>>,
sorter: Option<Arc<
Fn(&OsStr, &OsStr) -> cmp::Ordering + Send + Sync + 'static
>>,
threads: usize,
}
@@ -458,7 +462,9 @@ impl WalkBuilder {
}
if let Some(ref cmp) = cmp {
let cmp = cmp.clone();
wd = wd.sort_by(move |a, b| cmp(a, b));
wd = wd.sort_by(move |a, b| {
cmp(a.file_name(), b.file_name())
});
}
(p.to_path_buf(), Some(WalkEventIter::from(wd)))
}
@@ -571,6 +577,29 @@ impl WalkBuilder {
self
}
/// Enables all the standard ignore filters.
///
/// This toggles, as a group, all the filters that are enabled by default:
///
/// - [hidden()](#method.hidden)
/// - [parents()](#method.parents)
/// - [ignore()](#method.ignore)
/// - [git_ignore()](#method.git_ignore)
/// - [git_global()](#method.git_global)
/// - [git_exclude()](#method.git_exclude)
///
/// They may still be toggled individually after calling this function.
///
/// This is (by definition) enabled by default.
pub fn standard_filters(&mut self, yes: bool) -> &mut WalkBuilder {
self.hidden(yes)
.parents(yes)
.ignore(yes)
.git_ignore(yes)
.git_global(yes)
.git_exclude(yes)
}
/// Enables ignoring hidden files.
///
/// This is enabled by default.
@@ -610,6 +639,8 @@ impl WalkBuilder {
/// does not exist or does not specify `core.excludesFile`, then
/// `$XDG_CONFIG_HOME/git/ignore` is read. If `$XDG_CONFIG_HOME` is not
/// set or is empty, then `$HOME/.config/git/ignore` is used instead.
///
/// This is enabled by default.
pub fn git_global(&mut self, yes: bool) -> &mut WalkBuilder {
self.ig_builder.git_global(yes);
self
@@ -637,7 +668,7 @@ impl WalkBuilder {
self
}
/// Set a function for sorting directory entries.
/// Set a function for sorting directory entries by file name.
///
/// If a compare function is set, the resulting iterator will return all
/// paths in sorted order. The compare function will be called to compare
@@ -645,8 +676,9 @@ impl WalkBuilder {
/// entry.
///
/// Note that this is not used in the parallel iterator.
pub fn sort_by<F>(&mut self, cmp: F) -> &mut WalkBuilder
where F: Fn(&OsString, &OsString) -> cmp::Ordering + 'static {
pub fn sort_by_file_name<F>(&mut self, cmp: F) -> &mut WalkBuilder
where F: Fn(&OsStr, &OsStr) -> cmp::Ordering + Send + Sync + 'static
{
self.sorter = Some(Arc::new(cmp));
self
}
@@ -727,7 +759,7 @@ impl Iterator for Walk {
};
match ev {
Err(err) => {
return Some(Err(Error::from(err)));
return Some(Err(Error::from_walkdir(err)));
}
Ok(WalkEvent::Exit) => {
self.ig = self.ig.parent().unwrap();
@@ -763,7 +795,7 @@ impl Iterator for Walk {
/// the entire contents of a directory have been enumerated.
struct WalkEventIter {
depth: usize,
it: walkdir::Iter,
it: walkdir::IntoIter,
next: Option<Result<walkdir::DirEntry, walkdir::Error>>,
}
@@ -1276,11 +1308,11 @@ fn check_symlink_loop(
child_path: &Path,
child_depth: usize,
) -> Result<(), Error> {
let hchild = Handle::from_path(child_path).map_err(|err| {
Error::from(err).with_path(child_path).with_depth(child_depth)
})?;
for ig in ig_parent.parents().take_while(|ig| !ig.is_absolute_parent()) {
let same = try!(is_same_file(ig.path(), child_path).map_err(|err| {
Error::from(err).with_path(child_path).with_depth(child_depth)
}));
if same {
if ig.handle().map_or(true, |parent| parent == &hchild) {
return Err(Error::Loop {
ancestor: ig.path().to_path_buf(),
child: child_path.to_path_buf(),

View File

@@ -1,9 +1,9 @@
class RipgrepBin < Formula
version '0.5.2'
version '0.6.0'
desc "Search tool like grep and The Silver Searcher."
homepage "https://github.com/BurntSushi/ripgrep"
url "https://github.com/BurntSushi/ripgrep/releases/download/#{version}/ripgrep-#{version}-x86_64-apple-darwin.tar.gz"
sha256 "a0326a84af8517ad707d8c7cccba6e112de27822c391cc0937e4727fbb6c48f4"
sha256 "2aeffe25322f886bcd846ac15b6574dc769865fb44b28a9b0c356f3004019685"
conflicts_with "ripgrep"

View File

@@ -162,7 +162,7 @@ pub fn app() -> App<'static, 'static> {
.arg(flag("no-ignore-parent"))
.arg(flag("no-ignore-vcs"))
.arg(flag("null").short("0"))
.arg(flag("only-matching").short("o").conflicts_with("replace"))
.arg(flag("only-matching").short("o"))
.arg(flag("path-separator").value_name("SEPARATOR").takes_value(true))
.arg(flag("pretty").short("p"))
.arg(flag("replace").short("r")
@@ -398,8 +398,10 @@ lazy_static! {
"Only show the paths that contains zero matches.");
doc!(h, "with-filename",
"Show file name for each match.",
"Prefix each match with the file name that contains it. This is \
the default when more than one file is searched.");
"Display the file name for matches. This is the default when \
more than one file is searched. If --heading is enabled, the \
file name will be shown above clusters of matches from each \
file; otherwise, the file name will be shown on each match.");
doc!(h, "no-filename",
"Never show the file name for a match.",
"Never show the file name for a match. This is the default when \
@@ -509,7 +511,7 @@ lazy_static! {
is 10M. \n\nThe argument accepts the same size suffixes as \
allowed in the 'max-filesize' argument.");
doc!(h, "case-sensitive",
"Search case sensitively.",
"Search case sensitively (default).",
"Search case sensitively. This overrides -i/--ignore-case and \
-S/--smart-case.");
doc!(h, "smart-case",

View File

@@ -287,7 +287,7 @@ impl Args {
wd.parents(!self.no_ignore_parent);
wd.threads(self.threads());
if self.sort_files {
wd.sort_by(|a, b| a.cmp(b));
wd.sort_by_file_name(|a, b| a.cmp(b));
}
wd
}

View File

@@ -54,6 +54,7 @@ mod worker;
pub type Result<T> = result::Result<T, Box<Error + Send + Sync>>;
fn main() {
reset_sigpipe();
match Args::parse().map(Arc::new).and_then(run) {
Ok(0) => process::exit(1),
Ok(_) => process::exit(0),
@@ -107,6 +108,7 @@ fn run_parallel(args: Arc<Args>) -> Result<u64> {
let dent = match get_or_log_dir_entry(
result,
args.stdout_handle(),
args.files(),
args.no_messages(),
) {
None => return Continue,
@@ -153,6 +155,7 @@ fn run_one_thread(args: Arc<Args>) -> Result<u64> {
let dent = match get_or_log_dir_entry(
result,
args.stdout_handle(),
args.files(),
args.no_messages(),
) {
None => continue,
@@ -205,6 +208,7 @@ fn run_files_parallel(args: Arc<Args>) -> Result<u64> {
if let Some(dent) = get_or_log_dir_entry(
result,
args.stdout_handle(),
args.files(),
args.no_messages(),
) {
tx.send(dent).unwrap();
@@ -223,6 +227,7 @@ fn run_files_one_thread(args: Arc<Args>) -> Result<u64> {
let dent = match get_or_log_dir_entry(
result,
args.stdout_handle(),
args.files(),
args.no_messages(),
) {
None => continue,
@@ -250,6 +255,7 @@ fn run_types(args: Arc<Args>) -> Result<u64> {
fn get_or_log_dir_entry(
result: result::Result<ignore::DirEntry, ignore::Error>,
stdout_handle: Option<&same_file::Handle>,
files_only: bool,
no_messages: bool,
) -> Option<ignore::DirEntry> {
match result {
@@ -278,7 +284,7 @@ fn get_or_log_dir_entry(
}
// If we are redirecting stdout to a file, then don't search that
// file.
if is_stdout_file(&dent, stdout_handle, no_messages) {
if !files_only && is_stdout_file(&dent, stdout_handle, no_messages) {
return None;
}
Some(dent)
@@ -329,3 +335,22 @@ fn eprint_nothing_searched() {
applied a filter you didn't expect. \
Try running again with --debug.");
}
// The Rust standard library suppresses the default SIGPIPE behavior, so that
// writing to a closed pipe doesn't kill the process. The goal is to instead
// handle errors through the normal result mechanism. Ripgrep needs some
// refactoring before it will be able to do that, however, so we re-enable the
// standard SIGPIPE behavior as a workaround. See
// https://github.com/BurntSushi/ripgrep/issues/200.
#[cfg(unix)]
fn reset_sigpipe() {
extern crate libc;
unsafe {
libc::signal(libc::SIGPIPE, libc::SIG_DFL);
}
}
#[cfg(not(unix))]
fn reset_sigpipe() {
// no-op
}

View File

@@ -3,29 +3,58 @@ use std::fmt;
use std::path::Path;
use std::str::FromStr;
use regex::bytes::{Captures, Regex, Replacer};
use regex::bytes::{Captures, Match, Regex, Replacer};
use termcolor::{Color, ColorSpec, ParseColorError, WriteColor};
use pathutil::strip_prefix;
use ignore::types::FileTypeDef;
/// Track the start and end of replacements to allow coloring them on output.
#[derive(Debug)]
struct Offset {
start: usize,
end: usize,
}
impl Offset {
fn new(start: usize, end: usize) -> Offset {
Offset { start: start, end: end }
}
}
impl<'m, 'r> From<&'m Match<'r>> for Offset {
fn from(m: &'m Match<'r>) -> Self {
Offset{ start: m.start(), end: m.end() }
}
}
/// CountingReplacer implements the Replacer interface for Regex,
/// and counts how often replacement is being performed.
struct CountingReplacer<'r> {
replace: &'r [u8],
count: &'r mut usize,
offsets: &'r mut Vec<Offset>,
}
impl<'r> CountingReplacer<'r> {
fn new(replace: &'r [u8], count: &'r mut usize) -> CountingReplacer<'r> {
CountingReplacer { replace: replace, count: count }
fn new(
replace: &'r [u8],
count: &'r mut usize,
offsets: &'r mut Vec<Offset>,
) -> CountingReplacer<'r> {
CountingReplacer { replace: replace, count: count, offsets: offsets, }
}
}
impl<'r> Replacer for CountingReplacer<'r> {
fn replace_append(&mut self, caps: &Captures, dst: &mut Vec<u8>) {
*self.count += 1;
let start = dst.len();
caps.expand(self.replace, dst);
let end = dst.len();
if start != end {
self.offsets.push(Offset::new(start, end));
}
}
}
@@ -283,10 +312,16 @@ impl<W: WriteColor> Printer<W> {
}
if self.replace.is_some() {
let mut count = 0;
let mut offsets = Vec::new();
let line = {
let replacer = CountingReplacer::new(
self.replace.as_ref().unwrap(), &mut count);
re.replace_all(&buf[start..end], replacer)
self.replace.as_ref().unwrap(), &mut count, &mut offsets);
if self.only_matching {
re.replace_all(
&buf[start + match_start..start + match_end], replacer)
} else {
re.replace_all(&buf[start..end], replacer)
}
};
if self.max_columns.map_or(false, |m| line.len() > m) {
let msg = format!(
@@ -295,44 +330,45 @@ impl<W: WriteColor> Printer<W> {
self.write_eol();
return;
}
self.write(&line);
if line.last() != Some(&self.eol) {
self.write_eol();
}
self.write_matched_line(offsets, &*line, false);
} else {
if self.only_matching {
let buf = &buf[start + match_start..start + match_end];
self.write_matched_line(re, buf, true);
let buf = if self.only_matching {
&buf[start + match_start..start + match_end]
} else {
self.write_matched_line(re, &buf[start..end], false);
&buf[start..end]
};
if self.max_columns.map_or(false, |m| buf.len() > m) {
let count = re.find_iter(buf).count();
let msg = format!("[Omitted long line with {} matches]", count);
self.write_colored(msg.as_bytes(), |colors| colors.matched());
self.write_eol();
return;
}
let only_match = self.only_matching;
self.write_matched_line(
re.find_iter(buf).map(|x| Offset::from(&x)), buf, only_match);
}
}
fn write_matched_line(
&mut self,
re: &Regex,
buf: &[u8],
only_match: bool,
) {
if self.max_columns.map_or(false, |m| buf.len() > m) {
let count = re.find_iter(buf).count();
let msg = format!("[Omitted long line with {} matches]", count);
self.write_colored(msg.as_bytes(), |colors| colors.matched());
self.write_eol();
return;
}
fn write_matched_line<I>(&mut self, offsets: I, buf: &[u8], only_match: bool)
where I: IntoIterator<Item=Offset>,
{
if !self.wtr.supports_color() || self.colors.matched().is_none() {
self.write(buf);
} else if only_match {
self.write_colored(buf, |colors| colors.matched());
} else {
let mut last_written = 0;
for m in re.find_iter(buf) {
self.write(&buf[last_written..m.start()]);
self.write_colored(
&buf[m.start()..m.end()], |colors| colors.matched());
last_written = m.end();
for o in offsets {
self.write(&buf[last_written..o.start]);
// This conditional checks if the match is both empty *and*
// past the end of the line. In this case, we never want to
// emit an additional color escape.
if o.start != o.end || o.end != buf.len() {
self.write_colored(
&buf[o.start..o.end], |colors| colors.matched());
}
last_written = o.end;
}
self.write(&buf[last_written..]);
}
@@ -443,7 +479,7 @@ impl<W: WriteColor> Printer<W> {
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) );
let _ = self.wtr.set_color(get_color(&self.colors));
self.write(buf);
let _ = self.wtr.reset();
}

View File

@@ -299,6 +299,15 @@ impl<'a, R: io::Read, W: WriteColor> Searcher<'a, R, W> {
}
}
}
if self.after_context_remaining > 0 {
if self.last_printed == self.inp.lastnl {
try!(self.fill());
}
let upto = self.inp.lastnl;
if upto > 0 {
self.print_after_context(upto);
}
}
if self.match_count > 0 {
if self.opts.count {
self.printer.path_count(self.path, self.match_count);
@@ -1247,6 +1256,23 @@ fn main() {
");
}
#[test]
fn after_context_invert_one_max_count_two() {
let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| {
s.line_number(true)
.invert_match(true)
.after_context(1)
.max_count(Some(2))
});
assert_eq!(2, count);
assert_eq!(out, "\
/baz.rs:2:Holmeses, success in the province of detective work must always
/baz.rs-3-be, to a very large extent, the result of luck. Sherlock Holmes
/baz.rs:4:can extract a clew from a wisp of straw or a flake of cigar ash;
/baz.rs-5-but Doctor Watson has to have it taken out for him and dusted,
");
}
#[test]
fn after_context_two1() {
let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| {
@@ -1290,6 +1316,23 @@ fn main() {
");
}
#[test]
fn after_context_two_max_count_two() {
let (count, out) = search_smallcap(
"Doctor", SHERLOCK, |s| {
s.line_number(true).after_context(2).max_count(Some(2))
});
assert_eq!(2, count);
assert_eq!(out, "\
/baz.rs:1:For the Doctor Watsons of this world, as opposed to the Sherlock
/baz.rs-2-Holmeses, success in the province of detective work must always
/baz.rs-3-be, to a very large extent, the result of luck. Sherlock Holmes
--
/baz.rs:5:but Doctor Watson has to have it taken out for him and dusted,
/baz.rs-6-and exhibited clearly, with a label attached.
");
}
#[test]
fn after_context_three1() {
let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| {

View File

@@ -1,6 +1,6 @@
[package]
name = "termcolor"
version = "0.3.2" #:version
version = "0.3.3" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """
A simple cross platform library for writing colored text to a terminal.

View File

@@ -202,15 +202,23 @@ enum IoStandardStream {
impl IoStandardStream {
fn new(sty: StandardStreamType) -> IoStandardStream {
match sty {
StandardStreamType::Stdout => IoStandardStream::Stdout(io::stdout()),
StandardStreamType::Stderr => IoStandardStream::Stderr(io::stderr()),
StandardStreamType::Stdout => {
IoStandardStream::Stdout(io::stdout())
}
StandardStreamType::Stderr => {
IoStandardStream::Stderr(io::stderr())
}
}
}
fn lock(&self) -> IoStandardStreamLock {
match *self {
IoStandardStream::Stdout(ref s) => IoStandardStreamLock::StdoutLock(s.lock()),
IoStandardStream::Stderr(ref s) => IoStandardStreamLock::StderrLock(s.lock()),
IoStandardStream::Stdout(ref s) => {
IoStandardStreamLock::StdoutLock(s.lock())
}
IoStandardStream::Stderr(ref s) => {
IoStandardStreamLock::StderrLock(s.lock())
}
}
}
}
@@ -231,7 +239,7 @@ impl io::Write for IoStandardStream {
}
}
/// Same rigamorale for the locked variants of the standard streams.
/// Same rigmarole for the locked variants of the standard streams.
enum IoStandardStreamLock<'a> {
StdoutLock(io::StdoutLock<'a>),
@@ -257,7 +265,7 @@ impl<'a> io::Write for IoStandardStreamLock<'a> {
/// Satisfies `io::Write` and `WriteColor`, and supports optional coloring
/// to either of the standard output streams, stdout and stderr.
pub struct StandardStream {
wtr: LossyStandardStream<WriterInner<'static, IoStandardStream>>,
wtr: LossyStandardStream<WriterInner<IoStandardStream>>,
}
/// `StandardStreamLock` is a locked reference to a `StandardStream`.
@@ -265,26 +273,34 @@ pub struct StandardStream {
/// This implements the `io::Write` and `WriteColor` traits, and is constructed
/// via the `Write::lock` method.
///
/// The lifetime `'a` refers to the lifetime of the corresponding `StandardStream`.
/// The lifetime `'a` refers to the lifetime of the corresponding
/// `StandardStream`.
pub struct StandardStreamLock<'a> {
wtr: LossyStandardStream<WriterInner<'a, IoStandardStreamLock<'a>>>,
wtr: LossyStandardStream<WriterInnerLock<'a, IoStandardStreamLock<'a>>>,
}
/// WriterInner is a (limited) generic representation of a writer. It is
/// limited because W should only ever be stdout/stderr on Windows.
enum WriterInner<'a, W> {
enum WriterInner<W> {
NoColor(NoColor<W>),
Ansi(Ansi<W>),
#[cfg(windows)]
Windows { wtr: W, console: Mutex<wincolor::Console> },
}
/// WriterInnerLock is a (limited) generic representation of a writer. It is
/// limited because W should only ever be stdout/stderr on Windows.
enum WriterInnerLock<'a, W> {
NoColor(NoColor<W>),
Ansi(Ansi<W>),
/// What a gross hack. On Windows, we need to specify a lifetime for the
/// console when in a locked state, but obviously don't need to do that
/// on Unix, which make the `'a` unused. To satisfy the compiler, we need
/// on Unix, which makes the `'a` unused. To satisfy the compiler, we need
/// a PhantomData.
#[allow(dead_code)]
Unreachable(::std::marker::PhantomData<&'a ()>),
#[cfg(windows)]
Windows { wtr: W, console: Mutex<wincolor::Console> },
#[cfg(windows)]
WindowsLocked { wtr: W, console: MutexGuard<'a, wincolor::Console> },
Windows { wtr: W, console: MutexGuard<'a, wincolor::Console> },
}
impl StandardStream {
@@ -332,7 +348,9 @@ impl StandardStream {
} else {
WriterInner::NoColor(NoColor(IoStandardStream::new(sty)))
};
StandardStream { wtr: LossyStandardStream::new(wtr).is_console(is_win_console) }
StandardStream {
wtr: LossyStandardStream::new(wtr).is_console(is_win_console),
}
}
/// Create a new `StandardStream` with the given color preferences that
@@ -375,12 +393,11 @@ impl<'a> StandardStreamLock<'a> {
#[cfg(not(windows))]
fn from_stream(stream: &StandardStream) -> StandardStreamLock {
let locked = match *stream.wtr.get_ref() {
WriterInner::Unreachable(_) => unreachable!(),
WriterInner::NoColor(ref w) => {
WriterInner::NoColor(NoColor(w.0.lock()))
WriterInnerLock::NoColor(NoColor(w.0.lock()))
}
WriterInner::Ansi(ref w) => {
WriterInner::Ansi(Ansi(w.0.lock()))
WriterInnerLock::Ansi(Ansi(w.0.lock()))
}
};
StandardStreamLock { wtr: stream.wtr.wrap(locked) }
@@ -389,24 +406,19 @@ impl<'a> StandardStreamLock<'a> {
#[cfg(windows)]
fn from_stream(stream: &StandardStream) -> StandardStreamLock {
let locked = match *stream.wtr.get_ref() {
WriterInner::Unreachable(_) => unreachable!(),
WriterInner::NoColor(ref w) => {
WriterInner::NoColor(NoColor(w.0.lock()))
WriterInnerLock::NoColor(NoColor(w.0.lock()))
}
WriterInner::Ansi(ref w) => {
WriterInner::Ansi(Ansi(w.0.lock()))
WriterInnerLock::Ansi(Ansi(w.0.lock()))
}
#[cfg(windows)]
WriterInner::Windows { ref wtr, ref console } => {
WriterInner::WindowsLocked {
WriterInnerLock::Windows {
wtr: wtr.lock(),
console: console.lock().unwrap(),
}
}
#[cfg(windows)]
WriterInner::WindowsLocked{..} => {
panic!("cannot call StandardStream.lock while a StandardStreamLock is alive");
}
};
StandardStreamLock { wtr: stream.wtr.wrap(locked) }
}
@@ -438,48 +450,38 @@ impl<'a> WriteColor for StandardStreamLock<'a> {
fn reset(&mut self) -> io::Result<()> { self.wtr.reset() }
}
impl<'a, W: io::Write> io::Write for WriterInner<'a, W> {
impl<W: io::Write> io::Write for WriterInner<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
match *self {
WriterInner::Unreachable(_) => unreachable!(),
WriterInner::NoColor(ref mut wtr) => wtr.write(buf),
WriterInner::Ansi(ref mut wtr) => wtr.write(buf),
#[cfg(windows)]
WriterInner::Windows { ref mut wtr, .. } => wtr.write(buf),
#[cfg(windows)]
WriterInner::WindowsLocked { ref mut wtr, .. } => wtr.write(buf),
}
}
fn flush(&mut self) -> io::Result<()> {
match *self {
WriterInner::Unreachable(_) => unreachable!(),
WriterInner::NoColor(ref mut wtr) => wtr.flush(),
WriterInner::Ansi(ref mut wtr) => wtr.flush(),
#[cfg(windows)]
WriterInner::Windows { ref mut wtr, .. } => wtr.flush(),
#[cfg(windows)]
WriterInner::WindowsLocked { ref mut wtr, .. } => wtr.flush(),
}
}
}
impl<'a, W: io::Write> WriteColor for WriterInner<'a, W> {
impl<W: io::Write> WriteColor for WriterInner<W> {
fn supports_color(&self) -> bool {
match *self {
WriterInner::Unreachable(_) => unreachable!(),
WriterInner::NoColor(_) => false,
WriterInner::Ansi(_) => true,
#[cfg(windows)]
WriterInner::Windows { .. } => true,
#[cfg(windows)]
WriterInner::WindowsLocked { .. } => true,
}
}
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
match *self {
WriterInner::Unreachable(_) => unreachable!(),
WriterInner::NoColor(ref mut wtr) => wtr.set_color(spec),
WriterInner::Ansi(ref mut wtr) => wtr.set_color(spec),
#[cfg(windows)]
@@ -488,17 +490,11 @@ impl<'a, W: io::Write> WriteColor for WriterInner<'a, W> {
let mut console = console.lock().unwrap();
spec.write_console(&mut *console)
}
#[cfg(windows)]
WriterInner::WindowsLocked { ref mut wtr, ref mut console } => {
try!(wtr.flush());
spec.write_console(console)
}
}
}
fn reset(&mut self) -> io::Result<()> {
match *self {
WriterInner::Unreachable(_) => unreachable!(),
WriterInner::NoColor(ref mut wtr) => wtr.reset(),
WriterInner::Ansi(ref mut wtr) => wtr.reset(),
#[cfg(windows)]
@@ -507,8 +503,63 @@ impl<'a, W: io::Write> WriteColor for WriterInner<'a, W> {
try!(console.lock().unwrap().reset());
Ok(())
}
}
}
}
impl<'a, W: io::Write> io::Write for WriterInnerLock<'a, W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
match *self {
WriterInnerLock::Unreachable(_) => unreachable!(),
WriterInnerLock::NoColor(ref mut wtr) => wtr.write(buf),
WriterInnerLock::Ansi(ref mut wtr) => wtr.write(buf),
#[cfg(windows)]
WriterInner::WindowsLocked { ref mut wtr, ref mut console } => {
WriterInnerLock::Windows { ref mut wtr, .. } => wtr.write(buf),
}
}
fn flush(&mut self) -> io::Result<()> {
match *self {
WriterInnerLock::Unreachable(_) => unreachable!(),
WriterInnerLock::NoColor(ref mut wtr) => wtr.flush(),
WriterInnerLock::Ansi(ref mut wtr) => wtr.flush(),
#[cfg(windows)]
WriterInnerLock::Windows { ref mut wtr, .. } => wtr.flush(),
}
}
}
impl<'a, W: io::Write> WriteColor for WriterInnerLock<'a, W> {
fn supports_color(&self) -> bool {
match *self {
WriterInnerLock::Unreachable(_) => unreachable!(),
WriterInnerLock::NoColor(_) => false,
WriterInnerLock::Ansi(_) => true,
#[cfg(windows)]
WriterInnerLock::Windows { .. } => true,
}
}
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
match *self {
WriterInnerLock::Unreachable(_) => unreachable!(),
WriterInnerLock::NoColor(ref mut wtr) => wtr.set_color(spec),
WriterInnerLock::Ansi(ref mut wtr) => wtr.set_color(spec),
#[cfg(windows)]
WriterInnerLock::Windows { ref mut wtr, ref mut console } => {
try!(wtr.flush());
spec.write_console(console)
}
}
}
fn reset(&mut self) -> io::Result<()> {
match *self {
WriterInnerLock::Unreachable(_) => unreachable!(),
WriterInnerLock::NoColor(ref mut wtr) => wtr.reset(),
WriterInnerLock::Ansi(ref mut wtr) => wtr.reset(),
#[cfg(windows)]
WriterInnerLock::Windows { ref mut wtr, ref mut console } => {
try!(wtr.flush());
try!(console.reset());
Ok(())
@@ -565,7 +616,8 @@ impl BufferWriter {
StandardStreamType::Stdout => wincolor::Console::stdout(),
StandardStreamType::Stderr => wincolor::Console::stderr(),
}.ok().map(Mutex::new);
let stream = LossyStandardStream::new(IoStandardStream::new(sty)).is_console(con.is_some());
let stream = LossyStandardStream::new(IoStandardStream::new(sty))
.is_console(con.is_some());
BufferWriter {
stream: stream,
printed: AtomicBool::new(false),
@@ -1253,7 +1305,9 @@ struct LossyStandardStream<W> {
impl<W: io::Write> LossyStandardStream<W> {
#[cfg(not(windows))]
fn new(wtr: W) -> LossyStandardStream<W> { LossyStandardStream { wtr: wtr } }
fn new(wtr: W) -> LossyStandardStream<W> {
LossyStandardStream { wtr: wtr }
}
#[cfg(windows)]
fn new(wtr: W) -> LossyStandardStream<W> {
@@ -1320,3 +1374,15 @@ fn write_lossy_utf8<W: io::Write>(mut w: W, buf: &[u8]) -> io::Result<usize> {
Err(e) => w.write(&buf[..e.valid_up_to()]),
}
}
#[cfg(test)]
mod tests {
use super::StandardStream;
fn assert_is_send<T: Send>() {}
#[test]
fn standard_stream_is_send() {
assert_is_send::<StandardStream>();
}
}

View File

@@ -266,6 +266,20 @@ but Watson, Doctor has to have it taken out for him and dusted,
assert_eq!(lines, expected);
});
sherlock!(replace_with_only_matching, "of (\\w+)",
|wd: WorkDir, mut cmd: Command| {
cmd.arg("-o").arg("-r").arg("$1");
let lines: String = wd.stdout(&mut cmd);
let expected = "\
this
detective
luck
straw
cigar
";
assert_eq!(lines, expected);
});
sherlock!(file_types, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
wd.create("file.py", "Sherlock");
wd.create("file.rs", "Sherlock");
@@ -1014,12 +1028,15 @@ fn regression_210() {
let badutf8 = OsStr::from_bytes(&b"foo\xffbar"[..]);
let wd = WorkDir::new("regression_210");
let mut cmd = wd.command();
wd.create(badutf8, "test");
cmd.arg("-H").arg("test").arg(badutf8);
// APFS does not support creating files with invalid UTF-8 bytes.
// https://github.com/BurntSushi/ripgrep/issues/559
if wd.try_create(badutf8, "test").is_ok() {
let mut cmd = wd.command();
cmd.arg("-H").arg("test").arg(badutf8);
let out = wd.output(&mut cmd);
assert_eq!(out.stdout, b"foo\xffbar:test\n".to_vec());
let out = wd.output(&mut cmd);
assert_eq!(out.stdout, b"foo\xffbar:test\n".to_vec());
}
}
// See: https://github.com/BurntSushi/ripgrep/issues/228
@@ -1129,6 +1146,29 @@ clean!(regression_493, " 're ", "input.txt", |wd: WorkDir, mut cmd: Command| {
assert_eq!(lines, " 're \n");
});
// See: https://github.com/BurntSushi/ripgrep/issues/599
clean!(regression_599, "^$", "input.txt", |wd: WorkDir, mut cmd: Command| {
wd.create("input.txt", "\n\ntest\n");
cmd.args(&[
"--color", "ansi",
"--colors", "path:none",
"--colors", "line:none",
"--colors", "match:fg:red",
"--colors", "match:style:nobold",
"--line-number",
]);
let lines: String = wd.stdout(&mut cmd);
// Technically, the expected output should only be two lines, but:
// https://github.com/BurntSushi/ripgrep/issues/441
let expected = "\
1:
2:
4:
";
assert_eq!(expected, lines);
});
// See: https://github.com/BurntSushi/ripgrep/issues/1
clean!(feature_1_sjis, "Шерлок Холмс", ".", |wd: WorkDir, mut cmd: Command| {
let sherlock =

View File

@@ -41,11 +41,19 @@ impl WorkDir {
}
}
/// Create a new file with the given name and contents in this directory.
/// Create a new file with the given name and contents in this directory,
/// or panic on error.
pub fn create<P: AsRef<Path>>(&self, name: P, contents: &str) {
self.create_bytes(name, contents.as_bytes());
}
/// Try to create a new file with the given name and contents in this
/// directory.
pub fn try_create<P: AsRef<Path>>(&self, name: P, contents: &str) -> io::Result<()> {
let path = self.dir.join(name);
self.try_create_bytes(path, contents.as_bytes())
}
/// Create a new file with the given name and size.
pub fn create_size<P: AsRef<Path>>(&self, name: P, filesize: u64) {
let path = self.dir.join(name);
@@ -53,12 +61,19 @@ impl WorkDir {
nice_err(&path, file.set_len(filesize));
}
/// Create a new file with the given name and contents in this directory.
/// Create a new file with the given name and contents in this directory,
/// or panic on error.
pub fn create_bytes<P: AsRef<Path>>(&self, name: P, contents: &[u8]) {
let path = self.dir.join(name);
let mut file = nice_err(&path, File::create(&path));
nice_err(&path, file.write_all(contents));
nice_err(&path, file.flush());
nice_err(&path, self.try_create_bytes(&path, contents));
}
/// Try to create a new file with the given name and contents in this
/// directory.
fn try_create_bytes<P: AsRef<Path>>(&self, path: P, contents: &[u8]) -> io::Result<()> {
let mut file = File::create(&path)?;
file.write_all(contents)?;
file.flush()
}
/// Remove a file with the given name from this directory.