Compare commits

..

31 Commits

Author SHA1 Message Date
Andrew Gallant
c8e9f25b85 ci: fix macOS asciidoc installation 2018-02-20 21:05:40 -05:00
Andrew Gallant
9305f89f39 ci: fix man page generation on macOS 2018-02-20 20:55:12 -05:00
Andrew Gallant
9c216ad9a4 release: 0.8.1 2018-02-20 20:19:03 -05:00
Andrew Gallant
6862e07870 changelog: 0.8.1 2018-02-20 20:18:01 -05:00
Andrew Gallant
a6d09b2d42 deps: update to clap 2.30.0 2018-02-20 20:16:57 -05:00
Andrew Gallant
ab1b877c20 termcolor: release 0.3.5 2018-02-20 20:15:08 -05:00
Andrew Gallant
2b5c488814 ignore: release 0.4.1 2018-02-20 20:13:56 -05:00
Andrew Gallant
cb47be938e ci: build man page on ARM cross-compile
This fixes a bug where ripgrep's man page wasn't generated in the ARM
cross-compile build. Mostly, this should just require installing
asciidoc and making sure we test that it actually works.

Fixes #791
2018-02-20 20:05:55 -05:00
Andrew Gallant
fe9be658f4 doc: omit revision when it isn't available
If the revision is empty, then we shouldn't show the `(rev )` text in
the output of `rg --version`.

Fixes #789
2018-02-20 20:05:55 -05:00
Andrew Gallant
8c800adab7 doc: clarify failure mode
This adds a hint for end users that run into a common failure mode where
ripgrep won't search any files because they have a `*` rule in their
`$HOME/.gitignore`.

Fixes #815
2018-02-20 20:05:55 -05:00
Andrew Gallant
d65966efbc ignore: fix performance regression on Windows
This commit fixes a performance regression in Windows that resulted from
fallout from fixing #705. In particular, we introduced an additional
stat call for every single directory entry, which can be quite
disastrous for performance.

There is a corresponding companion PR that fixes the same bug in
walkdir: https://github.com/BurntSushi/walkdir/pull/96

Fixes #820
2018-02-20 19:50:52 -05:00
Markus Westerlind
597bf04a56 termcolor: add ?Sized bound for &mut T impl 2018-02-20 07:13:37 -05:00
Balaji Sivaraman
c78ab9e669 termcolor: improve "intense" docs
Fixes #797
2018-02-20 07:11:25 -05:00
Balaji Sivaraman
d57fc58081 termcolor: add underline support
This commit adds underline support to the termcolor crate, and
exposes it through ripgrep.

Fixes #798
2018-02-20 07:10:03 -05:00
Andrew Gallant
d09538c974 doc: clarify Debian/Ubuntu install instructions
Thanks @x4121 for the tip!
2018-02-20 07:02:08 -05:00
David Peter
94768881e1 doc: fix typo in Debian install instructions 2018-02-20 06:59:21 -05:00
Andrey Kolomoets
f3a9ced82c types: add csv 2018-02-19 20:59:15 -05:00
Andrew Gallant
18f549d289 ignore: fix symlink following on Windows
This commit fixes a bug where symlinks were always being followed on
Windows, even if the user did not request it. This only impacts the
parallel iterator.

This is a regression from the fallout of fixing #705.

Fixes #824
2018-02-19 20:52:37 -05:00
Cosmin Lehene
c749b604dc doc: clarify --ignore-file flag
Fixes #684
2018-02-18 17:53:10 -05:00
Andrew Gallant
d6748a3445 doc: add .deb installation instructions
Generating a Debian binary package was pretty easy using `cargo deb`, so
it is now part of the release. This commit updates the README's
installation methods to reference it.

I did look into setting up a PPA for Ubuntu, but my eyes glazed over while
reading the documentation. Providing a binary Debian package is likely a
faux pas, but it is extraordinarily convenient.
2018-02-18 10:32:53 -05:00
Uwe Dauernheim
9b7f420faa doc: fix files-with-matches typo 2018-02-17 08:24:31 -05:00
Andrew Gallant
361698b90a ignore: fix improper hidden filtering
This commit fixes a bug where `rg --hidden .` would behave differently
with respect to ignore filtering than `rg --hidden ./`. In particular,
this was due to a bug where the directory name `.` caused the leading
`.` in a hidden directory to get stripped, which in turn caused the
ignore rules to fail.

Fixes #807
2018-02-14 18:16:38 -05:00
David Peter
b71a110ccf ignore: fix custom ignore name bug
This commit fixes a bug in the handling of custom gitignore file names.
Previously, the directory walker would check for whether there were any
ignore rules present, but this check didn't incorporate the custom gitignore
rules. At a high level, this permits custom gitignore names to be used
even if no other source of gitignore rules is used.

Fixes #800
2018-02-14 06:53:26 -05:00
unsignedint
5c1af3c25d types: add VHDL 2018-02-13 07:32:16 -05:00
Keith Devens
ad3f55b0e5 doc: the year is 2018 2018-02-12 18:30:02 -05:00
Andrew Gallant
b8e6d50bbe doc: add "grep replacement" question to FAQ
I am tired of being throwing "but ripgrep is marketed as a grep
replacement" in my face. Let's answer it once and for all.
2018-02-12 17:57:14 -05:00
KARASZI István
81afe8c5a0 doc: fix typo 2018-02-12 07:16:10 -05:00
Andrew Gallant
c4e0d4bd7b pkg: update brew tap to 0.8.0, take 2 2018-02-11 20:39:12 -05:00
Andrew Gallant
23d1b91ead release: 0.8.0 2018-02-11 20:22:22 -05:00
Andrew Gallant
ac83ed4992 pkg: update brew tap to 0.8.0 2018-02-11 20:19:25 -05:00
Andrew Gallant
555fbd1201 pkg: delete Archlinux PKGBUILD
Other people are maintaining it and it has bitrotted anyway.
2018-02-11 20:18:56 -05:00
24 changed files with 345 additions and 119 deletions

View File

@@ -30,7 +30,8 @@ matrix:
env: TARGET=x86_64-unknown-linux-musl env: TARGET=x86_64-unknown-linux-musl
- os: osx - os: osx
rust: nightly rust: nightly
env: TARGET=x86_64-apple-darwin # XML_CATALOG_FILES is apparently necessary for asciidoc on macOS.
env: TARGET=x86_64-apple-darwin XML_CATALOG_FILES=/usr/local/etc/xml/catalog
- os: linux - os: linux
rust: nightly rust: nightly
env: TARGET=arm-unknown-linux-gnueabihf GCC_VERSION=4.8 env: TARGET=arm-unknown-linux-gnueabihf GCC_VERSION=4.8
@@ -41,6 +42,12 @@ matrix:
- binutils-arm-linux-gnueabihf - binutils-arm-linux-gnueabihf
- libc6-armhf-cross - libc6-armhf-cross
- libc6-dev-armhf-cross - libc6-dev-armhf-cross
# For generating man page.
- libxslt1-dev
- asciidoc
- docbook-xsl
- xsltproc
- libxml2-utils
# Beta channel. We enable these to make sure there are no regressions in # Beta channel. We enable these to make sure there are no regressions in
# Rust beta releases. # Rust beta releases.
- os: linux - os: linux
@@ -67,6 +74,12 @@ matrix:
- binutils-arm-linux-gnueabihf - binutils-arm-linux-gnueabihf
- libc6-armhf-cross - libc6-armhf-cross
- libc6-dev-armhf-cross - libc6-dev-armhf-cross
# For generating man page.
- libxslt1-dev
- asciidoc
- docbook-xsl
- xsltproc
- libxml2-utils
install: ci/install.sh install: ci/install.sh
script: ci/script.sh script: ci/script.sh
before_deploy: ci/before_deploy.sh before_deploy: ci/before_deploy.sh

View File

@@ -1,4 +1,40 @@
0.8.0 (2017-02-11) 0.8.1 (2018-02-20)
==================
This is a patch release of ripgrep that primarily fixes regressions introduced
in 0.8.0 (#820 and #824) in directory traversal on Windows. These regressions
do not impact non-Windows users.
Feature enhancements:
* Added or improved file type filtering for csv and VHDL.
* [FEATURE #798](https://github.com/BurntSushi/ripgrep/issues/798):
Add `underline` support to `termcolor` and ripgrep. See documentation on the
`--colors` flag for details.
Bug fixes:
* [BUG #684](https://github.com/BurntSushi/ripgrep/issues/684):
Improve documentation for the `--ignore-file` flag.
* [BUG #789](https://github.com/BurntSushi/ripgrep/issues/789):
Don't show `(rev )` if the revision wasn't available during the build.
* [BUG #791](https://github.com/BurntSushi/ripgrep/issues/791):
Add man page to ARM release.
* [BUG #797](https://github.com/BurntSushi/ripgrep/issues/797):
Improve documentation for "intense" setting in `termcolor`.
* [BUG #800](https://github.com/BurntSushi/ripgrep/issues/800):
Fix a bug in the `ignore` crate for custom ignore files. This had no impact
on ripgrep.
* [BUG #807](https://github.com/BurntSushi/ripgrep/issues/807):
Fix a bug where `rg --hidden .` behaved differently from `rg --hidden ./`.
* [BUG #815](https://github.com/BurntSushi/ripgrep/issues/815):
Clarify a common failure mode in user guide.
* [BUG #820](https://github.com/BurntSushi/ripgrep/issues/820):
Fixes a bug on Windows where symlinks were followed even if not requested.
* [BUG #824](https://github.com/BurntSushi/ripgrep/issues/824):
Fix a performance regression in directory traversal on Windows.
0.8.0 (2018-02-11)
================== ==================
This is a new minor version releae of ripgrep that satisfies several popular This is a new minor version releae of ripgrep that satisfies several popular
feature requests (config files, search compressed files, true colors), fixes feature requests (config files, search compressed files, true colors), fixes
@@ -47,7 +83,7 @@ Feature enhancements:
Add extended or "true" color support. Works in Windows 10! Add extended or "true" color support. Works in Windows 10!
[See the FAQ for details.](FAQ.md#colors) [See the FAQ for details.](FAQ.md#colors)
* [FEATURE #539](https://github.com/BurntSushi/ripgrep/issues/539): * [FEATURE #539](https://github.com/BurntSushi/ripgrep/issues/539):
Search gzip, bsip2, lzma or xz files when given `-z/--search-zip` flag. Search gzip, bzip2, lzma or xz files when given `-z/--search-zip` flag.
* [FEATURE #544](https://github.com/BurntSushi/ripgrep/issues/544): * [FEATURE #544](https://github.com/BurntSushi/ripgrep/issues/544):
Add support for line number alignment via a new `--line-number-width` flag. Add support for line number alignment via a new `--line-number-width` flag.
* [FEATURE #654](https://github.com/BurntSushi/ripgrep/pull/654): * [FEATURE #654](https://github.com/BurntSushi/ripgrep/pull/654):

22
Cargo.lock generated
View File

@@ -41,7 +41,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "clap" name = "clap"
version = "2.29.4" version = "2.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -114,7 +114,7 @@ dependencies = [
[[package]] [[package]]
name = "ignore" name = "ignore"
version = "0.4.0" version = "0.4.1"
dependencies = [ dependencies = [
"crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"globset 0.3.0", "globset 0.3.0",
@@ -125,7 +125,7 @@ dependencies = [
"same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -225,15 +225,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "ripgrep" name = "ripgrep"
version = "0.7.1" version = "0.8.1"
dependencies = [ dependencies = [
"atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"bytecount 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "bytecount 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.29.4 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding_rs 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "encoding_rs 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"globset 0.3.0", "globset 0.3.0",
"grep 0.1.8", "grep 0.1.8",
"ignore 0.4.0", "ignore 0.4.1",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -242,7 +242,7 @@ dependencies = [
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 0.3.4", "termcolor 0.3.5",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -274,7 +274,7 @@ dependencies = [
[[package]] [[package]]
name = "termcolor" name = "termcolor"
version = "0.3.4" version = "0.3.5"
dependencies = [ dependencies = [
"wincolor 0.1.6", "wincolor 0.1.6",
] ]
@@ -331,7 +331,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "walkdir" name = "walkdir"
version = "2.1.3" version = "2.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -371,7 +371,7 @@ dependencies = [
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
"checksum bytecount 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "882585cd7ec84e902472df34a5e01891202db3bf62614e1f0afe459c1afcf744" "checksum bytecount 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "882585cd7ec84e902472df34a5e01891202db3bf62614e1f0afe459c1afcf744"
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
"checksum clap 2.29.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7b8f59bcebcfe4269b09f71dab0da15b355c75916a8f975d3876ce81561893ee" "checksum clap 2.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1c07b9257a00f3fc93b7f3c417fc15607ec7a56823bc2c37ec744e266387de5b"
"checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19"
"checksum encoding_rs 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98fd0f24d1fb71a4a6b9330c8ca04cbd4e7cc5d846b54ca74ff376bc7c9f798d" "checksum encoding_rs 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98fd0f24d1fb71a4a6b9330c8ca04cbd4e7cc5d846b54ca74ff376bc7c9f798d"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
@@ -401,7 +401,7 @@ dependencies = [
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum walkdir 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b167e9a4420d8dddb260e70c90a4a375a1e5691f21f70e715553da87b6c2503a" "checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369"
"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" "checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "ripgrep" name = "ripgrep"
version = "0.7.1" #:version version = "0.8.1" #: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

72
FAQ.md
View File

@@ -20,6 +20,7 @@
* [How do I create an alias for ripgrep on Windows?](#rg-alias-windows) * [How do I create an alias for ripgrep on Windows?](#rg-alias-windows)
* [How do I create a PowerShell profile?](#powershell-profile) * [How do I create a PowerShell profile?](#powershell-profile)
* [How do I pipe non-ASCII content to ripgrep on Windows?](#pipe-non-ascii-windows) * [How do I pipe non-ASCII content to ripgrep on Windows?](#pipe-non-ascii-windows)
* [Can ripgrep replace grep?](#posix4ever)
<h3 name="config"> <h3 name="config">
@@ -189,10 +190,10 @@ The --colors` flag is a bit more complicated. The general format is:
* `{attribute}` should be one of `fg`, `bg` or `style`, corresponding to * `{attribute}` should be one of `fg`, `bg` or `style`, corresponding to
foreground color, background color, or miscellaneous styling (such as whether foreground color, background color, or miscellaneous styling (such as whether
to bold the output or not). to bold the output or not).
* `{value}` is determined by the value of `{attribute}`. If `{attribute}` is * `{value}` is determined by the value of `{attribute}`. If
`style`, then `{value}` should be one of `nobold`, `bold`, `nointense` or `{attribute}` is `style`, then `{value}` should be one of `nobold`,
`intense`. If `{attribute}` is `fg` or `bg`, then `{value}` should be a `bold`, `nointense`, `intense`, `nounderline` or `underline`. If
color. `{attribute}` is `fg` or `bg`, then `{value}` should be a color.
A color is specified by either one of eight of English names, a single 256-bit A color is specified by either one of eight of English names, a single 256-bit
number or an RGB triple (with over 16 million possible values, or "true number or an RGB triple (with over 16 million possible values, or "true
@@ -466,3 +467,66 @@ that the console will use for printing to UTF-8 with
`[System.Console]::OutputEncoding = [System.Text.Encoding]::UTF8`. This `[System.Console]::OutputEncoding = [System.Text.Encoding]::UTF8`. This
will also reset when PowerShell is restarted, so you can add that line 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. to your profile as well if you want to make the setting permanent.
<h3 name="posix4ever">
Can ripgrep replace grep?
</h3>
Yes and no.
If, upon hearing that "ripgrep can replace grep," you *actually* hear, "ripgrep
can be used in every instance grep can be used, in exactly the same way, for
the same use cases, with exactly the same bug-for-bug behavior," then no,
ripgrep trivially *cannot* replace grep. Moreover, ripgrep will *never* replace
grep.
If, upon hearing that "ripgrep can replace grep," you *actually* hear, "ripgrep
can replace grep in some cases and not in other use cases," then yes, that is
indeed true!
Let's go over some of those use cases in favor of ripgrep. Some of these may
not apply to you. That's OK. There may be other use cases not listed here that
do apply to you. That's OK too.
(For all claims related to performance in the following words, see my
[blog post](https://blog.burntsushi.net/ripgrep/)
introducing ripgrep.)
* Are you frequently searching a repository of code? If so, ripgrep might be a
good choice since there's likely a good chunk of your repository that you
don't want to search. grep, can, of course, be made to filter files using
recursive search, and if you don't mind writing out the requisite `--exclude`
rules or writing wrapper scripts, then grep might be sufficient. (I'm not
kidding, I myself did this with grep for almost a decade before writing
ripgrep.) But if you instead enjoy having a search tool respect your
`.gitignore`, then ripgrep might be perfect for you!
* Are you frequently searching non-ASCII text that is UTF-8 encoded? One of
ripgrep's key features is that it can handle Unicode features in your
patterns in a way that tends to be faster than GNU grep. Unicode features
in ripgrep are enabled by default; there is no need to configure your locale
settings to use ripgrep properly because ripgrep doesn't respect your locale
settings.
* Do you need to search UTF-16 files and you don't want to bother explicitly
transcoding them? Great. ripgrep does this for you automatically. No need
to enable it.
* Do you need to search a large directory of large files? ripgrep uses
parallelism by default, which tends to make it faster than a standard
`grep -r` search. However, if you're OK writing the occasional
`find ./ -print0 | xargs -P8 -0 grep` command, then maybe grep is good
enough.
Here are some cases where you might *not* want to use ripgrep. The same caveats
for the previous section apply.
* Are you writing portable shell scripts intended to work in a variety of
environments? Great, probably not a good idea to use ripgrep! ripgrep is has
nowhere near the ubquity of grep, so if you do use ripgrep, you might need
to futz with the installation process more than you would with grep.
* Do you care about POSIX compatibility? If so, then you can't use ripgrep
because it never was, isn't and never will be POSIX compatible.
* Do you hate tools that try to do something smart? If so, ripgrep is all about
being smart, so you might prefer to just stick with grep.
* Is there a particular feature of grep you rely on that ripgrep either doesn't
have or never will have? If the former, file a bug report, maybe ripgrep can
do it! If the latter, well, then, just use grep.

View File

@@ -58,6 +58,10 @@ $ rg fast README.md
129: optimizations to make searching very fast. 129: optimizations to make searching very fast.
``` ```
(**Note:** If you see an error message from ripgrep saying that it didn't
search any files, then re-run ripgrep with the `--debug` flag. One likely cause
of this is that you have a `*` rule in a `$HOME/.gitignore` file.)
So what happened here? ripgrep read the contents of `README.md`, and for each So what happened here? ripgrep read the contents of `README.md`, and for each
line that contained `fast`, ripgrep printed it to your terminal. ripgrep also line that contained `fast`, ripgrep printed it to your terminal. ripgrep also
included the line number for each line by default. If your terminal supports included the line number for each line by default. If your terminal supports

View File

@@ -85,9 +85,9 @@ increases the times to `2.640s` for ripgrep and `10.277s` for GNU grep.
### Why should I use ripgrep? ### Why should I use ripgrep?
* It can replace both The Silver Searcher and GNU grep because it is generally * It can replace many use cases served by both The Silver Searcher and GNU grep
faster than both. (N.B. It is not, strictly speaking, a "drop-in" replacement because it is generally faster than both. (See [the FAQ](FAQ.md#posix4ever)
for both, but the feature sets are far more similar than different.) for more details on whether ripgrep can truly replace grep.)
* Like The Silver Searcher, ripgrep defaults to recursive directory search * Like The Silver Searcher, ripgrep defaults to recursive directory search
and won't search files ignored by your `.gitignore` files. It also ignores and won't search files ignored by your `.gitignore` files. It also ignores
hidden and binary files by default. ripgrep also implements full support hidden and binary files by default. ripgrep also implements full support
@@ -172,8 +172,8 @@ The binary name for ripgrep is `rg`.
**[Archives of precompiled binaries for ripgrep are available for Windows, **[Archives of precompiled binaries for ripgrep are available for Windows,
macOS and Linux.](https://github.com/BurntSushi/ripgrep/releases)** Users of macOS and Linux.](https://github.com/BurntSushi/ripgrep/releases)** Users of
platforms not explicitly mentioned below (such as Debian) are advised platforms not explicitly mentioned below are advised to download one of these
to download one of these archives. archives.
Linux binaries are static executables. Windows binaries are available either as Linux binaries are static executables. Windows binaries are available either as
built with MinGW (GNU) or with Microsoft Visual C++ (MSVC). When possible, built with MinGW (GNU) or with Microsoft Visual C++ (MSVC). When possible,
@@ -243,13 +243,23 @@ $ nix-env --install ripgrep
$ # (Or using the attribute name, which is also ripgrep.) $ # (Or using the attribute name, which is also ripgrep.)
``` ```
If you're a **Debian** user (or a user of a Debian derivative like **Ubuntu**),
then ripgrep can be installed using a binary `.deb` file provided in each
[ripgrep release](https://github.com/BurntSushi/ripgrep/releases). Note that
ripgrep is not in the official Debian or Ubuntu repositories.
```
$ curl -LO https://github.com/BurntSushi/ripgrep/releases/download/0.8.1/ripgrep_0.8.1_amd64.deb
$ sudo dpkg -i ripgrep_0.8.1_amd64.deb
```
If you're an **Ubuntu** user, ripgrep can be installed from the `snap` store. If you're an **Ubuntu** user, ripgrep can be installed from the `snap` store.
* Note that if you are using `16.04 LTS` or later, snap is already installed. * Note that if you are using `16.04 LTS` or later, snap is already installed.
* For older versions you can install snap using * For older versions you can install snap using
[this guide](https://docs.snapcraft.io/core/install-ubuntu). [this guide](https://docs.snapcraft.io/core/install-ubuntu).
``` ```
sudo snap install rg $ sudo snap install rg
``` ```
If you're a **Rust programmer**, ripgrep can be installed with `cargo`. If you're a **Rust programmer**, ripgrep can be installed with `cargo`.

View File

@@ -58,8 +58,13 @@ fn git_revision_hash() -> Option<String> {
let result = process::Command::new("git") let result = process::Command::new("git")
.args(&["rev-parse", "--short=10", "HEAD"]) .args(&["rev-parse", "--short=10", "HEAD"])
.output(); .output();
result.ok().map(|output| { result.ok().and_then(|output| {
String::from_utf8_lossy(&output.stdout).trim().to_string() let v = String::from_utf8_lossy(&output.stdout).trim().to_string();
if v.is_empty() {
None
} else {
Some(v)
}
}) })
} }

View File

@@ -27,7 +27,7 @@ install_osx_dependencies() {
return return
fi fi
brew install asciidoc brew install asciidoc docbook-xsl
} }
configure_cargo() { configure_cargo() {

View File

@@ -23,6 +23,13 @@ main() {
# sanity check the file type # sanity check the file type
file target/"$TARGET"/debug/rg file target/"$TARGET"/debug/rg
# Check that we've generated man page and other shell completions.
outdir="$(cargo_out_dir "target/$TARGET/debug")"
file "$outdir/rg.bash"
file "$outdir/rg.fish"
file "$outdir/_rg.ps1"
file "$outdir/rg.1"
# Apparently tests don't work on arm, so just bail now. I guess we provide # Apparently tests don't work on arm, so just bail now. I guess we provide
# ARM releases on a best effort basis? # ARM releases on a best effort basis?
if is_arm; then if is_arm; then
@@ -32,15 +39,6 @@ main() {
# Test that zsh completions are in sync with ripgrep's actual args. # Test that zsh completions are in sync with ripgrep's actual args.
"$(dirname "${0}")/test_complete.sh" "$(dirname "${0}")/test_complete.sh"
# Check that we've generated man page and other shell completions.
outdir="$(cargo_out_dir "target/$TARGET/debug")"
file "$outdir/rg.bash"
file "$outdir/rg.fish"
file "$outdir/_rg.ps1"
# N.B. man page isn't generated on ARM cross-compile, but we gave up
# long before this anyway.
file "$outdir/rg.1"
# Run tests for ripgrep and all sub-crates. # Run tests for ripgrep and all sub-crates.
cargo test --target "$TARGET" --verbose --all cargo test --target "$TARGET" --verbose --all
} }

View File

@@ -125,7 +125,7 @@ _rg() {
[[ "${state}" == 'style' ]] && [[ "${state}" == 'style' ]] &&
_values -S ':' 'style value' \ _values -S ':' 'style value' \
bold nobold intense nointense && return 0 bold nobold intense nointense underline nounderline && return 0
;; ;;
typespec) typespec)

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "ignore" name = "ignore"
version = "0.4.0" #:version version = "0.4.1" #: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`

View File

@@ -73,13 +73,6 @@ struct IgnoreOptions {
git_exclude: bool, git_exclude: bool,
} }
impl IgnoreOptions {
/// Returns true if at least one type of ignore rules should be matched.
fn has_any_ignore_options(&self) -> bool {
self.ignore || self.git_global || self.git_ignore || self.git_exclude
}
}
/// Ignore is a matcher useful for recursively walking one or more directories. /// Ignore is a matcher useful for recursively walking one or more directories.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Ignore(Arc<IgnoreInner>); pub struct Ignore(Arc<IgnoreInner>);
@@ -267,6 +260,15 @@ impl Ignore {
(ig, errs.into_error_option()) (ig, errs.into_error_option())
} }
/// Returns true if at least one type of ignore rule should be matched.
fn has_any_ignore_rules(&self) -> bool {
let opts = self.0.opts;
let has_custom_ignore_files = !self.0.custom_ignore_filenames.is_empty();
opts.ignore || opts.git_global || opts.git_ignore
|| opts.git_exclude || has_custom_ignore_files
}
/// Returns a match indicating whether the given file path should be /// Returns a match indicating whether the given file path should be
/// ignored or not. /// ignored or not.
/// ///
@@ -295,7 +297,7 @@ impl Ignore {
} }
} }
let mut whitelisted = Match::None; let mut whitelisted = Match::None;
if self.0.opts.has_any_ignore_options() { if self.has_any_ignore_rules() {
let mat = self.matched_ignore(path, is_dir); let mat = self.matched_ignore(path, is_dir);
if mat.is_ignore() { if mat.is_ignore() {
return mat; return mat;

View File

@@ -66,6 +66,12 @@ impl Glob {
pub fn is_only_dir(&self) -> bool { pub fn is_only_dir(&self) -> bool {
self.is_only_dir self.is_only_dir
} }
/// Returns true if and only if this glob has a `**/` prefix.
fn has_doublestar_prefix(&self) -> bool {
self.actual.starts_with("**/")
|| (self.actual == "**" && self.is_only_dir)
}
} }
/// Gitignore is a matcher for the globs in one or more gitignore files /// Gitignore is a matcher for the globs in one or more gitignore files
@@ -278,7 +284,10 @@ impl Gitignore {
// BUT, a file name might not have any directory components to it, // BUT, a file name might not have any directory components to it,
// in which case, we don't want to accidentally strip any part of the // in which case, we don't want to accidentally strip any part of the
// file name. // file name.
if !is_file_name(path) { //
// As an additional special case, if the root is just `.`, then we
// shouldn't try to strip anything, e.g., when path begins with a `.`.
if self.root != Path::new(".") && !is_file_name(path) {
if let Some(p) = strip_prefix(&self.root, path) { if let Some(p) = strip_prefix(&self.root, path) {
path = p; path = p;
// If we're left with a leading slash, get rid of it. // If we're left with a leading slash, get rid of it.
@@ -454,7 +463,7 @@ impl GitignoreBuilder {
// prefix. // prefix.
if !literal_separator { if !literal_separator {
// ... but only if we don't already have a **/ prefix. // ... but only if we don't already have a **/ prefix.
if !(glob.actual.starts_with("**/") || (glob.actual == "**" && glob.is_only_dir)) { if !glob.has_doublestar_prefix() {
glob.actual = format!("**/{}", glob.actual); glob.actual = format!("**/{}", glob.actual);
} }
} }
@@ -620,6 +629,12 @@ mod tests {
ignored!(ig29, ROOT, "node_modules/ ", "node_modules", true); ignored!(ig29, ROOT, "node_modules/ ", "node_modules", true);
ignored!(ig30, ROOT, "**/", "foo/bar", true); ignored!(ig30, ROOT, "**/", "foo/bar", true);
ignored!(ig31, ROOT, "path1/*", "path1/foo"); ignored!(ig31, ROOT, "path1/*", "path1/foo");
ignored!(ig32, ROOT, ".a/b", ".a/b");
ignored!(ig33, "./", ".a/b", ".a/b");
ignored!(ig34, ".", ".a/b", ".a/b");
ignored!(ig35, "./.", ".a/b", ".a/b");
ignored!(ig36, "././", ".a/b", ".a/b");
ignored!(ig37, "././.", ".a/b", ".a/b");
not_ignored!(ignot1, ROOT, "amonths", "months"); not_ignored!(ignot1, ROOT, "amonths", "months");
not_ignored!(ignot2, ROOT, "monthsa", "months"); not_ignored!(ignot2, ROOT, "monthsa", "months");

View File

@@ -122,6 +122,7 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
("csharp", &["*.cs"]), ("csharp", &["*.cs"]),
("cshtml", &["*.cshtml"]), ("cshtml", &["*.cshtml"]),
("css", &["*.css", "*.scss"]), ("css", &["*.css", "*.scss"]),
("csv", &["*.csv"]),
("cython", &["*.pyx"]), ("cython", &["*.pyx"]),
("dart", &["*.dart"]), ("dart", &["*.dart"]),
("d", &["*.d"]), ("d", &["*.d"]),
@@ -274,6 +275,7 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
("twig", &["*.twig"]), ("twig", &["*.twig"]),
("vala", &["*.vala"]), ("vala", &["*.vala"]),
("vb", &["*.vb"]), ("vb", &["*.vb"]),
("vhdl", &["*.vhd", "*.vhdl"]),
("vim", &["*.vim"]), ("vim", &["*.vim"]),
("vimscript", &["*.vim"]), ("vimscript", &["*.vim"]),
("wiki", &["*.mediawiki", "*.wiki"]), ("wiki", &["*.mediawiki", "*.wiki"]),

View File

@@ -249,6 +249,14 @@ struct DirEntryRaw {
/// The underlying inode number (Unix only). /// The underlying inode number (Unix only).
#[cfg(unix)] #[cfg(unix)]
ino: u64, ino: u64,
/// The underlying metadata (Windows only). We store this on Windows
/// because this comes for free while reading a directory.
///
/// We use this to determine whether an entry is a directory or not, which
/// works around a bug in Rust's standard library:
/// https://github.com/rust-lang/rust/issues/46484
#[cfg(windows)]
metadata: fs::Metadata,
} }
impl fmt::Debug for DirEntryRaw { impl fmt::Debug for DirEntryRaw {
@@ -274,6 +282,20 @@ impl DirEntryRaw {
} }
fn metadata(&self) -> Result<Metadata, Error> { fn metadata(&self) -> Result<Metadata, Error> {
self.metadata_internal()
}
#[cfg(windows)]
fn metadata_internal(&self) -> Result<fs::Metadata, Error> {
if self.follow_link {
fs::metadata(&self.path)
} else {
Ok(self.metadata.clone())
}.map_err(|err| Error::Io(io::Error::from(err)).with_path(&self.path))
}
#[cfg(not(windows))]
fn metadata_internal(&self) -> Result<fs::Metadata, Error> {
if self.follow_link { if self.follow_link {
fs::metadata(&self.path) fs::metadata(&self.path)
} else { } else {
@@ -309,21 +331,29 @@ impl DirEntryRaw {
err: Box::new(err), err: Box::new(err),
} }
})?; })?;
Ok(DirEntryRaw::from_entry_os(depth, ent, ty)) DirEntryRaw::from_entry_os(depth, ent, ty)
} }
#[cfg(not(unix))] #[cfg(windows)]
fn from_entry_os( fn from_entry_os(
depth: usize, depth: usize,
ent: &fs::DirEntry, ent: &fs::DirEntry,
ty: fs::FileType, ty: fs::FileType,
) -> DirEntryRaw { ) -> Result<DirEntryRaw, Error> {
DirEntryRaw { let md = ent.metadata().map_err(|err| {
let err = Error::Io(io::Error::from(err)).with_path(ent.path());
Error::WithDepth {
depth: depth,
err: Box::new(err),
}
})?;
Ok(DirEntryRaw {
path: ent.path(), path: ent.path(),
ty: ty, ty: ty,
follow_link: false, follow_link: false,
depth: depth, depth: depth,
} metadata: md,
})
} }
#[cfg(unix)] #[cfg(unix)]
@@ -331,16 +361,16 @@ impl DirEntryRaw {
depth: usize, depth: usize,
ent: &fs::DirEntry, ent: &fs::DirEntry,
ty: fs::FileType, ty: fs::FileType,
) -> DirEntryRaw { ) -> Result<DirEntryRaw, Error> {
use std::os::unix::fs::DirEntryExt; use std::os::unix::fs::DirEntryExt;
DirEntryRaw { Ok(DirEntryRaw {
path: ent.path(), path: ent.path(),
ty: ty, ty: ty,
follow_link: false, follow_link: false,
depth: depth, depth: depth,
ino: ent.ino(), ino: ent.ino(),
} })
} }
#[cfg(not(unix))] #[cfg(not(unix))]
@@ -353,6 +383,7 @@ impl DirEntryRaw {
ty: md.file_type(), ty: md.file_type(),
follow_link: true, follow_link: true,
depth: depth, depth: depth,
metadata: md,
}) })
} }
@@ -1026,6 +1057,11 @@ impl Work {
self.dent.is_dir() self.dent.is_dir()
} }
/// Returns true if and only if this work item is a symlink.
fn is_symlink(&self) -> bool {
self.dent.file_type().map_or(false, |ft| ft.is_symlink())
}
/// Adds ignore rules for parent directories. /// Adds ignore rules for parent directories.
/// ///
/// Note that this only applies to entries at depth 0. On all other /// Note that this only applies to entries at depth 0. On all other
@@ -1112,7 +1148,7 @@ impl Worker {
while let Some(mut work) = self.get_work() { while let Some(mut work) = self.get_work() {
// If the work is not a directory, then we can just execute the // If the work is not a directory, then we can just execute the
// caller's callback immediately and move on. // caller's callback immediately and move on.
if !work.is_dir() { if work.is_symlink() || !work.is_dir() {
if (self.f)(Ok(work.dent)).is_quit() { if (self.f)(Ok(work.dent)).is_quit() {
self.quit_now(); self.quit_now();
return; return;
@@ -1585,6 +1621,26 @@ mod tests {
assert_paths(td.path(), &builder, &["bar", "a", "a/bar"]); assert_paths(td.path(), &builder, &["bar", "a", "a/bar"]);
} }
#[test]
fn custom_ignore_exclusive_use() {
let td = TempDir::new("walk-test-").unwrap();
let custom_ignore = ".customignore";
mkdirp(td.path().join("a"));
wfile(td.path().join(custom_ignore), "foo");
wfile(td.path().join("foo"), "");
wfile(td.path().join("a/foo"), "");
wfile(td.path().join("bar"), "");
wfile(td.path().join("a/bar"), "");
let mut builder = WalkBuilder::new(td.path());
builder.ignore(false);
builder.git_ignore(false);
builder.git_global(false);
builder.git_exclude(false);
builder.add_custom_ignore_filename(&custom_ignore);
assert_paths(td.path(), &builder, &["bar", "a", "a/bar"]);
}
#[test] #[test]
fn gitignore() { fn gitignore() {
let td = TempDir::new("walk-test-").unwrap(); let td = TempDir::new("walk-test-").unwrap();

View File

@@ -1,4 +0,0 @@
*.xz
src
pkg
*.gz

View File

@@ -1,37 +0,0 @@
# Contributor: Andrew Gallant <jamslam@gmail.com>
# Maintainer: Andrew Gallant
pkgname=ripgrep
pkgver=0.2.3
pkgrel=1
pkgdesc="A search tool that combines the usability of The Silver Searcher with the raw speed of grep."
arch=('i686' 'x86_64')
url="https://github.com/BurntSushi/ripgrep"
license=('UNLICENSE')
makedepends=('cargo')
source=("https://github.com/BurntSushi/$pkgname/archive/$pkgver.tar.gz")
sha256sums=('a88531558d2023df76190ea2e52bee50d739eabece8a57df29abbad0c6bdb917')
build() {
cd "$pkgname-$pkgver"
if command -v rustup > /dev/null 2>&1; then
RUSTFLAGS="-C target-cpu=native" rustup run nightly \
cargo build --release --features simd-accel
elif rustc --version | grep -q nightly; then
RUSTFLAGS="-C target-cpu=native" \
cargo build --release --features simd-accel
else
cargo build --release
fi
}
package() {
cd "$pkgname-$pkgver"
install -Dm755 "target/release/rg" "$pkgdir/usr/bin/rg"
install -Dm644 "doc/rg.1" "$pkgdir/usr/share/man/man1/rg.1"
install -Dm644 "README.md" "$pkgdir/usr/share/doc/ripgrep/README.md"
install -Dm644 "COPYING" "$pkgdir/usr/share/doc/ripgrep/COPYING"
install -Dm644 "LICENSE-MIT" "$pkgdir/usr/share/doc/ripgrep/LICENSE-MIT"
install -Dm644 "UNLICENSE" "$pkgdir/usr/share/doc/ripgrep/UNLICENSE"
install -Dm644 "CHANGELOG.md" "$pkgdir/usr/share/doc/ripgrep/CHANGELOG.md"
}

View File

@@ -1,23 +1,23 @@
class RipgrepBin < Formula class RipgrepBin < Formula
version '0.7.1' version '0.8.0'
desc "Search tool like grep and The Silver Searcher." desc "Recursively search directories for a regex pattern."
homepage "https://github.com/BurntSushi/ripgrep" homepage "https://github.com/BurntSushi/ripgrep"
if OS.mac? if OS.mac?
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 "ee670b0fba46323ee9a2d1c5b8bee46fa3e45778f6f105f2e8e9ee29e8bd0d45" sha256 "fb35e92fd57d28a1e68daf964764c3da7f027ad30cca7a07a1848224776f36b2"
elsif OS.linux? elsif OS.linux?
url "https://github.com/BurntSushi/ripgrep/releases/download/#{version}/ripgrep-#{version}-x86_64-unknown-linux-musl.tar.gz" url "https://github.com/BurntSushi/ripgrep/releases/download/#{version}/ripgrep-#{version}-x86_64-unknown-linux-musl.tar.gz"
sha256 "ac595c2239b9a30e0e0744578afa6b73e32cdd8ae61d4f1c0ee5d6b55adbadcf" sha256 "621f2f16f65203aa37e7c10ecfb22384c4c01e70ebbd30a13c0d6944ffc6e59e"
end end
conflicts_with "ripgrep" conflicts_with "ripgrep"
def install def install
bin.install "rg" bin.install "rg"
man1.install "rg.1" man1.install "doc/rg.1"
bash_completion.install "complete/rg.bash-completion" bash_completion.install "complete/rg.bash"
fish_completion.install "complete/rg.fish" fish_completion.install "complete/rg.fish"
zsh_completion.install "complete/_rg" zsh_completion.install "complete/_rg"
end end

View File

@@ -682,7 +682,8 @@ fn flag_colors(args: &mut Vec<RGArg>) {
This flag specifies color settings for use in the output. This flag may be This flag specifies color settings for use in the output. This flag may be
provided multiple times. Settings are applied iteratively. Colors are limited provided multiple times. Settings are applied iteratively. Colors are limited
to one of eight choices: red, blue, green, cyan, magenta, yellow, white and to one of eight choices: red, blue, green, cyan, magenta, yellow, white and
black. Styles are limited to nobold, bold, nointense or intense. black. Styles are limited to nobold, bold, nointense, intense, nounderline
or underline.
The format of the flag is `{type}:{attribute}:{value}`. `{type}` should be The format of the flag is `{type}:{attribute}:{value}`. `{type}` should be
one of path, line, column or match. `{attribute}` can be fg, bg or style. one of path, line, column or match. `{attribute}` can be fg, bg or style.
@@ -848,7 +849,7 @@ fn flag_files_with_matches(args: &mut Vec<RGArg>) {
const LONG: &str = long!("\ const LONG: &str = long!("\
Only print the paths with at least one match. Only print the paths with at least one match.
This overrides --file-without-match. This overrides --files-without-match.
"); ");
let arg = RGArg::switch("files-with-matches").short("l") let arg = RGArg::switch("files-with-matches").short("l")
.help(SHORT).long_help(LONG) .help(SHORT).long_help(LONG)
@@ -1000,12 +1001,12 @@ This flag overrides -s/--case-sensitive and -S/--smart-case.
fn flag_ignore_file(args: &mut Vec<RGArg>) { fn flag_ignore_file(args: &mut Vec<RGArg>) {
const SHORT: &str = "Specify additional ignore files."; const SHORT: &str = "Specify additional ignore files.";
const LONG: &str = long!("\ const LONG: &str = long!("\
Specify one or more files which contain ignore patterns. These patterns are Specifies a path to one or more .gitignore format rules files. These patterns
applied after the patterns found in .gitignore and .ignore are applied. Ignore are applied after the patterns found in .gitignore and .ignore are applied
patterns should be in the gitignore format and are matched relative to the and are matched relative to the current working directory. Multiple additional
current working directory. Multiple additional ignore files can be specified ignore files can be specified by using the --ignore-file flag several times.
by using the --ignore-file flag several times. When specifying multiple ignore When specifying multiple ignore files, earlier files have lower precedence
files, earlier files have lower precedence than later files. than later files.
If you are looking for a way to include or exclude files and directories If you are looking for a way to include or exclude files and directories
directly on the command line, then used -g instead. directly on the command line, then used -g instead.

View File

@@ -555,7 +555,8 @@ 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, nointense, intense.", name) nobold, bold, nointense, intense, nounderline, \
underline.", name)
} }
Error::InvalidFormat(ref original) => { Error::InvalidFormat(ref original) => {
write!( write!(
@@ -627,7 +628,8 @@ pub struct ColorSpecs {
/// Valid colors are `black`, `blue`, `green`, `red`, `cyan`, `magenta`, /// Valid colors are `black`, `blue`, `green`, `red`, `cyan`, `magenta`,
/// `yellow`, `white`. /// `yellow`, `white`.
/// ///
/// Valid style instructions are `nobold`, `bold`, `intense`, `nointense`. /// Valid style instructions are `nobold`, `bold`, `intense`, `nointense`,
/// `underline`, `nounderline`.
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct Spec { pub struct Spec {
ty: OutType, ty: OutType,
@@ -668,6 +670,8 @@ enum Style {
NoBold, NoBold,
Intense, Intense,
NoIntense, NoIntense,
Underline,
NoUnderline
} }
impl ColorSpecs { impl ColorSpecs {
@@ -727,6 +731,8 @@ impl SpecValue {
Style::NoBold => { cspec.set_bold(false); } Style::NoBold => { cspec.set_bold(false); }
Style::Intense => { cspec.set_intense(true); } Style::Intense => { cspec.set_intense(true); }
Style::NoIntense => { cspec.set_intense(false); } Style::NoIntense => { cspec.set_intense(false); }
Style::Underline => { cspec.set_underline(true); }
Style::NoUnderline => { cspec.set_underline(false); }
} }
} }
} }
@@ -806,6 +812,8 @@ impl FromStr for Style {
"nobold" => Ok(Style::NoBold), "nobold" => Ok(Style::NoBold),
"intense" => Ok(Style::Intense), "intense" => Ok(Style::Intense),
"nointense" => Ok(Style::NoIntense), "nointense" => Ok(Style::NoIntense),
"underline" => Ok(Style::Underline),
"nounderline" => Ok(Style::NoUnderline),
_ => Err(Error::UnrecognizedStyle(s.to_string())), _ => Err(Error::UnrecognizedStyle(s.to_string())),
} }
} }
@@ -859,6 +867,12 @@ mod tests {
value: SpecValue::Style(Style::Intense), value: SpecValue::Style(Style::Intense),
}); });
let spec: Spec = "match:style:underline".parse().unwrap();
assert_eq!(spec, Spec {
ty: OutType::Match,
value: SpecValue::Style(Style::Underline),
});
let spec: Spec = "line:none".parse().unwrap(); let spec: Spec = "line:none".parse().unwrap();
assert_eq!(spec, Spec { assert_eq!(spec, Spec {
ty: OutType::Line, ty: OutType::Line,

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "termcolor" name = "termcolor"
version = "0.3.4" #:version version = "0.3.5" #: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.

View File

@@ -104,7 +104,7 @@ pub trait WriteColor: io::Write {
fn reset(&mut self) -> io::Result<()>; fn reset(&mut self) -> io::Result<()>;
} }
impl<'a, T: WriteColor> WriteColor for &'a mut T { impl<'a, T: ?Sized + WriteColor> WriteColor for &'a mut T {
fn supports_color(&self) -> bool { (&**self).supports_color() } fn supports_color(&self) -> bool { (&**self).supports_color() }
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
(&mut **self).set_color(spec) (&mut **self).set_color(spec)
@@ -980,6 +980,9 @@ impl<W: io::Write> WriteColor for Ansi<W> {
if spec.bold { if spec.bold {
self.write_str("\x1B[1m")?; self.write_str("\x1B[1m")?;
} }
if spec.underline {
self.write_str("\x1B[4m")?;
}
Ok(()) Ok(())
} }
@@ -1212,6 +1215,7 @@ pub struct ColorSpec {
bg_color: Option<Color>, bg_color: Option<Color>,
bold: bool, bold: bool,
intense: bool, intense: bool,
underline: bool,
} }
impl ColorSpec { impl ColorSpec {
@@ -1251,10 +1255,37 @@ impl ColorSpec {
self self
} }
/// Get whether this is underline or not.
///
/// Note that the underline setting has no effect in a Windows console.
pub fn underline(&self) -> bool { self.underline }
/// Set whether the text is underlined or not.
///
/// Note that the underline setting has no effect in a Windows console.
pub fn set_underline(&mut self, yes: bool) -> &mut ColorSpec {
self.underline = yes;
self
}
/// Get whether this is intense or not. /// Get whether this is intense or not.
///
/// On Unix-like systems, this will output the ANSI escape sequence
/// that will print a high-intensity version of the color
/// specified.
///
/// On Windows systems, this will output the ANSI escape sequence
/// that will print a brighter version of the color specified.
pub fn intense(&self) -> bool { self.intense } pub fn intense(&self) -> bool { self.intense }
/// Set whether the text is intense or not. /// Set whether the text is intense or not.
///
/// On Unix-like systems, this will output the ANSI escape sequence
/// that will print a high-intensity version of the color
/// specified.
///
/// On Windows systems, this will output the ANSI escape sequence
/// that will print a brighter version of the color specified.
pub fn set_intense(&mut self, yes: bool) -> &mut ColorSpec { pub fn set_intense(&mut self, yes: bool) -> &mut ColorSpec {
self.intense = yes; self.intense = yes;
self self
@@ -1262,7 +1293,8 @@ impl ColorSpec {
/// Returns true if this color specification has no colors or styles. /// Returns true if this color specification has no colors or styles.
pub fn is_none(&self) -> bool { pub fn is_none(&self) -> bool {
self.fg_color.is_none() && self.bg_color.is_none() && !self.bold self.fg_color.is_none() && self.bg_color.is_none()
&& !self.bold && !self.underline
} }
/// Clears this color specification so that it has no color/style settings. /// Clears this color specification so that it has no color/style settings.
@@ -1270,6 +1302,7 @@ impl ColorSpec {
self.fg_color = None; self.fg_color = None;
self.bg_color = None; self.bg_color = None;
self.bold = false; self.bold = false;
self.underline = false;
} }
/// Writes this color spec to the given Windows console. /// Writes this color spec to the given Windows console.

View File

@@ -1152,7 +1152,8 @@ clean!(regression_428_unrecognized_style, "Sherlok", ".",
let output = cmd.output().unwrap(); let output = cmd.output().unwrap();
let err = String::from_utf8_lossy(&output.stderr); let err = String::from_utf8_lossy(&output.stderr);
let expected = "\ let expected = "\
Unrecognized style attribute ''. Choose from: nobold, bold, nointense, intense. Unrecognized style attribute ''. Choose from: nobold, bold, nointense, intense, \
nounderline, underline.
"; ";
assert_eq!(err, expected); assert_eq!(err, expected);
}); });
@@ -1232,6 +1233,19 @@ clean!(regression_599, "^$", "input.txt", |wd: WorkDir, mut cmd: Command| {
assert_eq!(expected, lines); assert_eq!(expected, lines);
}); });
// See: https://github.com/BurntSushi/ripgrep/issues/807
clean!(regression_807, "test", ".", |wd: WorkDir, mut cmd: Command| {
wd.create(".gitignore", ".a/b");
wd.create_dir(".a/b");
wd.create_dir(".a/c");
wd.create(".a/b/file", "test");
wd.create(".a/c/file", "test");
cmd.arg("--hidden");
let lines: String = wd.stdout(&mut cmd);
assert_eq!(lines, format!("{}:test\n", path(".a/c/file")));
});
// 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 =