Compare commits

...

61 Commits

Author SHA1 Message Date
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
Andrew Gallant
f3146f8316 changelog: 0.8.0 2018-02-11 13:57:29 -05:00
Andrew Gallant
56341973ee ignore: release 0.4.0 2018-02-11 13:42:59 -05:00
Andrew Gallant
a431160d4c globset: release 0.3.0 2018-02-11 13:41:36 -05:00
Andrew Gallant
5d15f49f0c termcolor: release 0.3.4 2018-02-11 13:39:12 -05:00
Andrew Gallant
7718ee362e wincolor: release 0.1.6 2018-02-11 13:38:00 -05:00
Andrew Gallant
739f8f596b grep: release 0.1.8 2018-02-11 13:35:54 -05:00
Andrew Gallant
e818d7529b deps: update several dependencies
We specifically avoid updating tempdir since it seems to have grown a
dependency on `remove_dir_all`, which in turn still uses winapi 0.2.
2018-02-11 13:31:41 -05:00
Andrew Gallant
a2a7f58aa6 doc: fix asciidoc->man formatting 2018-02-10 22:48:46 -05:00
Andrew Gallant
c4a5bc06c5 ci: remove cargo clean
We aren't using Travis' Cargo cache any more (because it actually seems
to slow down builds), so there's no reason to clean out old build
outputs.

Also, even if we were using the Cargo cache, our approach to finding the
correct Cargo OUT_DIR has become more robust, so we still wouldn't need
to remove the old build outputs.
2018-02-10 22:28:12 -05:00
Andrew Gallant
96ee4482cd globset: remove use of unsafe
This commit removes, in retrospect, a silly use of `unsafe`. In particular,
to extract a file name extension (distinct from how `std` implements it),
we were transmuting an OsStr to its underlying WTF-8 byte representation
and then searching that. This required `unsafe` and relied on an
undocumented std API, so it was a bad choice to make, but everything gets
sacrificed at the Alter of Performance.

The thing I didn't seem to realize at the time was that:

  1. On Unix, you can already get the raw byte representation in a manner
     that has zero cost.
  2. On Windows, paths are already being encoded and copied every which
     way. So doing a UTF-8 check and, in rare cases (for invalid UTF-8),
     an extra copy, doesn't seem like that much more of an added expense.

Thus, rewrite the extension extraction using safe APIs. On Unix, this
should have identical performance characteristics as the previous
implementation. On Windows, we do pay a higher cost in the UTF-8
check, but Windows is already paying a similar cost a few times over
anyway.
2018-02-10 22:28:12 -05:00
Andrew Gallant
3effea0b7c doc: add color FAQ entries
This commit adds FAQ entries about how to configure ripgrep's coloring,
and how to get true color support in Windows consoles.
2018-02-10 22:28:12 -05:00
Andrew Gallant
2d68054b1d termcolor: support ANSI in Windows terminals
This commit uses the new virtual terminal processing feature in Windows 10
to enable the use of ANSI escape codes to color ripgrep's output. This
technique is preferred over the console APIs because it seems like where
the future is heading, but also because it avoids needing to use an
intermediate buffer to deal with the Windows console in a multithreaded
environment.
2018-02-10 22:28:12 -05:00
Andrew Gallant
65a63788bc wincolor: add support for enabling VT100
This commit adds a new method to the Console type which permits toggling
the VIRTUAL_TERMINAL_PROCESSING mode on a console. Specifically, this
enables the use of ANSI escape sequences for color in Windows terminals.
2018-02-10 22:28:12 -05:00
Andrew Gallant
7e5589f07d termcolor: permit hex colors
This commit adds support for specifying Ansi256 or RGB colors using
hexadecimal notation.
2018-02-10 22:28:12 -05:00
Andrew Gallant
09c5b2c4ea ci: update deployment for doc rearrangement
This fixes CI to handle the new documentation files. We also continue to
do more cleanup. In particular, we devise a nicer way of detecting the
most recent Cargo OUT_DIR by writing a dummy file, and looking for the
most recently modified version of that file.
2018-02-10 12:12:47 -05:00
Andrew Gallant
904c75bd30 doc: overhaul documentation
This commit cleans up the README and splits portions of it out into
a user guide (GUIDE.md) and a FAQ (FAQ.md). The README now provides a
small list of documentation "quick" links to various parts of the docs.

This commit also does a few other minor touchups.
2018-02-10 12:12:47 -05:00
Andrew Gallant
ca3e0e8a49 doc: clarify --files-without-match
This adds a couple common keywords to the documentation.

Fixes #779
2018-02-10 12:12:47 -05:00
Andrew Gallant
ae2d036dd4 build: remove compile script
This script has only ever intended to be a convenience to me to compile
ripgrep. It is otherwise a distraction, so remove it.
2018-02-10 12:12:47 -05:00
Andrew Gallant
8e93fa0e7f deps: update regex to 0.2.6
This regex update disabled the Tuned Boyer-Moore literal searcher which
has a bug in it that isn't straight-forward to fix. We bring that update
into ripgrep with this commit.

Fixes #780, Fixes #781
2018-02-08 18:25:55 -05:00
Andrew Gallant
7f5c07434b argv: add several hidden flags
This adds hidden counter-flags for the following:

  -L/--follow [--no-follow]
  --hidden [--no-hidden]
  --no-ignore [--ignore]
  --no-ignore-parent [--ignore-parent]
  --no-ignore-vcs [--ignore-vcs]
  --no-messages [--messages]
  --search-zip [--no-search-zip]
  --sort-files [--no-sort-files]
  --text [--no-text]

In the above list, the counter-flags are in brackets.

While these flags are hidden, we document the counter-flags in the
documentation for the flags they are countering.
2018-02-06 18:28:39 -05:00
Andrew Gallant
874f0b96a6 argv: support hidden flags
This commit adds support for hidden flags. The purpose of hidden flags
is for things that end users likely won't need unless they have a
configuration file that disables ripgrep's defaults. These flags will
provide a way to re-enable ripgrep's defaults.
2018-02-06 18:26:23 -05:00
Behnam Esfahbod
706323ad8f globset: add more tests for single-asterisk pattern
This adds a few tests that check for bugs reported here:
https://github.com/rust-lang/cargo/issues/4268

The bugs reported in the aforementioned issue are probably caused by not
enabling the `literal_separator` option in `GlobBuilder`. Enabling that
in the tests under question fixes the issue.

Closes #773
2018-02-06 17:42:22 -05:00
Andrew Gallant
8460d7fe3d ci: fix deploy condition
The previous setting was for debugging that accidentally got merged.
2018-02-06 17:27:57 -05:00
Andrew Gallant
e1f1ede17d ci: test build outputs
This modifies CI to check that we generate completion files and a man
page.

We also enable tests on arm.
2018-02-06 17:24:31 -05:00
Andrew Gallant
6553940328 doc: generate man page
This commit uses the recent refactoring for defining flags to
automatically generate a man page. This finally allows us to define the
documentation for each flag in a single place.

The man page is generated on every build, if and only if `asciidoc` is
installed. When generated, it is placed in Cargo's `OUT_DIR` directory,
which is the same place that shell completions live.
2018-02-06 12:07:59 -05:00
Andrew Gallant
b50ae9a99c ci: cleanup
This cleans up our CI scripts but doesn't significantly change anything.
Mostly this is removing dead code and wrong comments, and making the style
a bit more consistent.
2018-02-06 12:07:59 -05:00
Andrew Gallant
224c112e05 argv: tweak the meaning of zero
This commit makes a small tweak to the --max-columns flag. Namely, if
the value of the flag is 0, then ripgrep behaves as-if the flag were
absent.

This is useful in the context of ripgrep reading configuration from the
environment. For example, an end user might set --max-columns=150, but we
should permit the user to disable this setting when needed. Using -M0 is
a nice way to do that.

We do this because a zero value for --max-columns isn't particularly
meaningful. We do leave the --max-count, --max-filesize and --maxdepth
flags alone though, since a zero value for those flags is potentially
meaningful. (--max-count even has tests for ripgrep's behavior when
given a value of 0.)
2018-02-06 12:07:59 -05:00
Andrew Gallant
8cb5833ef9 argv: update clap to 2.29.4
We use the new AppSettings::AllArgsOverrideSelf to permit all flags to
be specified multiple times. This removes the need for our previous
work-around where we would enable `multiple` for every flag and then
just extract the last value when consuming clap's matches.

We also add a couple regression tests that ensure repeated switches and
flags work as expected.
2018-02-06 12:07:59 -05:00
Kevin K
85cd3f0a6e argv: fix PATTERN typo
When referencing the PATTERN positional argument,
we should use `pattern` and not `PATTERN`. The former
is the clap identifier name while the latter is the argument
value name.
2018-02-05 11:37:17 -05:00
Andrew Gallant
c57d0fb4e8 config: add persistent configuration
This commit adds support for reading configuration files that change
ripgrep's default behavior. The format of the configuration file is an
"rc" style and is very simple. It is defined by two rules:

  1. Every line is a shell argument, after trimming ASCII whitespace.
  2. Lines starting with '#' (optionally preceded by any amount of
     ASCII whitespace) are ignored.

ripgrep will look for a single configuration file if and only if the
RIPGREP_CONFIG_PATH environment variable is set and is non-empty.
ripgrep will parse shell arguments from this file on startup and will
behave as if the arguments in this file were prepended to any explicit
arguments given to ripgrep on the command line.

For example, if your ripgreprc file contained a single line:

    --smart-case

then the following command

    RIPGREP_CONFIG_PATH=wherever/.ripgreprc rg foo

would behave identically to the following command

    rg --smart-case foo

This commit also adds a new flag, --no-config, that when present will
suppress any and all support for configuration. This includes any future
support for auto-loading configuration files from pre-determined paths
(which this commit does not add).

Conflicts between configuration files and explicit arguments are handled
exactly like conflicts in the same command line invocation. That is,
this command:

    RIPGREP_CONFIG_PATH=wherever/.ripgreprc rg foo --case-sensitive

is exactly equivalent to

    rg --smart-case foo --case-sensitive

in which case, the --case-sensitive flag would override the --smart-case
flag.

Closes #196
2018-02-04 10:40:20 -05:00
Andrew Gallant
d83bab4d3f argv: permit repeated flags
This commit builds on the previous argv refactor by being more principled
about how we declared our flags. In particular, we now require that every
clap argument is one of three things: a positional argument, a switch or
a flag that accepts exactly one value. The latter two are always permitted
to be repeated, and we modify the code that consumes a clap::ArgMatches to
always use the *last* value of an argument. (clap by default always uses
the first value of argument, if it has been repeated and is accessed via
one of the singleton accessors.)

Fixes #553
2018-02-04 10:40:20 -05:00
Andrew Gallant
ce84e1ef04 argv: refactor clap initialization
This commit refactors how we define flags. In theory, this commit
should not result in any behavioral changes (other than perhaps more
consistent rules for flag overrides).

There are two important changes:

Firstly, each flag (or tightly coupled group of flags) is defined in its
own function. This function includes the documentation for that flag. This
improves the locality for each flag; everything you need to know about it
is self-contained in one small region of code.

Secondly, each flag is defined in terms of a very small ripgrep-specific
layer above clap. This permits us to have a set of structured arguments
independent of clap. The intention here is that we can use this indirection
to generate other documentation such as man pages.

This commit lays the ground work for modifying our use of clap in
principled way such that flags can be specified multiple times without
conflict. This in turn will help us implement support for persistent
configuration.
2018-02-04 10:40:20 -05:00
Andrew Gallant
c8e755f11f deps: remove vec-map feature from clap
This removes the vec-map feature from clap. clap's README claims that
vec-map provides a small performance benefit, but I could observe any in
ripgrep workloads.

The benefit here is that it drops a dependency.

Amazingly, this drops whole release build times for ripgrep from 68s to
33s, and debug build time also decreases from 22s to 15.5s. This was
entirely unintentional but a welcome surprise.
2018-02-04 10:40:20 -05:00
Andrew Gallant
68dac7c4b0 build: add git hash
This commit makes the git hash ripgrep was built with available for use
in the version string.

We also do a few minor touchups in build.rs and src/app.rs.
2018-02-04 10:40:20 -05:00
Andrew Gallant
3535047094 logger: drop env_logger
This commit updates the `log` crate to 0.4 and drops the dependency on
env_logger. In particular, the latest version of env_logger brings in
additional non-optional dependencies such as chrono that I don't think is
worth including into ripgrep.

It turns out ripgrep doesn't need any fancy logging. We just need a concept
of log levels and the ability to print to stderr. Therefore, we just roll
our own super simple logger.

This update is motivated by the persistent configuration task. In
particular, we need the ability to toggle the global log level more than
once, and this doesn't appear to be possible with older versions of the
log crate.
2018-02-04 10:40:20 -05:00
Andrew Gallant
fe00255494 deps: bump wincolor 2018-02-03 20:38:03 -05:00
45 changed files with 4449 additions and 2393 deletions

3
.gitignore vendored
View File

@@ -6,6 +6,7 @@ target
/ignore/Cargo.lock
/termcolor/Cargo.lock
/wincolor/Cargo.lock
/deployment
# Snapcraft files
stage
@@ -13,4 +14,4 @@ prime
parts
*.snap
*.pyc
ripgrep*_source.tar.bz2
ripgrep*_source.tar.bz2

View File

@@ -1,25 +1,27 @@
language: rust
cache: cargo
env:
global:
- PROJECT_NAME=ripgrep
- PROJECT_NAME: ripgrep
- RUST_BACKTRACE: full
addons:
apt:
packages:
# For generating man page.
- libxslt1-dev
- asciidoc
- docbook-xsl
- xsltproc
- libxml2-utils
# Needed for completion-function test.
- zsh
# Needed for testing decompression search.
- xz-utils
matrix:
fast_finish: true
include:
# Nightly channel.
# (All *nix releases are done on the nightly channel to take advantage
# of the regex library's multiple pattern SIMD search.)
# All *nix releases are done on the nightly channel to take advantage
# of the regex library's multiple pattern SIMD search.
- os: linux
rust: nightly
env: TARGET=i686-unknown-linux-musl
@@ -39,14 +41,22 @@ matrix:
- binutils-arm-linux-gnueabihf
- libc6-armhf-cross
- libc6-dev-armhf-cross
# Beta channel.
# 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
# Rust beta releases.
- os: linux
rust: beta
env: TARGET=x86_64-unknown-linux-musl
- os: linux
rust: beta
env: TARGET=x86_64-unknown-linux-gnu
# Minimum Rust supported channel.
# Minimum Rust supported channel. We enable these to make sure ripgrep
# continues to work on the advertised minimum Rust version.
- os: linux
rust: 1.20.0
env: TARGET=x86_64-unknown-linux-gnu
@@ -63,43 +73,33 @@ matrix:
- binutils-arm-linux-gnueabihf
- libc6-armhf-cross
- libc6-dev-armhf-cross
before_install:
- export PATH="$PATH:$HOME/.cargo/bin"
install:
- bash ci/install.sh
script:
- bash ci/script.sh
before_deploy:
- bash ci/before_deploy.sh
# For generating man page.
- libxslt1-dev
- asciidoc
- docbook-xsl
- xsltproc
- libxml2-utils
install: ci/install.sh
script: ci/script.sh
before_deploy: ci/before_deploy.sh
deploy:
provider: releases
file_glob: true
file: deployment/${PROJECT_NAME}-${TRAVIS_TAG}-${TARGET}.tar.gz
skip_cleanup: true
on:
condition: $TRAVIS_RUST_VERSION = nightly
branch: master
tags: true
api_key:
secure: "IbSnsbGkxSydR/sozOf1/SRvHplzwRUHzcTjM7BKnr7GccL86gRPUrsrvD103KjQUGWIc1TnK1YTq5M0Onswg/ORDjqa1JEJPkPdPnVh9ipbF7M2De/7IlB4X4qXLKoApn8+bx2x/mfYXu4G+G1/2QdbaKK2yfXZKyjz0YFx+6CNrVCT2Nk8q7aHvOOzAL58vsG8iPDpupuhxlMDDn/UhyOWVInmPPQ0iJR1ZUJN8xJwXvKvBbfp3AhaBiAzkhXHNLgBR8QC5noWWMXnuVDMY3k4f3ic0V+p/qGUCN/nhptuceLxKFicMCYObSZeUzE5RAI0/OBW7l3z2iCoc+TbAnn+JrX/ObJCfzgAOXAU3tLaBFMiqQPGFKjKg1ltSYXomOFP/F7zALjpvFp4lYTBajRR+O3dqaxA9UQuRjw27vOeUpMcga4ZzL4VXFHzrxZKBHN//XIGjYAVhJ1NSSeGpeJV5/+jYzzWKfwSagRxQyVCzMooYFFXzn8Yxdm3PJlmp3GaAogNkdB9qKcrEvRINCelalzALPi0hD/HUDi8DD2PNTCLLMo6VSYtvc685Zbe+KgNzDV1YyTrRCUW6JotrS0r2ULLwnsh40hSB//nNv3XmwNmC/CmW5QAnIGj8cBMF4S2t6ohADIndojdAfNiptmaZOIT6owK7bWMgPMyopo="
file_glob: true
file: ${PROJECT_NAME}-${TRAVIS_TAG}-${TARGET}.*
# don't delete the artifacts from previous phases
skip_cleanup: true
# deploy when a new tag is pushed
on:
# channel to use to produce the release artifacts
# NOTE make sure you only release *once* per target
# TODO you may want to pick a different channel
condition: $TRAVIS_RUST_VERSION = nightly
tags: true
branches:
only:
# Pushes and PR to the master branch
- master
# IMPORTANT Ruby regex to match tags. Required, or travis won't trigger deploys when a new tag
# is pushed. This regex matches semantic versions like v1.2.3-rc4+2016.02.22
# Ruby regex to match tags. Required, or travis won't trigger deploys when
# a new tag is pushed.
- /^\d+\.\d+\.\d+.*$/
notifications:
email:
on_success: never

View File

@@ -1,3 +1,135 @@
0.8.0 (2018-02-11)
==================
This is a new minor version releae of ripgrep that satisfies several popular
feature requests (config files, search compressed files, true colors), fixes
many bugs and improves the quality of life for ripgrep maintainers. This
release also includes greatly improved documentation in the form of a
[User Guide](GUIDE.md) and a [FAQ](FAQ.md).
This release increases the **minimum supported Rust version** from 1.17 to
1.20.
**BREAKING CHANGES**:
Note that these are all very minor and unlikely to impact most users.
* In order to support configuration files, flag overrides needed to be
rethought. In some cases, this changed ripgrep's behavior. For example,
in ripgrep 0.7.1, `rg foo -s -i` will perform a case sensitive search
since the `-s/--case-sensitive` flag was defined to always take precedence
over the `-i/--ignore-case` flag, regardless of position. In ripgrep 0.8.0
however, the override rule for all flags has changed to "the most recent
flag wins among competing flags." That is, `rg foo -s -i` now performs a
case insensitive search.
* The `-M/--max-columns` flag was tweaked so that specifying a value of `0`
now makes ripgrep behave as if the flag was absent. This makes it possible
to set a default value in a configuration file and then override it. The
previous ripgrep behavior was to suppress all matching non-empty lines.
* In all globs, `[^...]` is now equivalent to `[!...]` (indicating class
negation). Previously, `^` had no special significance in a character class.
* For **downstream packagers**, the directory hierarchy in ripgrep's archive
releases has changed. The root directory now only contains the executable,
README and license. There is now a new directory called `doc` which contains
the man page (previously in the root), a user guide (new), a FAQ (new) and
the CHANGELOG (previously not included in release). The `complete`
directory remains the same.
Feature enhancements:
* Added or improved file type filtering for
Apache Avro, C++, GN, Google Closure Templates, Jupyter notebooks, man pages,
Protocol Buffers, Smarty and Web IDL.
* [FEATURE #196](https://github.com/BurntSushi/ripgrep/issues/196):
Support a configuration file. See
[the new user guide](GUIDE.md#configuration-file)
for details.
* [FEATURE #261](https://github.com/BurntSushi/ripgrep/issues/261):
Add extended or "true" color support. Works in Windows 10!
[See the FAQ for details.](FAQ.md#colors)
* [FEATURE #539](https://github.com/BurntSushi/ripgrep/issues/539):
Search gzip, bzip2, lzma or xz files when given `-z/--search-zip` flag.
* [FEATURE #544](https://github.com/BurntSushi/ripgrep/issues/544):
Add support for line number alignment via a new `--line-number-width` flag.
* [FEATURE #654](https://github.com/BurntSushi/ripgrep/pull/654):
Support linuxbrew in ripgrep's Brew tap.
* [FEATURE #673](https://github.com/BurntSushi/ripgrep/issues/673):
Bring back `.rgignore` files. (A higher precedent, application specific
version of `.ignore`.)
* [FEATURE #676](https://github.com/BurntSushi/ripgrep/issues/676):
Provide ARM binaries. **WARNING:** This will be provided on a best effort
basis.
* [FEATURE #709](https://github.com/BurntSushi/ripgrep/issues/709):
Suggest `-F/--fixed-strings` flag on a regex syntax error.
* [FEATURE #740](https://github.com/BurntSushi/ripgrep/issues/740):
Add a `--passthru` flag that causes ripgrep to print every line it reads.
* [FEATURE #785](https://github.com/BurntSushi/ripgrep/pull/785):
Overhaul documentation. Cleaned up README, added user guide and FAQ.
* [FEATURE 7f5c07](https://github.com/BurntSushi/ripgrep/commit/7f5c07434be92103b5bf7e216b9c7494aed2d8cb):
Add hidden flags for convenient overrides (e.g., `--no-text`).
Bug fixes:
* [BUG #553](https://github.com/BurntSushi/ripgrep/issues/553):
Permit flags to be repeated.
* [BUG #633](https://github.com/BurntSushi/ripgrep/issues/633):
Fix a bug where ripgrep would panic on Windows while following symlinks.
* [BUG #649](https://github.com/BurntSushi/ripgrep/issues/649):
Fix handling of `!**/` in `.gitignore`.
* [BUG #663](https://github.com/BurntSushi/ripgrep/issues/663):
**BREAKING CHANGE:** Support `[^...]` glob syntax (as identical to `[!...]`).
* [BUG #693](https://github.com/BurntSushi/ripgrep/issues/693):
Don't display context separators when not printing matches.
* [BUG #705](https://github.com/BurntSushi/ripgrep/issues/705):
Fix a bug that prevented ripgrep from searching OneDrive directories.
* [BUG #717](https://github.com/BurntSushi/ripgrep/issues/717):
Improve `--smart-case` uppercase character detection.
* [BUG #725](https://github.com/BurntSushi/ripgrep/issues/725):
Clarify that globs do not override explicitly given paths to search.
* [BUG #742](https://github.com/BurntSushi/ripgrep/pull/742):
Write ANSI reset code as `\x1B[0m` instead of `\x1B[m`.
* [BUG #747](https://github.com/BurntSushi/ripgrep/issues/747):
Remove `yarn.lock` from YAML file type.
* [BUG #760](https://github.com/BurntSushi/ripgrep/issues/760):
ripgrep can now search `/sys/devices/system/cpu/vulnerabilities/*` files.
* [BUG #761](https://github.com/BurntSushi/ripgrep/issues/761):
Fix handling of gitignore patterns that contain a `/`.
* [BUG #776](https://github.com/BurntSushi/ripgrep/pull/776):
**BREAKING CHANGE:** `--max-columns=0` now disables the limit.
* [BUG #779](https://github.com/BurntSushi/ripgrep/issues/779):
Clarify documentation for `--files-without-match`.
* [BUG #780](https://github.com/BurntSushi/ripgrep/issues/780),
[BUG #781](https://github.com/BurntSushi/ripgrep/issues/781):
Fix bug where ripgrep missed some matching lines.
Maintenance fixes:
* [MAINT #772](https://github.com/BurntSushi/ripgrep/pull/772):
Drop `env_logger` in favor of simpler logger to avoid many new dependencies.
* [MAINT #772](https://github.com/BurntSushi/ripgrep/pull/772):
Add git revision hash to ripgrep's version string.
* [MAINT #772](https://github.com/BurntSushi/ripgrep/pull/772):
(Seemingly) improve compile times.
* [MAINT #776](https://github.com/BurntSushi/ripgrep/pull/776):
Automatically generate man page during build.
* [MAINT #786](https://github.com/BurntSushi/ripgrep/pull/786):
Remove use of `unsafe` in `globset`. :tada:
* [MAINT e9d448](https://github.com/BurntSushi/ripgrep/commit/e9d448e93bb4e1fb3b0c1afc29adb5af6ed5283d):
Add an issue template (has already drastically improved bug reports).
* [MAINT ae2d03](https://github.com/BurntSushi/ripgrep/commit/ae2d036dd4ba2a46acac9c2d77c32e7c667eb850):
Remove the `compile` script.
Friends of ripgrep:
I'd like to extend my gratitude to
[@balajisivaraman](https://github.com/balajisivaraman)
for their recent hard work in a number of areas, and in particular, for
implementing the "search compressed files" feature. Their work in sketching out
a specification for that and other work has been exemplary.
Thanks
[@balajisivaraman](https://github.com/balajisivaraman)!
0.7.1 (2017-10-22)
==================
This is a patch release of ripgrep that includes a fix to very bad regression

194
Cargo.lock generated
View File

@@ -16,9 +16,9 @@ name = "atty"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -41,16 +41,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clap"
version = "2.29.0"
version = "2.29.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.9.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)",
]
[[package]]
@@ -60,21 +59,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "encoding_rs"
version = "0.7.1"
version = "0.7.2"
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)",
"simd 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "env_logger"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fnv"
version = "1.0.6"
@@ -82,16 +73,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "fuchsia-zircon"
version = "0.3.2"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fuchsia-zircon-sys"
version = "0.3.2"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -101,41 +92,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "globset"
version = "0.2.1"
version = "0.3.0"
dependencies = [
"aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "grep"
version = "0.1.7"
version = "0.1.8"
dependencies = [
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ignore"
version = "0.3.1"
version = "0.4.1"
dependencies = [
"crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"globset 0.2.1",
"globset 0.3.0",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"same-file 1.0.1 (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)",
"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)",
"walkdir 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.2 (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)",
]
[[package]]
@@ -145,20 +136,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.34"
version = "0.2.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "log"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "log"
version = "0.4.0"
version = "0.4.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)",
@@ -169,7 +152,7 @@ name = "memchr"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -177,8 +160,8 @@ name = "memmap"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -186,21 +169,32 @@ name = "num_cpus"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.3.19"
version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fuchsia-zircon 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.33"
version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -208,12 +202,12 @@ name = "redox_termios"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "0.2.4"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -231,34 +225,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ripgrep"
version = "0.7.1"
version = "0.8.0"
dependencies = [
"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)",
"clap 2.29.0 (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)",
"globset 0.2.1",
"grep 0.1.7",
"ignore 0.3.1",
"clap 2.29.4 (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",
"grep 0.1.8",
"ignore 0.4.1",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (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)",
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"memmap 0.6.2 (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.4 (registry+https://github.com/rust-lang/crates.io-index)",
"same-file 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 0.3.3",
"winapi 0.3.2 (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)",
"termcolor 0.3.4",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "same-file"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -268,7 +261,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "strsim"
version = "0.6.0"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -276,14 +269,14 @@ name = "tempdir"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termcolor"
version = "0.3.3"
version = "0.3.4"
dependencies = [
"wincolor 0.1.4",
"wincolor 0.1.6",
]
[[package]]
@@ -291,8 +284,8 @@ name = "termion"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -331,11 +324,6 @@ name = "utf8-ranges"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vec_map"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "void"
version = "1.0.2"
@@ -343,37 +331,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "walkdir"
version = "2.1.3"
version = "2.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"same-file 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi"
version = "0.3.2"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.3.2"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.3.2"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "wincolor"
version = "0.1.4"
version = "0.1.6"
dependencies = [
"winapi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[metadata]
@@ -383,29 +371,28 @@ dependencies = [
"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 cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
"checksum clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "110d43e343eb29f4f51c1db31beb879d546db27998577e5715270a54bcf41d3f"
"checksum clap 2.29.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7b8f59bcebcfe4269b09f71dab0da15b355c75916a8f975d3876ce81561893ee"
"checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19"
"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 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 fuchsia-zircon 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bd510087c325af53ba24f3be8f1c081b0982319adcb8b03cad764512923ccc19"
"checksum fuchsia-zircon-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "08b3a6f13ad6b96572b53ce7af74543132f1a7055ccceb6d073dd36c54481859"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
"checksum libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "36fbc8a8929c632868295d0178dd8f63fc423fd7537ad0738372bd010b3ac9b0"
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
"checksum log 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3a89a0c46ba789b8a247d4c567aed4d7c68e624672d238b45cc3ec20dc9f940"
"checksum libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "1e5d97d6708edaa407429faa671b942dc0f2727222fb6b6539bf1db936e4b121"
"checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2"
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
"checksum rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "9e7944d95d25ace8f377da3ac7068ce517e4c646754c43a1b1849177bbf72e59"
"checksum redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "07b8f011e3254d5a9b318fde596d409a0001c9ae4c6e7907520c2eaa4d988c99"
"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1"
"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum regex 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "42af8b40717e6a4dae0c00e09d65733e3c68aecfa865c3cc75ea1ed0e66d5149"
"checksum regex 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "5be5347bde0c48cfd8c3fdc0766cdfe9d8a755ef84d620d6794c778c91de8b2b"
"checksum regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e"
"checksum same-file 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3257af0472da4b8b8902102a57bafffd9991f0f43772a8af6153d597e6e4ae2"
"checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637"
"checksum simd 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd0805c7363ab51a829a1511ad24b6ed0349feaa756c4bc2f977f9f496e6673"
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
@@ -413,9 +400,8 @@ dependencies = [
"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 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b167e9a4420d8dddb260e70c90a4a375a1e5691f21f70e715553da87b6c2503a"
"checksum winapi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "890b38836c01d72fdb636d15c9cfc52ec7fd783b330abc93cd1686f4308dfccc"
"checksum winapi-i686-pc-windows-gnu 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ec6667f60c23eca65c561e63a13d81b44234c2e38a6b6c959025ee907ec614cc"
"checksum winapi-x86_64-pc-windows-gnu 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98f12c52b2630cd05d2c3ffd8e008f7f48252c042b4871c72aed9dc733b96668"
"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-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"

View File

@@ -1,6 +1,6 @@
[package]
name = "ripgrep"
version = "0.7.1" #:version
version = "0.8.0" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """
Line oriented search tool using Rust's regex library. Combines the raw
@@ -30,35 +30,42 @@ name = "integration"
path = "tests/tests.rs"
[workspace]
members = [ "grep", "globset", "ignore", "termcolor", "wincolor" ]
members = ["grep", "globset", "ignore", "termcolor", "wincolor"]
[dependencies]
atty = "0.2.2"
bytecount = "0.3.1"
clap = "2.26"
encoding_rs = "0.7"
env_logger = { version = "0.4", default-features = false }
grep = { version = "0.1.7", path = "grep" }
ignore = { version = "0.3.1", path = "ignore" }
globset = { version = "0.3.0", path = "globset" }
grep = { version = "0.1.8", path = "grep" }
ignore = { version = "0.4.0", path = "ignore" }
lazy_static = "1"
libc = "0.2"
log = "0.3"
log = "0.4"
memchr = "2"
memmap = "0.6"
num_cpus = "1"
regex = "0.2.4"
same-file = "1"
termcolor = { version = "0.3.3", path = "termcolor" }
globset = { version = "0.2.1", path = "globset" }
termcolor = { version = "0.3.4", path = "termcolor" }
[dependencies.clap]
version = "2.29.4"
default-features = false
features = ["suggestions", "color"]
[target.'cfg(windows)'.dependencies.winapi]
version = "0.3"
features = ["std", "winnt"]
[build-dependencies]
clap = "2.26"
lazy_static = "1"
[build-dependencies.clap]
version = "2.29.4"
default-features = false
features = ["suggestions", "color"]
[features]
avx-accel = ["bytecount/avx-accel"]
simd-accel = [

532
FAQ.md Normal file
View File

@@ -0,0 +1,532 @@
## FAQ
* [Does ripgrep support configuration files?](#config)
* [What's changed in ripgrep recently?](#changelog)
* [When is the next release?](#release)
* [Does ripgrep have a man page?](#manpage)
* [Does ripgrep have support for shell auto-completion?](#complete)
* [How do I use lookaround and/or backreferences?](#fancy)
* [How do I configure ripgrep's colors?](#colors)
* [How do I enable true colors on Windows?](#truecolors-windows)
* [How do I stop ripgrep from messing up colors when I kill it?](#stop-ripgrep)
* [How can I get results in a consistent order?](#order)
* [How do I search files that aren't UTF-8?](#encoding)
* [How do I search compressed files?](#compressed)
* [How do I search over multiple lines?](#multiline)
* [How do I get around the regex size limit?](#size-limit)
* [How do I make the `-f/--file` flag faster?](#dfa-size)
* [How do I make the output look like The Silver Searcher's output?](#silver-searcher-output)
* [When I run `rg`, why does it execute some other command?](#rg-other-cmd)
* [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 pipe non-ASCII content to ripgrep on Windows?](#pipe-non-ascii-windows)
* [Can ripgrep replace grep?](#posix4ever)
<h3 name="config">
Does ripgrep support configuration files?
</h3>
Yes. See the
[guide's section on configuration files](GUIDE.md#configuration-file).
<h3 name="changelog">
What's changed in ripgrep recently?
</h3>
Please consult ripgrep's [CHANGELOG](CHANGELOG.md).
<h3 name="release">
When is the next release?
</h3>
ripgrep is a project whose contributors are volunteers. A release schedule
adds undue stress to said volunteers. Therefore, releases are made on a best
effort basis and no dates **will ever be given**.
One exception to this is high impact bugs. If a ripgrep release contains a
significant regression, then there will generally be a strong push to get a
patch release out with a fix.
<h3 name="manpage">
Does ripgrep have a man page?
</h3>
Yes! Whenever ripgrep is compiled on a system with `asciidoc` present, then a
man page is generated from ripgrep's argv parser. After compiling ripgrep, you
can find the man page like so from the root of the repository:
```
$ find ./target -name rg.1 -print0 | xargs -0 ls -t | head -n1
./target/debug/build/ripgrep-79899d0edd4129ca/out/rg.1
```
Running `man -l ./target/debug/build/ripgrep-79899d0edd4129ca/out/rg.1` will
show the man page in your normal pager.
Note that the man page's documentation for options is equivalent to the output
shown in `rg --help`. To see more condensed documentation (one line per flag),
run `rg -h`.
The man page is also included in all
[ripgrep binary releases](https://github.com/BurntSushi/ripgrep/releases).
<h3 name="complete">
Does ripgrep have support for shell auto-completion?
</h3>
Yes! Shell completions can be found in the
[same directory as the man page](#manpage)
after building ripgrep. Zsh completions are maintained separately and committed
to the repository in `complete/_rg`.
Shell completions are also included in all
[ripgrep binary releases](https://github.com/BurntSushi/ripgrep/releases).
For **bash**, move `rg.bash` to
`$XDG_CONFIG_HOME/bash_completion` or `/etc/bash_completion.d/`.
For **fish**, move `rg.fish` to `$HOME/.config/fish/completions/`.
For **zsh**, move `_rg` to one of your `$fpath` directories.
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.
<h3 name="order">
How can I get results in a consistent order?
</h3>
By default, ripgrep uses parallelism to execute its search because this makes
the search much faster on most modern systems. This in turn means that ripgrep
has a non-deterministic aspect to it, since the interleaving of threads during
the execution of the program is itself non-deterministic. This has the effect
of printing results in a somewhat arbitrary order, and this order can change
from run to run of ripgrep.
The only way to make the order of results consistent is to ask ripgrep to
sort the output. Currently, this will disable all parallelism. (On smaller
repositories, you might not notice much of a performance difference!) You
can achieve this with the `--sort-files` flag.
There is more discussion on this topic here:
https://github.com/BurntSushi/ripgrep/issues/152
<h3 name="encoding">
How do I search files that aren't UTF-8?
</h3>
See the [guide's section on file encoding](GUIDE.md#file-encoding).
<h3 name="compressed">
How do I search compressed files?
</h3>
ripgrep's `-z/--search-zip` flag will cause it to search compressed files
automatically. Currently, this supports gzip, bzip2, lzma and xz only and
requires the corresponding `gzip`, `bzip2` and `xz` binaries to be installed on
your system. (That is, ripgrep does decompression by shelling out to another
process.)
ripgrep currently does not search archive formats, so `*.tar.gz` files, for
example, are skipped.
<h3 name="multiline">
How do I search over multiple lines?
</h3>
This isn't currently possible. ripgrep is fundamentally a line-oriented search
tool. With that said,
[multiline search is a planned opt-in feature](https://github.com/BurntSushi/ripgrep/issues/176).
<h3 name="fancy">
How do I use lookaround and/or backreferences?
</h3>
This isn't currently possible. ripgrep uses finite automata to implement
regular expression search, and in turn, guarantees linear time searching on all
inputs. It is difficult to efficiently support lookaround and backreferences in
finite automata engines, so ripgrep does not provide these features.
If a production quality regular expression engine with these features is ever
written in Rust, then it is possible ripgrep will provide it as an opt-in
feature.
<h3 name="colors">
How do I configure ripgrep's colors?
</h3>
ripgrep has two flags related to colors:
* `--color` controls *when* to use colors.
* `--colors` controls *which* colors to use.
The `--color` flag accepts one of the following possible values: `never`,
`auto`, `always` or `ansi`. The `auto` value is the default and will cause
ripgrep to only enable colors when it is printing to a terminal. But if you
pipe ripgrep to a file or some other process, then it will suppress colors.
The --colors` flag is a bit more complicated. The general format is:
```
--colors '{type}:{attribute}:{value}'
```
* `{type}` should be one of `path`, `line`, `column` or `match`. Each of these
correspond to the four different types of things that ripgrep will add color
to in its output. Select the type whose color you want to change.
* `{attribute}` should be one of `fg`, `bg` or `style`, corresponding to
foreground color, background color, or miscellaneous styling (such as whether
to bold the output or not).
* `{value}` is determined by the value of `{attribute}`. If
`{attribute}` is `style`, then `{value}` should be one of `nobold`,
`bold`, `nointense`, `intense`, `nounderline` or `underline`. If
`{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
number or an RGB triple (with over 16 million possible values, or "true
color").
The color names are `red`, `blue`, `green`, `cyan`, `magenta`, `yellow`,
`white` or `black`.
A single 256-bit number is a value in the range 0-255 (inclusive). It can
either be in decimal format (e.g., `62`) or hexadecimal format (e.g., `0x3E`).
An RGB triple corresponds to three numbers (decimal or hexadecimal) separated
by commas.
As a special case, `--colors '{type}:none'` will clear all colors and styles
associated with `{type}`, which lets you start with a clean slate (instead of
building on top of ripgrep's default color settings).
Here's an example that makes highlights the matches with a nice blue background
with bolded white text:
```
$ rg somepattern \
--colors 'match:none' \
--colors 'match:bg:0x33,0x66,0xFF' \
--colors 'match:fg:white' \
--colors 'match:style:bold'
```
Colors are an ideal candidate to set in your
[configuration file](GUIDE.md#configuration-file). See the
[question on emulating The Silver Searcher's output style](#silver-searcher-output)
for an example specific to colors.
<h3 name="truecolors-windows">
How do I enable true colors on Windows?
</h3>
First, see the previous question's
[answer on configuring colors](#colors).
Secondly, coloring on Windows is a bit complicated. If you're using a terminal
like Cygwin, then it's likely true color support already works out of the box.
However, if you are using a normal Windows console (`cmd` or `PowerShell`) and
a version of Windows prior to 10, then there is no known way to get true
color support. If you are on Windows 10 and using a Windows console, then
true colors should work out of the box with one caveat: you might need to
clear ripgrep's default color settings first. That is, instead of this:
```
$ rg somepattern --colors 'match:fg:0x33,0x66,0xFF'
```
you should do this
```
$ rg somepattern --colors 'match:none' --colors 'match:fg:0x33,0x66,0xFF'
```
This is because ripgrep might set the default style for `match` to `bold`, and
it seems like Windows 10's VT100 support doesn't permit bold and true color
ANSI escapes to be used simultaneously. The work-around above will clear
ripgrep's default styling, allowing you to craft it exactly as desired.
<h3 name="stop-ripgrep">
How do I stop ripgrep from messing up colors when I kill it?
</h3>
Type in `color` in cmd.exe (Command Prompt) and `echo -ne "\033[0m"` on
Unix-like systems to restore your original foreground color.
In PowerShell, you can add the following code to your profile which will
restore the original foreground color when `Reset-ForegroundColor` is called.
Including the `Set-Alias` line will allow you to call it with simply `color`.
```powershell
$OrigFgColor = $Host.UI.RawUI.ForegroundColor
function Reset-ForegroundColor {
$Host.UI.RawUI.ForegroundColor = $OrigFgColor
}
Set-Alias -Name color -Value Reset-ForegroundColor
```
PR [#187](https://github.com/BurntSushi/ripgrep/pull/187) fixed this, and it
was later deprecated in
[#281](https://github.com/BurntSushi/ripgrep/issues/281). A full explanation is
available
[here](https://github.com/BurntSushi/ripgrep/issues/281#issuecomment-269093893).
<h3 name="size-limit">
How do I get around the regex size limit?
</h3>
If you've given ripgrep a particularly large pattern (or a large number of
smaller patterns), then it is possible that it will fail to compile because it
hit a pre-set limit. For example:
```
$ rg '\pL{1000}'
Compiled regex exceeds size limit of 10485760 bytes.
```
(Note: `\pL{1000}` may look small, but `\pL` is the character class containing
all Unicode letters, which is quite large. *And* it's repeated 1000 times.)
In this case, you can work around by simply increasing the limit:
```
$ rg '\pL{1000}' --regex-size-limit 1G
```
Increasing the limit to 1GB does not necessarily mean that ripgrep will use
that much memory. The limit just says that it's allowed to (approximately) use
that much memory for constructing the regular expression.
<h3 name="dfa-size">
How do I make the <code>-f/--file</code> flag faster?
</h3>
The `-f/--file` permits one to give a file to ripgrep which contains a pattern
on each line. ripgrep will then report any line that matches any of the
patterns.
If this pattern file gets too big, then it is possible ripgrep will slow down
dramatically. *Typically* this is because an internal cache is too small, and
will cause ripgrep to spill over to a slower but more robust regular expression
engine. If this is indeed the problem, then it is possible to increase this
cache and regain speed. The cache can be controlled via the `--dfa-size-limit`
flag. For example, using `--dfa-size-limit 1G` will set the cache size to 1GB.
(Note that this doesn't mean ripgrep will use 1GB of memory automatically, but
it will allow the regex engine to if it needs to.)
<h3 name="silver-searcher-output">
How do I make the output look like The Silver Searcher's output?
</h3>
Use the `--colors` flag, like so:
```
rg --colors line:fg:yellow \
--colors line:style:bold \
--colors path:fg:green \
--colors path:style:bold \
--colors match:fg:black \
--colors match:bg:yellow \
--colors match:style:nobold \
foo
```
Alternatively, add your color configuration to your ripgrep config file (which
is activated by setting the `RIPGREP_CONFIG_PATH` environment variable to point
to your config file). For example:
```
$ cat $HOME/.config/ripgrep/rc
--colors=line:fg:yellow
--colors=line:style:bold
--colors=path:fg:green
--colors=path:style:bold
--colors=match:fg:black
--colors=match:bg:yellow
--colors=match:style:nobold
$ RIPGREP_CONFIG_PATH=$HOME/.config/ripgrep/rc rg foo
```
<h3 name="rg-other-cmd">
When I run <code>rg</code>, why does it execute some other command?
</h3>
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'`.
<h3 name="rg-alias-windows">
How do I create an alias for ripgrep on Windows?
</h3>
Often you can find a need to make alias for commands you use a lot that set
certain flags. But PowerShell function aliases do not behave like your typical
linux shell alias. You always need to propagate arguments and `stdin` input.
But it cannot be done simply as
`function grep() { $input | rg.exe --hidden $args }`
Use below example as reference to how setup alias in PowerShell.
```powershell
function grep {
$count = @($input).Count
$input.Reset()
if ($count) {
$input | rg.exe --hidden $args
}
else {
rg.exe --hidden $args
}
}
```
PowerShell special variables:
* input - is powershell `stdin` object that allows you to access its content.
* args - is array of arguments passed to this function.
This alias checks whether there is `stdin` input and propagates only if there
is some lines. Otherwise empty `$input` will make powershell to trigger `rg` to
search empty `stdin`.
<h3 name="powershell-profile">
How do I create a PowerShell profile?
</h3>
To customize powershell on start-up, there is a special PowerShell script that
has to be created. In order to find its location, type `$profile`.
See
[Microsoft's documentation](https://technet.microsoft.com/en-us/library/bb613488(v=vs.85).aspx)
for more details.
Any PowerShell code in this file gets evaluated at the start of console. This
way you can have own aliases to be created at start.
<h3 name="pipe-non-ascii-windows">
How do I pipe non-ASCII content to ripgrep on Windows?
</h3>
When piping input into native executables in PowerShell, the encoding of the
input is controlled by the `$OutputEncoding` variable. By default, this is set
to US-ASCII, and any characters in the pipeline that don't have encodings in
US-ASCII are converted to `?` (question mark) characters.
To change this setting, set `$OutputEncoding` to a different encoding, as
represented by a .NET encoding object. Some common examples are below. The
value of this variable is reset when PowerShell restarts, so to make this
change take effect every time PowerShell is started add a line setting the
variable into your PowerShell profile.
Example `$OutputEncoding` settings:
* UTF-8 without BOM: `$OutputEncoding = [System.Text.UTF8Encoding]::new()`
* The console's output encoding:
`$OutputEncoding = [System.Console]::OutputEncoding`
If you continue to have encoding problems, you can also force the encoding
that the console will use for printing to UTF-8 with
`[System.Console]::OutputEncoding = [System.Text.Encoding]::UTF8`. This
will also reset when PowerShell is restarted, so you can add that line
to your profile as well if you want to make the setting permanent.
<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.

680
GUIDE.md Normal file
View File

@@ -0,0 +1,680 @@
## User Guide
This guide is intended to give an elementary description of ripgrep and an
overview of its capabilities. This guide assumes that ripgrep is
[installed](README.md#installation)
and that readers have passing familiarity with using command line tools. This
also assumes a Unix-like system, although most commands are probably easily
translatable to any command line shell environment.
### Table of Contents
* [Basics](#basics)
* [Recursive search](#recursive-search)
* [Automatic filtering](#automatic-filtering)
* [Manual filtering: globs](#manual-filtering-globs)
* [Manual filtering: file types](#manual-filtering-file-types)
* [Replacements](#replacements)
* [Configuration file](#configuration-file)
* [File encoding](#file-encoding)
* [Common options](#common-options)
### Basics
ripgrep is a command line tool that searches your files for patterns that
you give it. ripgrep behaves as if reading each file line by line. If a line
matches the pattern provided to ripgrep, then that line will be printed. If a
line does not match the pattern, then the line is not printed.
The best way to see how this works is with an example. To show an example, we
need something to search. Let's try searching ripgrep's source code. First
grab a ripgrep source archive from
https://github.com/BurntSushi/ripgrep/archive/0.7.1.zip
and extract it:
```
$ curl -LO https://github.com/BurntSushi/ripgrep/archive/0.7.1.zip
$ unzip 0.7.1.zip
$ cd ripgrep-0.7.1
$ ls
benchsuite grep tests Cargo.toml LICENSE-MIT
ci ignore wincolor CHANGELOG.md README.md
complete pkg appveyor.yml compile snapcraft.yaml
doc src build.rs COPYING UNLICENSE
globset termcolor Cargo.lock HomebrewFormula
```
Let's try our first search by looking for all occurrences of the word `fast`
in `README.md`:
```
$ rg fast README.md
75: faster than both. (N.B. It is not, strictly speaking, a "drop-in" replacement
88: color and full Unicode support. Unlike GNU grep, `ripgrep` stays fast while
119:### Is it really faster than everything else?
124:Summarizing, `ripgrep` is fast because:
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
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
colors, then your output might actually look something like this screenshot:
[![A screenshot of a sample search ripgrep](https://burntsushi.net/stuff/ripgrep-guide-sample.png)](https://burntsushi.net/stuff/ripgrep-guide-sample.png)
In this example, we searched for something called a "literal" string. This
means that our pattern was just some normal text that we asked ripgrep to
find. But ripgrep supports the ability to specify patterns via [regular
expressions](https://en.wikipedia.org/wiki/Regular_expression). As an example,
what if we wanted to find all lines have a word that contains `fast` followed
by some number of other letters?
```
$ rg 'fast\w+' README.md
75: faster than both. (N.B. It is not, strictly speaking, a "drop-in" replacement
119:### Is it really faster than everything else?
```
In this example, we used the pattern `fast\w+`. This pattern tells ripgrep to
look for any lines containing the letters `fast` followed by *one or more*
word-like characters. Namely, `\w` matches characters that compose words (like
`a` and `L` but unlike `.` and ` `). The `+` after the `\w` means, "match the
previous pattern one or more times." This means that the word `fast` won't
match because there are no word characters following the final `t`. But a word
like `faster` will. `faste` would also match!
Here's a different variation on this same theme:
```
$ rg 'fast\w*' README.md
75: faster than both. (N.B. It is not, strictly speaking, a "drop-in" replacement
88: color and full Unicode support. Unlike GNU grep, `ripgrep` stays fast while
119:### Is it really faster than everything else?
124:Summarizing, `ripgrep` is fast because:
129: optimizations to make searching very fast.
```
In this case, we used `fast\w*` for our pattern instead of `fast\w+`. The `*`
means that it should match *zero* or more times. In this case, ripgrep will
print the same lines as the pattern `fast`, but if your terminal supports
colors, you'll notice that `faster` will be highlighted instead of just the
`fast` prefix.
It is beyond the scope of this guide to provide a full tutorial on regular
expressions, but ripgrep's specific syntax is documented here:
https://docs.rs/regex/0.2.5/regex/#syntax
### Recursive search
In the previous section, we showed how to use ripgrep to search a single file.
In this section, we'll show how to use ripgrep to search an entire directory
of files. In fact, *recursively* searching your current working directory is
the default mode of operation for ripgrep, which means doing this is very
simple.
Using our unzipped archive of ripgrep source code, here's how to find all
function definitions whose name is `write`:
```
$ rg 'fn write\('
src/printer.rs
469: fn write(&mut self, buf: &[u8]) {
termcolor/src/lib.rs
227: fn write(&mut self, b: &[u8]) -> io::Result<usize> {
250: fn write(&mut self, b: &[u8]) -> io::Result<usize> {
428: fn write(&mut self, b: &[u8]) -> io::Result<usize> { self.wtr.write(b) }
441: fn write(&mut self, b: &[u8]) -> io::Result<usize> { self.wtr.write(b) }
454: fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
511: fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
848: fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
915: fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
949: fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1114: fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1348: fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1353: fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
```
(**Note:** We escape the `(` here because `(` has special significance inside
regular expressions. You could also use `rg -F 'fn write('` to achieve the
same thing, where `-F` interprets your pattern as a literal string instead of
a regular expression.)
In this example, we didn't specify a file at all. Instead, ripgrep defaulted
to searching your current directory in the absence of a path. In general,
`rg foo` is equivalent to `rg foo ./`.
This particular search showed us results in both the `src` and `termcolor`
directories. The `src` directory is the core ripgrep code where as `termcolor`
is a dependency of ripgrep (and is used by other tools). What if we only wanted
to search core ripgrep code? Well, that's easy, just specify the directory you
want:
```
$ rg 'fn write\(' src
src/printer.rs
469: fn write(&mut self, buf: &[u8]) {
```
Here, ripgrep limited its search to the `src` directory. Another way of doing
this search would be to `cd` into the `src` directory and simply use `rg 'fn
write\('` again.
### Automatic filtering
After recursive search, ripgrep's most important feature is what it *doesn't*
search. By default, when you search a directory, ripgrep will ignore all of
the following:
1. Files and directories that match the rules in your `.gitignore` glob
pattern.
2. Hidden files and directories.
3. Binary files. (ripgrep considers any file with a `NUL` byte to be binary.)
4. Symbolic links aren't followed.
All of these things can be toggled using various flags provided by ripgrep:
1. You can disable `.gitignore` handling with the `--no-ignore` flag.
2. Hidden files and directories can be searched with the `--hidden` flag.
3. Binary files can be searched via the `--text` (`-a` for short) flag.
Be careful with this flag! Binary files may emit control characters to your
terminal, which might cause strange behavior.
4. ripgrep can follow symlinks with the `--follow` (`-L` for short) flag.
As a special convenience, ripgrep also provides a flag called `--unrestricted`
(`-u` for short). Repeated uses of this flag will cause ripgrep to disable
more and more of its filtering. That is, `-u` will disable `.gitignore`
handling, `-uu` will search hidden files and directories and `-uuu` will search
binary files. This is useful when you're using ripgrep and you aren't sure
whether its filtering is hiding results from you. Tacking on a couple `-u`
flags is a quick way to find out. (Use the `--debug` flag if you're still
perplexed, and if that doesn't help,
[file an issue](https://github.com/BurntSushi/ripgrep/issues/new).)
ripgrep's `.gitignore` handling actually goes a bit beyond just `.gitignore`
files. ripgrep will also respect repository specific rules found in
`$GIT_DIR/info/exclude`, as well as any global ignore rules in your
`core.excludesFile` (which is usually `$XDG_CONFIG_HOME/git/ignore` on
Unix-like systems).
Sometimes you want to search files that are in your `.gitignore`, so it is
possible to specify additional ignore rules or overrides in a `.ignore`
(application agnostic) or `.rgignore` (ripgrep specific) file.
For example, let's say you have a `.gitignore` file that looks like this:
```
log/
```
This generally means that any `log` directory won't be tracked by `git`.
However, perhaps it contains useful output that you'd like to include in your
searches, but you still don't want to track it in `git`. You can achieve this
by creating a `.ignore` file in the same directory as the `.gitignore` file
with the following contents:
```
!log/
```
ripgrep treats `.ignore` files with higher precedence than `.gitignore` files
(and treats `.rgignore` files with higher precdence than `.ignore` files).
This means ripgrep will see the `!log/` whitelist rule first and search that
directory.
Like `.gitignore`, a `.ignore` file can be placed in any directory. Its rules
will be processed with respect to the directory it resides in, just like
`.gitignore`.
For a more in depth description of how glob patterns in a `.gitignore` file
are interpreted, please see `man gitignore`.
### Manual filtering: globs
In the previous section, we talked about ripgrep's filtering that it does by
default. It is "automatic" because it reacts to your environment. That is, it
uses already existing `.gitignore` files to produce more relevant search
results.
In addition to automatic filtering, ripgrep also provides more manual or ad hoc
filtering. This comes in two varieties: additional glob patterns specified in
your ripgrep commands and file type filtering. This section covers glob
patterns while the next section covers file type filtering.
In our ripgrep source code (see [Basics](#basics) for instructions on how to
get a source archive to search), let's say we wanted to see which things depend
on `clap`, our argument parser.
We could do this:
```
$ rg clap
[lots of results]
```
But this shows us many things, and we're only interested in where we wrote
`clap` as a dependency. Instead, we could limit ourselves to TOML files, which
is how dependencies are communicated to Rust's build tool, Cargo:
```
$ rg clap -g '*.toml'
Cargo.toml
35:clap = "2.26"
51:clap = "2.26"
```
The `-g '*.toml'` syntax says, "make sure every file searched matches this
glob pattern." Note that we put `'*.toml'` in single quotes to prevent our
shell from expanding the `*`.
If we wanted, we could tell ripgrep to search anything *but* `*.toml` files:
```
$ rg clap -g '!*.toml'
[lots of results]
```
This will give you a lot of results again as above, but they won't include
files ending with `.toml`. Note that the use of a `!` here to mean "negation"
is a bit non-standard, but it was chosen to be consistent with how globs in
`.gitignore` files are written. (Although, the meaning is reversed. In
`.gitignore` files, a `!` prefix means whitelist, and on the command line, a
`!` means blacklist.)
Globs are interpreted in exactly the same way as `.gitignore` patterns. That
is, later globs will override earlier globs. For example, the following command
will search only `*.toml` files:
```
$ rg clap -g '!*.toml' -g '*.toml'
```
Interestingly, reversing the order of the globs in this case will match
nothing, since the presence of at least one non-blacklist glob will institute a
requirement that every file searched must match at least one glob. In this
case, the blacklist glob takes precedence over the previous glob and prevents
any file from being searched at all!
### Manual filtering: file types
Over time, you might notice that you use the same glob patterns over and over.
For example, you might find yourself doing a lot of searches where you only
want to see results for Rust files:
```
$ rg 'fn run' -g '*.rs'
```
Instead of writing out the glob every time, you can use ripgrep's support for
file types:
```
$ rg 'fn run' --type rust
```
or, more succinctly,
```
$ rg 'fn run' -trust
```
The way the `--type` flag functions is simple. It acts as a name that is
assigned to one or more globs that match the relevant files. This lets you
write a single type that might encompass a broad range of file extensions. For
example, if you wanted to search C files, you'd have to check both C source
files and C header files:
```
$ rg 'int main' -g '*.{c,h}'
```
or you could just use the C file type:
```
$ rg 'int main' -tc
```
Just as you can write blacklist globs, you can blacklist file types too:
```
$ rg clap --type-not rust
```
or, more succinctly,
```
$ rg clap -Trust
```
That is, `-t` means "include files of this type" where as `-T` means "exclude
files of this type."
To see the globs that make up a type, run `rg --type-list`:
```
$ rg --type-list | rg '^make:'
make: *.mak, *.mk, GNUmakefile, Gnumakefile, Makefile, gnumakefile, makefile
```
By default, ripgrep comes with a bunch of pre-defined types. Generally, these
types correspond to well known public formats. But you can define your own
types as well. For example, perhaps you frequently search "web" files, which
consist of Javascript, HTML and CSS:
```
$ rg --type-add 'web:*.html' --type-add 'web:*.css' --type-add 'web:*.js' -tweb title
```
or, more succinctly,
```
$ rg --type-add 'web:*.{html,css,js}' -tweb title
```
The above command defines a new type, `web`, corresponding to the glob
`*.{html,css,js}`. It then applies the new filter with `-tweb` and searches for
the pattern `title`. If you ran
```
$ rg --type-add 'web:*.{html,css,js}' --type-list
```
Then you would see your `web` type show up in the list, even though it is not
part of ripgrep's built-in types.
It is important to stress here that the `--type-add` flag only applies to the
current command. It does not add a new file type and save it somewhere in a
persistent form. If you want a type to be available in every ripgrep command,
then you should either create a shell alias:
```
alias rg="rg --type-add 'web:*.{html,css,js}'"
```
or add `--type-add=web:*.{html,css,js}` to your ripgrep configuration file.
([Configuration files](#configuration-file) are covered in more detail later.)
### Replacements
ripgrep provides a limited ability to modify its output by replacing matched
text with some other text. This is easiest to explain with an example. Remember
when we searched for the word `fast` in ripgrep's README?
```
$ rg fast README.md
75: faster than both. (N.B. It is not, strictly speaking, a "drop-in" replacement
88: color and full Unicode support. Unlike GNU grep, `ripgrep` stays fast while
119:### Is it really faster than everything else?
124:Summarizing, `ripgrep` is fast because:
129: optimizations to make searching very fast.
```
What if we wanted to *replace* all occurrences of `fast` with `FAST`? That's
easy with ripgrep's `--replace` flag:
```
$ rg fast README.md --replace FAST
75: FASTer than both. (N.B. It is not, strictly speaking, a "drop-in" replacement
88: color and full Unicode support. Unlike GNU grep, `ripgrep` stays FAST while
119:### Is it really FASTer than everything else?
124:Summarizing, `ripgrep` is FAST because:
129: optimizations to make searching very FAST.
```
or, more succinctly,
```
$ rg fast README.md -r FAST
[snip]
```
In essence, the `--replace` flag applies *only* to the matching portion of text
in the output. If you instead wanted to replace an entire line of text, then
you need to include the entire line in your match. For example:
```
$ rg '^.*fast.*$' README.md -r FAST
75:FAST
88:FAST
119:FAST
124:FAST
129:FAST
```
Alternatively, you can combine the `--only-matching` (or `-o` for short) with
the `--replace` flag to achieve the same result:
```
$ rg fast README.md --only-matching --replace FAST
75:FAST
88:FAST
119:FAST
124:FAST
129:FAST
```
or, more succinctly,
```
$ rg fast README.md -or FAST
[snip]
```
Finally, replacements can include capturing groups. For example, let's say
we wanted to find all occurrences of `fast` followed by another word and
join them together with a dash. The pattern we might use for that is
`fast\s+(\w+)`, which matches `fast`, followed by any amount of whitespace,
followed by any number of "word" characters. We put the `\w+` in a "capturing
group" (indicated by parentheses) so that we can reference it later in our
replacement string. For example:
```
$ rg 'fast\s+(\w+)' README.md -r 'fast-$1'
88: color and full Unicode support. Unlike GNU grep, `ripgrep` stays fast-while
124:Summarizing, `ripgrep` is fast-because:
```
Our replacement string here, `fast-$1`, consists of `fast-` followed by the
contents of the capturing group at index `1`. (Capturing groups actually start
at index 0, but the `0`th capturing group always corresponds to the entire
match. The capturing group at index `1` always corresponds to the first
explicit capturing group found in the regex pattern.)
Capturing groups can also be named, which is sometimes more convenient than
using the indices. For example, the following command is equivalent to the
above command:
```
$ rg 'fast\s+(?P<word>\w+)' README.md -r 'fast-$word'
88: color and full Unicode support. Unlike GNU grep, `ripgrep` stays fast-while
124:Summarizing, `ripgrep` is fast-because:
```
It is important to note that ripgrep **will never modify your files**. The
`--replace` flag only controls ripgrep's output. (And there is no flag to let
you do a replacement in a file.)
### Configuration file
It is possible that ripgrep's default options aren't suitable in every case.
For that reason, and because shell aliases aren't always convenient, ripgrep
supports configuration files.
Setting up a configuration file is simple. ripgrep will not look in any
predetermined directory for a config file automatically. Instead, you need to
set the `RIPGREP_CONFIG_PATH` environment variable to the file path of your
config file. Once the environment variable is set, open the file and just type
in the flags you want set automatically. There are only two rules for
describing the format of the config file:
1. Every line is a shell argument, after trimming ASCII whitespace.
2. Lines starting with `#` (optionally preceded by any amount of
ASCII whitespace) are ignored.
In particular, there is no escaping. Each line is given to ripgrep as a single
command line argument verbatim.
Here's an example of a configuration file, which demonstrates some of the
formatting peculiarities:
```
$ cat $HOME/.ripgreprc
# Don't let ripgrep vomit really long lines to my terminal.
--max-columns=150
# Add my 'web' type.
--type-add
web:*.{html,css,js}*
# Set the colors.
--colors=line:none
--colors=line:style:bold
# Because who cares about case!?
--smart-case
```
When we use a flag that has a value, we either put the flag and the value on
the same line but delimited by an `=` sign (e.g., `--max-columns=150`), or we
put the flag and the value on two different lines. This is because ripgrep's
argument parser knows to treat the single argument `--max-columns=150` as a
flag with a value, but if we had written `--max-columns 150` in our
configuration file, then ripgrep's argument parser wouldn't know what to do
with it.
Putting the flag and value on different lines is exactly equivalent and is a
matter of style.
Comments are encouraged so that you remember what the config is doing. Empty
lines are OK too.
So let's say you're using the above configuration file, but while you're at a
terminal, you really want to be able to see lines longer than 150 columns. What
do you do? Thankfully, all you need to do is pass `--max-columns 0` (or `-M0`
for short) on the command line, which will override your configuration file's
setting. This works because ripgrep's configuration file is *prepended* to the
explicit arguments you give it on the command line. Since flags given later
override flags given earlier, everything works as expected. This works for most
other flags as well, and each flag's documentation states which other flags
override it.
If you're confused about what configuration file ripgrep is reading arguments
from, then running ripgrep with the `--debug` flag should help clarify things.
The debug output should note what config file is being loaded and the arugments
that have been read from the configuration.
Finally, if you want to make absolutely sure that ripgrep *isn't* reading a
configuration file, then you can pass the `--no-config` flag, which will always
prevent ripgrep from reading extraneous configuration from the environment,
regardless of what other methods of configuration are added to ripgrep in the
future.
### File encoding
[Text encoding](https://en.wikipedia.org/wiki/Character_encoding) is a complex
topic, but we can try to summarize its relevancy to ripgrep:
* Files are generally just a bundle of bytes. There is no reliable way to know
their encoding.
* Either the encoding of the pattern must match the encoding of the files being
searched, or a form of transcoding must be performed converts either the
pattern or the file to the same encoding as the other.
* ripgrep tends to work best on plain text files, and among plain text files,
the most popular encodings likely consist of ASCII, latin1 or UTF-8. As
a special exception, UTF-16 is prevalent in Windows environments
In light of the above, here is how ripgrep behaves:
* All input is assumed to be ASCII compatible (which means every byte that
corresponds to an ASCII codepoint actually is an ASCII codepoint). This
includes ASCII itself, latin1 and UTF-8.
* ripgrep works best with UTF-8. For example, ripgrep's regular expression
engine supports Unicode features. Namely, character classes like `\w` will
match all word characters by Unicode's definition and `.` will match any
Unicode codepoint instead of any byte. These constructions assume UTF-8,
so they simply won't match when they come across bytes in a file that aren't
UTF-8.
* To handle the UTF-16 case, ripgrep will do something called "BOM sniffing"
by default. That is, the first three bytes of a file will be read, and if
they correspond to a UTF-16 BOM, then ripgrep will transcode the contents of
the file from UTF-16 to UTF-8, and then execute the search on the transcoded
version of the file. (This incurs a performance penalty since transcoding
is slower than regex searching.)
* To handle other cases, ripgrep provides a `-E/--encoding` flag, which permits
you to specify an encoding from the
[Encoding Standard](https://encoding.spec.whatwg.org/#concept-encoding-get).
ripgrep will assume *all* files searched are the encoding specified and
will perform a transcoding step just like in the UTF-16 case described above.
By default, ripgrep will not require its input be valid UTF-8. That is, ripgrep
can and will search arbitrary bytes. The key here is that if you're searching
content that isn't UTF-8, then the usefulness of your pattern will degrade. If
you're searching bytes that aren't ASCII compatible, then it's likely the
pattern won't find anything. With all that said, this mode of operation is
important, because it lets you find ASCII or UTF-8 *within* files that are
otherwise arbitrary bytes.
Finally, it is possible to disable ripgrep's Unicode support from within the
pattern regular expression. For example, let's say you wanted `.` to match any
byte rather than any Unicode codepoint. (You might want this while searching a
binary file, since `.` by default will not match invalid UTF-8.) You could do
this by disabling Unicode via a regular expression flag:
```
$ rg '(?-u:.)'
```
This works for any part of the pattern. For example, the following will find
any Unicode word character followed by any ASCII word character followed by
another Unicode word character:
```
$ rg '\w(?-u:\w)\w'
```
### Common options
ripgrep has a lot of flags. Too many to keep in your head at once. This section
is intended to give you a sampling of some of the most important and frequently
used options that will likely impact how you use ripgrep on a regular basis.
* `-h`: Show ripgrep's condensed help output.
* `--help`: Show ripgrep's longer form help output. (Nearly what you'd find in
ripgrep's man page, so pipe it into a pager!)
* `-i/--ignore-case`: When searching for a pattern, ignore case differences.
That is `rg -i fast` matches `fast`, `fASt`, `FAST`, etc.
* `-S/--smart-case`: This is similar to `--ignore-case`, but disables itself
if the pattern contains any uppercase letters. Usually this flag is put into
alias or a config file.
* `-w/--word-regexp`: Require that all matches of the pattern be surrounded
by word boundaries. That is, given `pattern`, the `--word-regexp` flag will
cause ripgrep to behave as if `pattern` were actually `\b(?:pattern)\b`.
* `-c/--count`: Report a count of total matched lines.
* `--files`: Print the files that ripgrep *would* search, but don't actually
search them.
* `-a/--text`: Search binary files as if they were plain text.
* `-z/--search-zip`: Search compressed files (gzip, bzip2, lzma, xz). This is
disabled by default.
* `-C/--context`: Show the lines surrounding a match.
* `--sort-files`: Force ripgrep to sort its output by file name. (This disables
parallelism, so it might be slower.)
* `-L/--follow`: Follow symbolic links while recursively searching.
* `-M/--max-columns`: Limit the length of lines printed by ripgrep.
* `--debug`: Shows ripgrep's debug output. This is useful for understanding
why a particular file might be ignored from search, or what kinds of
configuration ripgrep is loading from the environment.

408
README.md
View File

@@ -1,11 +1,11 @@
ripgrep (rg)
------------
`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).
ripgrep is a line-oriented search tool that recursively searches your current
directory for a regex pattern while respecting your gitignore rules. ripgrep
has first class support on Windows, macOS and Linux, with binary downloads
available for [every release](https://github.com/BurntSushi/ripgrep/releases).
ripgrep is similar to other popular search tools like The Silver Searcher,
ack and grep.
[![Linux build status](https://travis-ci.org/BurntSushi/ripgrep.svg?branch=master)](https://travis-ci.org/BurntSushi/ripgrep)
[![Windows build status](https://ci.appveyor.com/api/projects/status/github/BurntSushi/ripgrep?svg=true)](https://ci.appveyor.com/project/BurntSushi/ripgrep)
@@ -13,23 +13,36 @@ Windows, macOS and Linux, with binary downloads available for
Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org).
### CHANGELOG
Please see the [CHANGELOG](CHANGELOG.md) for a release history.
### Documentation quick links
* [Installation](#installation)
* [User Guide](GUIDE.md)
* [Frequently Asked Questions](FAQ.md)
* [Regex syntax](https://docs.rs/regex/0.2.5/regex/#syntax)
* [Configuration files](GUIDE.md#configuration-file)
* [Shell completions](FAQ.md#complete)
* [Building](#building)
### Screenshot of search results
[![A screenshot of a sample search with ripgrep](http://burntsushi.net/stuff/ripgrep1.png)](http://burntsushi.net/stuff/ripgrep1.png)
### Quick examples comparing tools
This example searches the entire Linux kernel source tree (after running
`make defconfig && make -j8`) for `[A-Z]+_SUSPEND`, where all matches must be
words. Timings were collected on a system with an Intel i7-6900K 3.2 GHz, and
ripgrep was compiled using the `compile` script in this repo.
ripgrep was compiled with SIMD enabled.
Please remember that a single benchmark is never enough! See my
[blog post on `ripgrep`](http://blog.burntsushi.net/ripgrep/)
[blog post on ripgrep](http://blog.burntsushi.net/ripgrep/)
for a very detailed comparison with more benchmarks and analysis.
| Tool | Command | Line count | Time |
@@ -69,65 +82,62 @@ large file (~9.3GB,
In the above benchmark, passing the `-n` flag (for showing line numbers)
increases the times to `2.640s` for ripgrep and `10.277s` for GNU grep.
### Why should I use `ripgrep`?
* 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
### Why should I use ripgrep?
* It can replace many use cases served by both The Silver Searcher and GNU grep
because it is generally faster than both. (See [the FAQ](FAQ.md#posix4ever)
for more details on whether ripgrep can truly replace grep.)
* 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
hidden and binary files by default. ripgrep also implements full support
for `.gitignore`, whereas there are many bugs related to that functionality
in The Silver Searcher.
* `ripgrep` can search specific types of files. For example, `rg -tpy foo`
* ripgrep can search specific types of files. For example, `rg -tpy foo`
limits your search to Python files and `rg -Tjs foo` excludes Javascript
files from your search. `ripgrep` can be taught about new file types with
files from your search. ripgrep can be taught about new file types with
custom matching rules.
* `ripgrep` supports many features found in `grep`, such as showing the context
* ripgrep supports many features found in `grep`, such as showing the context
of search results, searching multiple patterns, highlighting matches with
color and full Unicode support. Unlike GNU grep, `ripgrep` stays fast while
color and full Unicode support. Unlike GNU grep, ripgrep stays fast while
supporting Unicode (which is always on).
* `ripgrep` supports searching files in text encodings other than UTF-8, such
* ripgrep supports searching files in text encodings other than UTF-8, such
as UTF-16, latin-1, GBK, EUC-JP, Shift_JIS and more. (Some support for
automatically detecting UTF-16 is provided. Other text encodings must be
specifically specified with the `-E/--encoding` flag.)
* `ripgrep` supports searching files compressed in a common format (gzip, xz,
* ripgrep supports searching files compressed in a common format (gzip, xz,
lzma or bzip2 current) with the `-z/--search-zip` flag.
In other words, use `ripgrep` if you like speed, filtering by default, fewer
In other words, use ripgrep if you like speed, filtering by default, fewer
bugs, and Unicode support.
### Why shouldn't I use `ripgrep`?
I'd like to try to convince you why you *shouldn't* use `ripgrep`. This should
### Why shouldn't I use ripgrep?
I'd like to try to convince you why you *shouldn't* use ripgrep. This should
give you a glimpse at some important downsides or missing features of
`ripgrep`.
ripgrep.
* `ripgrep` uses a regex engine based on finite automata, so if you want fancy
regex features such as backreferences or lookaround, `ripgrep` won't provide
them to you. `ripgrep` does support lots of things though, including, but not
* ripgrep uses a regex engine based on finite automata, so if you want fancy
regex features such as backreferences or lookaround, ripgrep won't provide
them to you. ripgrep does support lots of things though, including, but not
limited to: lazy quantification (e.g., `a+?`), repetitions (e.g., `a{2,5}`),
begin/end assertions (e.g., `^\w+$`), word boundaries (e.g., `\bfoo\b`), and
support for Unicode categories (e.g., `\p{Sc}` to match currency symbols or
`\p{Lu}` to match any uppercase letter). (Fancier regexes will never be
supported.)
* `ripgrep` doesn't have multiline search. (Unlikely to ever be supported.)
* ripgrep doesn't have multiline search. (Will happen as an opt-in feature.)
In other words, if you like fancy regexes or multiline search, then `ripgrep`
In other words, if you like fancy regexes or multiline search, then ripgrep
may not quite meet your needs (yet).
### Feature comparison
Andy Lester, author of [ack](https://beyondgrep.com/), has published an
excellent table comparing the features of ack, ag, git-grep, GNU grep and
ripgrep: https://beyondgrep.com/feature-comparison/
### Is it really faster than everything else?
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:
Summarizing, ripgrep is fast because:
* It is built on top of
[Rust's regex engine](https://github.com/rust-lang-nursery/regex).
@@ -138,7 +148,7 @@ Summarizing, `ripgrep` is fast because:
engine.
* It supports searching with either memory maps or by searching incrementally
with an intermediate buffer. The former is better for single files and the
latter is better for large directories. `ripgrep` chooses the best searching
latter is better for large directories. ripgrep chooses the best searching
strategy for you automatically.
* Applies your ignore patterns in `.gitignore` files using a
[`RegexSet`](https://doc.rust-lang.org/regex/regex/struct.RegexSet.html).
@@ -148,14 +158,22 @@ Summarizing, `ripgrep` is fast because:
[`crossbeam`](https://docs.rs/crossbeam) and
[`ignore`](https://docs.rs/ignore).
### Feature comparison
Andy Lester, author of [ack](https://beyondgrep.com/), has published an
excellent table comparing the features of ack, ag, git-grep, GNU grep and
ripgrep: https://beyondgrep.com/feature-comparison/
### Installation
The binary name for `ripgrep` is `rg`.
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
platforms not explicitly mentioned below (such as Debian) are advised
to download one of these archives.
platforms not explicitly mentioned below 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,
@@ -179,63 +197,73 @@ $ brew tap burntsushi/ripgrep https://github.com/BurntSushi/ripgrep.git
$ brew install burntsushi/ripgrep/ripgrep-bin
```
If you're a **Windows Chocolatey** user, then you can install `ripgrep` from the [official repo](https://chocolatey.org/packages/ripgrep):
If you're a **Windows Chocolatey** user, then you can install ripgrep from the [official repo](https://chocolatey.org/packages/ripgrep):
```
$ choco install ripgrep
```
If you're an **Arch Linux** user, then you can install `ripgrep` from the official repos:
If you're an **Arch Linux** user, then you can install ripgrep from the official repos:
```
$ pacman -S ripgrep
```
If you're a **Gentoo** user, you can install `ripgrep` from the [official repo](https://packages.gentoo.org/packages/sys-apps/ripgrep):
If you're a **Gentoo** user, you can install ripgrep from the [official repo](https://packages.gentoo.org/packages/sys-apps/ripgrep):
```
$ emerge sys-apps/ripgrep
```
If you're a **Fedora 27+** user, you can install `ripgrep` from official repositories.
If you're a **Fedora 27+** user, you can install ripgrep from official repositories.
```
$ sudo dnf install ripgrep
```
If you're a **Fedora 24+** user, you can install `ripgrep` from [copr](https://copr.fedorainfracloud.org/coprs/carlwgeorge/ripgrep/):
If you're a **Fedora 24+** user, you can install ripgrep from [copr](https://copr.fedorainfracloud.org/coprs/carlwgeorge/ripgrep/):
```
$ sudo dnf copr enable carlwgeorge/ripgrep
$ sudo dnf install ripgrep
```
If you're a **RHEL/CentOS 7** user, you can install `ripgrep` from [copr](https://copr.fedorainfracloud.org/coprs/carlwgeorge/ripgrep/):
If you're a **RHEL/CentOS 7** user, you can install ripgrep from [copr](https://copr.fedorainfracloud.org/coprs/carlwgeorge/ripgrep/):
```
$ sudo yum-config-manager --add-repo=https://copr.fedorainfracloud.org/coprs/carlwgeorge/ripgrep/repo/epel-7/carlwgeorge-ripgrep-epel-7.repo
$ sudo yum install ripgrep
```
If you're a **Nix** user, you can install `ripgrep` from
If you're a **Nix** user, you can install ripgrep from
[nixpkgs](https://github.com/NixOS/nixpkgs/blob/master/pkgs/tools/text/ripgrep/default.nix):
```
$ 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 an **Ubuntu** user, `ripgrep` can be installed from the `snap` store.
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.0/ripgrep_0.8.0_amd64.deb
$ sudo dpkg -i ripgrep_0.8.0_amd64.deb
```
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.
* For older versions you can install snap using
[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`.
* Note that the minimum supported version of Rust for ripgrep is **1.17**,
If you're a **Rust programmer**, ripgrep can be installed with `cargo`.
* Note that the minimum supported version of Rust for ripgrep is **1.20**,
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
@@ -245,145 +273,15 @@ If you're a **Rust programmer**, `ripgrep` can be installed with `cargo`.
$ cargo install ripgrep
```
`ripgrep` isn't currently in any other package repositories.
ripgrep isn't currently in any other package repositories.
[I'd like to change that](https://github.com/BurntSushi/ripgrep/issues/10).
### Whirlwind tour
The command-line usage of `ripgrep` doesn't differ much from other tools that
perform a similar function, so you probably already know how to use `ripgrep`.
The full details can be found in `rg --help`, but let's go on a whirlwind tour.
`ripgrep` detects when its printing to a terminal, and will automatically
colorize your output and show line numbers, just like The Silver Searcher.
Coloring works on Windows too! Colors can be controlled more granularly with
the `--color` flag.
One last thing before we get started: generally speaking, `ripgrep` assumes the
input it is reading to be UTF-8. However, if ripgrep notices a file is encoded as
UTF-16, then it will know how to search it. For other encodings, you'll need to
explicitly specify them with the `-E/--encoding` flag.
To recursively search the current directory, while respecting all `.gitignore`
files, ignore hidden files and directories and skip binary files:
```
$ rg foobar
```
The above command also respects all `.ignore` files, including in parent
directories. `.ignore` files can be used when `.gitignore` files are
insufficient. In all cases, `.ignore` patterns take precedence over
`.gitignore`.
To ignore all ignore files, use `-u`. To additionally search hidden files
and directories, use `-uu`. To additionally search binary files, use `-uuu`.
(In other words, "search everything, dammit!") In particular, `rg -uuu` is
similar to `grep -a -r`.
```
$ rg -uu foobar # similar to `grep -r`
$ rg -uuu foobar # similar to `grep -a -r`
```
(Tip: If your ignore files aren't being adhered to like you expect, run your
search with the `--debug` flag.)
Make the search case insensitive with `-i`, invert the search with `-v` or
show the 2 lines before and after every search result with `-C2`.
Force all matches to be surrounded by word boundaries with `-w`.
Search and replace (find first and last names and swap them):
```
$ rg '([A-Z][a-z]+)\s+([A-Z][a-z]+)' --replace '$2, $1'
```
Named groups are supported:
```
$ rg '(?P<first>[A-Z][a-z]+)\s+(?P<last>[A-Z][a-z]+)' --replace '$last, $first'
```
Up the ante with full Unicode support, by matching any uppercase Unicode letter
followed by any sequence of lowercase Unicode letters (good luck doing this
with other search tools!):
```
$ rg '(\p{Lu}\p{Ll}+)\s+(\p{Lu}\p{Ll}+)' --replace '$2, $1'
```
Search only files matching a particular glob:
```
$ rg foo -g 'README.*'
```
<!--*-->
Or exclude files matching a particular glob:
```
$ rg foo -g '!*.min.js'
```
Search and return paths matching a particular glob (i.e., `-g` flag in ag/ack):
```
$ rg -g 'doc*' --files
```
Search only HTML and CSS files:
```
$ rg -thtml -tcss foobar
```
Search everything except for Javascript files:
```
$ rg -Tjs foobar
```
To see a list of types supported, run `rg --type-list`. To add a new type, use
`--type-add`, which must be accompanied by a pattern for searching (`rg` won't
persist your type settings):
```
$ rg --type-add 'foo:*.{foo,foobar}' -tfoo bar
```
The type `foo` will now match any file ending with the `.foo` or `.foobar`
extensions.
### Regex syntax
The syntax supported is
[documented as part of Rust's regex library](https://doc.rust-lang.org/regex/regex/index.html#syntax).
### Shell completions
Shell completion files are included in the release tarball for Bash, Fish, Zsh
and PowerShell.
For **bash**, move `complete/rg.bash-completion` to `$XDG_CONFIG_HOME/bash_completion`
or `/etc/bash_completion.d/`.
For **fish**, move `complete/rg.fish` to `$HOME/.config/fish/completions/`.
For **PowerShell**, add `. _rg.ps1` to your PowerShell
[profile](https://technet.microsoft.com/en-us/library/bb613488(v=vs.85).aspx)
(note the leading period). If the `_rg.ps1` file is not on your `PATH`, do
`. /path/to/_rg.ps1` instead.
For **zsh**, move `complete/_rg` to one of your `$fpath` directories.
### Building
`ripgrep` is written in Rust, so you'll need to grab a
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.17 (stable) or newer. Building is easy:
ripgrep compiles with Rust 1.20 (stable) or newer. Building is easy:
```
$ git clone https://github.com/BurntSushi/ripgrep
@@ -393,8 +291,8 @@ $ ./target/release/rg --version
0.1.3
```
If you have a Rust nightly compiler, then you can enable optional SIMD
acceleration like so:
If you have a Rust nightly compiler and a recent Intel CPU, then you can enable
optional SIMD acceleration like so:
```
RUSTFLAGS="-C target-cpu=native" cargo build --release --features 'simd-accel avx-accel'
@@ -403,144 +301,14 @@ RUSTFLAGS="-C target-cpu=native" cargo build --release --features 'simd-accel av
If your machine doesn't support AVX instructions, then simply remove
`avx-accel` from the features list. Similarly for SIMD.
### Running tests
`ripgrep` is relatively well-tested, including both unit tests and integration
ripgrep is relatively well-tested, including both unit tests and integration
tests. To run the full test suite, use:
```
$ cargo test
$ cargo test --all
```
from the repository root.
### Tips
#### Windows Powershell
##### Powershell Profile
To customize powershell on start-up, there is a special powershell script that has to be created.
In order to find its location, type `$profile`
See [more](https://technet.microsoft.com/en-us/library/bb613488(v=vs.85).aspx) for profile details.
Any powershell code in this file gets evaluated at the start of console.
This way you can have own aliases to be created at start.
##### Setup function alias
Often you can find a need to make alias for the favourite utility.
But powershell function aliases do not behave like your typical linux shell alias.
You always need to propagate arguments and **Stdin** input.
But it cannot be done simply as `function grep() { $input | rg.exe --hidden $args }`
Use below example as reference to how setup alias in powershell.
```powershell
function grep {
$count = @($input).Count
$input.Reset()
if ($count) {
$input | rg.exe --hidden $args
}
else {
rg.exe --hidden $args
}
}
```
Powershell special variables:
* input - is powershell **Stdin** object that allows you to access its content.
* args - is array of arguments passed to this function.
This alias checks whether there is **Stdin** input and propagates only if there is some lines.
Otherwise empty `$input` will make powershell to trigger `rg` to search empty **Stdin**
##### Piping non-ASCII content to ripgrep
When piping input into native executables in PowerShell, the encoding of the
input is controlled by the `$OutputEncoding` variable. By default, this is set
to US-ASCII, and any characters in the pipeline that don't have encodings in
US-ASCII are converted to `?` (question mark) characters.
To change this setting, set `$OutputEncoding` to a different encoding, as
represented by a .NET encoding object. Some common examples are below. The
value of this variable is reset when PowerShell restarts, so to make this
change take effect every time PowerShell is started add a line setting the
variable into your PowerShell profile.
Example `$OutputEncoding` settings:
* UTF-8 without BOM: `$OutputEncoding = [System.Text.UTF8Encoding]::new()`
* The console's output encoding:
`$OutputEncoding = [System.Console]::OutputEncoding`
If you continue to have encoding problems, you can also force the encoding
that the console will use for printing to UTF-8 with
`[System.Console]::OutputEncoding = [System.Text.Encoding]::UTF8`. This
will also reset when PowerShell is restarted, so you can add that line
to your profile as well if you want to make the setting permanent.
#### How do I make the output look like ag's?
Use the `--colors` flag, like so:
rg --colors line:fg:yellow \
--colors line:style:bold \
--colors path:fg:green \
--colors path:style:bold \
--colors match:fg:black \
--colors match:bg:yellow \
--colors match:style:nobold \
foo
### Known issues
#### I just hit Ctrl+C in the middle of ripgrep's output and now my terminal's foreground color is wrong!
Type in `color` in cmd.exe (Command Prompt) and `echo -ne "\033[0m"` on Unix
to restore your original foreground color.
In PowerShell, you can add the following code to your profile which will
restore the original foreground color when `Reset-ForegroundColor` is called.
Including the `Set-Alias` line will allow you to call it with simply `color`.
```powershell
$OrigFgColor = $Host.UI.RawUI.ForegroundColor
function Reset-ForegroundColor {
$Host.UI.RawUI.ForegroundColor = $OrigFgColor
}
Set-Alias -Name color -Value Reset-ForegroundColor
```
PR [#187](https://github.com/BurntSushi/ripgrep/pull/187) fixed this, and it
was later deprecated in
[#281](https://github.com/BurntSushi/ripgrep/issues/281). A full explanation is
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'`

162
build.rs
View File

@@ -4,23 +4,181 @@ extern crate clap;
extern crate lazy_static;
use std::env;
use std::fs;
use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::path::Path;
use std::process;
use clap::Shell;
use app::{RGArg, RGArgKind};
#[allow(dead_code)]
#[path = "src/app.rs"]
mod app;
fn main() {
// OUT_DIR is set by Cargo and it's where any additional build artifacts
// are written.
let outdir = match env::var_os("OUT_DIR") {
None => return,
Some(outdir) => outdir,
None => {
eprintln!(
"OUT_DIR environment variable not defined. \
Please file a bug: \
https://github.com/BurntSushi/ripgrep/issues/new");
process::exit(1);
}
};
fs::create_dir_all(&outdir).unwrap();
let stamp_path = Path::new(&outdir).join("ripgrep-stamp");
if let Err(err) = File::create(&stamp_path) {
panic!("failed to write {}: {}", stamp_path.display(), err);
}
if let Err(err) = generate_man_page(&outdir) {
eprintln!("failed to generate man page: {}", err);
}
// Use clap to build completion files.
let mut app = app::app();
app.gen_completions("rg", Shell::Bash, &outdir);
app.gen_completions("rg", Shell::Fish, &outdir);
app.gen_completions("rg", Shell::PowerShell, &outdir);
// Note that we do not use clap's support for zsh. Instead, zsh completions
// are manually maintained in `complete/_rg`.
// Make the current git hash available to the build.
if let Some(rev) = git_revision_hash() {
println!("cargo:rustc-env=RIPGREP_BUILD_GIT_HASH={}", rev);
}
}
fn git_revision_hash() -> Option<String> {
let result = process::Command::new("git")
.args(&["rev-parse", "--short=10", "HEAD"])
.output();
result.ok().and_then(|output| {
let v = String::from_utf8_lossy(&output.stdout).trim().to_string();
if v.is_empty() {
None
} else {
Some(v)
}
})
}
fn generate_man_page<P: AsRef<Path>>(outdir: P) -> io::Result<()> {
// If asciidoc isn't installed, then don't do anything.
if let Err(err) = process::Command::new("a2x").output() {
eprintln!("Could not run 'a2x' binary, skipping man page generation.");
eprintln!("Error from running 'a2x': {}", err);
return Ok(());
}
// 1. Read asciidoc template.
// 2. Interpolate template with auto-generated docs.
// 3. Save interpolation to disk.
// 4. Use a2x (part of asciidoc) to convert to man page.
let outdir = outdir.as_ref();
let cwd = env::current_dir()?;
let tpl_path = cwd.join("doc").join("rg.1.txt.tpl");
let txt_path = outdir.join("rg.1.txt");
let mut tpl = String::new();
File::open(&tpl_path)?.read_to_string(&mut tpl)?;
tpl = tpl.replace("{OPTIONS}", &formatted_options()?);
let githash = git_revision_hash();
let githash = githash.as_ref().map(|x| &**x);
tpl = tpl.replace("{VERSION}", &app::long_version(githash));
File::create(&txt_path)?.write_all(tpl.as_bytes())?;
let result = process::Command::new("a2x")
.arg("--no-xmllint")
.arg("--doctype").arg("manpage")
.arg("--format").arg("manpage")
.arg(&txt_path)
.spawn()?
.wait()?;
if !result.success() {
let msg = format!("'a2x' failed with exit code {:?}", result.code());
return Err(ioerr(msg));
}
Ok(())
}
fn formatted_options() -> io::Result<String> {
let mut args = app::all_args_and_flags();
args.sort_by(|x1, x2| x1.name.cmp(&x2.name));
let mut formatted = vec![];
for arg in args {
if arg.hidden {
continue;
}
// ripgrep only has two positional arguments, and probably will only
// ever have two positional arguments, so we just hardcode them into
// the template.
if let app::RGArgKind::Positional{..} = arg.kind {
continue;
}
formatted.push(formatted_arg(&arg)?);
}
Ok(formatted.join("\n\n"))
}
fn formatted_arg(arg: &RGArg) -> io::Result<String> {
match arg.kind {
RGArgKind::Positional{..} => panic!("unexpected positional argument"),
RGArgKind::Switch { long, short, multiple } => {
let mut out = vec![];
let mut header = format!("--{}", long);
if let Some(short) = short {
header = format!("-{}, {}", short, header);
}
if multiple {
header = format!("*{}* ...::", header);
} else {
header = format!("*{}*::", header);
}
writeln!(out, "{}", header)?;
writeln!(out, "{}", formatted_doc_txt(arg)?)?;
Ok(String::from_utf8(out).unwrap())
}
RGArgKind::Flag { long, short, value_name, multiple, .. } => {
let mut out = vec![];
let mut header = format!("--{}", long);
if let Some(short) = short {
header = format!("-{}, {}", short, header);
}
if multiple {
header = format!("*{}* _{}_ ...::", header, value_name);
} else {
header = format!("*{}* _{}_::", header, value_name);
}
writeln!(out, "{}", header)?;
writeln!(out, "{}", formatted_doc_txt(arg)?)?;
Ok(String::from_utf8(out).unwrap())
}
}
}
fn formatted_doc_txt(arg: &RGArg) -> io::Result<String> {
let paragraphs: Vec<&str> = arg.doc_long.split("\n\n").collect();
if paragraphs.is_empty() {
return Err(ioerr(format!("missing docs for --{}", arg.name)));
}
let first = format!(" {}", paragraphs[0].replace("\n", "\n "));
if paragraphs.len() == 1 {
return Ok(first);
}
Ok(format!("{}\n+\n{}", first, paragraphs[1..].join("\n+\n")))
}
fn ioerr(msg: String) -> io::Error {
io::Error::new(io::ErrorKind::Other, msg)
}

57
ci/before_deploy.sh Normal file → Executable file
View File

@@ -1,40 +1,55 @@
# `before_deploy` phase: here we package the build artifacts
#!/bin/bash
# package the build artifacts
set -ex
. $(dirname $0)/utils.sh
. "$(dirname $0)/utils.sh"
# Generate artifacts for release
mk_artifacts() {
if is_ssse3_target; then
RUSTFLAGS="-C target-feature=+ssse3" \
cargo build --target $TARGET --release --features simd-accel
cargo build --target "$TARGET" --release --features simd-accel
else
cargo build --target $TARGET --release
cargo build --target "$TARGET" --release
fi
}
mk_tarball() {
# create a "staging" directory
local td=$(mktempd)
local out_dir=$(pwd)
local name="${PROJECT_NAME}-${TRAVIS_TAG}-${TARGET}"
# When cross-compiling, use the right `strip` tool on the binary.
local gcc_prefix="$(gcc_prefix)"
mkdir "${td:?}/${name}"
mkdir "$td/$name/complete"
# Create a temporary dir that contains our staging area.
# $tmpdir/$name is what eventually ends up as the deployed archive.
local tmpdir="$(mktemp -d)"
local name="${PROJECT_NAME}-${TRAVIS_TAG}-${TARGET}"
local staging="$tmpdir/$name"
mkdir -p "$staging"/{complete,doc}
# The deployment directory is where the final archive will reside.
# This path is known by the .travis.yml configuration.
local out_dir="$(pwd)/deployment"
mkdir -p "$out_dir"
# Find the correct (most recent) Cargo "out" directory. The out directory
# contains shell completion files and the man page.
local cargo_out_dir="$(cargo_out_dir "target/$TARGET")"
cp target/$TARGET/release/rg "$td/$name/rg"
${gcc_prefix}strip "$td/$name/rg"
cp {doc/rg.1,README.md,UNLICENSE,COPYING,LICENSE-MIT} "$td/$name/"
cp \
target/$TARGET/release/build/ripgrep-*/out/{rg.bash-completion,rg.fish,_rg.ps1} \
"$td/$name/complete/"
cp complete/_rg "$td/$name/complete/"
# Copy the ripgrep binary and strip it.
cp "target/$TARGET/release/rg" "$staging/rg"
"${gcc_prefix}strip" "$staging/rg"
# Copy the licenses and README.
cp {README.md,UNLICENSE,COPYING,LICENSE-MIT} "$staging/"
# Copy documentation and man page.
cp {CHANGELOG.md,FAQ.md,GUIDE.md} "$staging/doc/"
if command -V a2x 2>&1 > /dev/null; then
# The man page should only exist if we have asciidoc installed.
cp "$cargo_out_dir/rg.1" "$staging/doc/"
fi
# Copy shell completion files.
cp "$cargo_out_dir"/{rg.bash,rg.fish,_rg.ps1} "$staging/complete/"
cp complete/_rg "$staging/complete/"
pushd $td
tar czf "$out_dir/$name.tar.gz" *
popd
rm -r $td
(cd "$tmpdir" && tar czf "$out_dir/$name.tar.gz" "$name")
rm -rf "$tmpdir"
}
main() {

47
ci/install.sh Normal file → Executable file
View File

@@ -1,43 +1,46 @@
# `install` phase: install stuff needed for the `script` phase
#!/bin/bash
# install stuff needed for the `script` phase
# Where rustup gets installed.
export PATH="$PATH:$HOME/.cargo/bin"
set -ex
. $(dirname $0)/utils.sh
install_c_toolchain() {
case $TARGET in
aarch64-unknown-linux-gnu)
sudo apt-get install -y --no-install-recommends \
gcc-aarch64-linux-gnu libc6-arm64-cross libc6-dev-arm64-cross
;;
*)
# For other targets, this is handled by addons.apt.packages in .travis.yml
;;
esac
}
. "$(dirname $0)/utils.sh"
install_rustup() {
curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=$TRAVIS_RUST_VERSION
curl https://sh.rustup.rs -sSf \
| sh -s -- -y --default-toolchain="$TRAVIS_RUST_VERSION"
rustc -V
cargo -V
}
install_standard_crates() {
install_targets() {
if [ $(host) != "$TARGET" ]; then
rustup target add $TARGET
fi
}
install_osx_dependencies() {
if ! is_osx; then
return
fi
brew install asciidoc
}
configure_cargo() {
local prefix=$(gcc_prefix)
if [ -n "${prefix}" ]; then
local gcc_suffix=
test -n "${GCC_VERSION}" && gcc_suffix="-${GCC_VERSION}" || :
if [ -n "$GCC_VERSION" ]; then
gcc_suffix="-$GCC_VERSION"
fi
local gcc="${prefix}gcc${gcc_suffix}"
# information about the cross compiler
${gcc} -v
"${gcc}" -v
# tell cargo which linker to use for cross compilation
mkdir -p .cargo
@@ -49,12 +52,10 @@ EOF
}
main() {
install_c_toolchain
install_osx_dependencies
install_rustup
install_standard_crates
install_targets
configure_cargo
# TODO if you need to install extra stuff add it here
}
main

54
ci/script.sh Normal file → Executable file
View File

@@ -1,30 +1,46 @@
# `script` phase: you usually build, test and generate docs in this phase
#!/bin/bash
# build, test and generate docs in this phase
set -ex
. $(dirname $0)/utils.sh
# NOTE Workaround for rust-lang/rust#31907 - disable doc tests when cross compiling
# This has been fixed in the nightly channel but it would take a while to reach the other channels
disable_cross_doctests() {
if [ $(host) != "$TARGET" ] && [ "$TRAVIS_RUST_VERSION" = "stable" ]; then
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
brew install gnu-sed --default-names
fi
find src -name '*.rs' -type f | xargs sed -i -e 's:\(//.\s*```\):\1 ignore,:g'
fi
}
. "$(dirname $0)/utils.sh"
main() {
# disable_cross_doctests
cargo build --target "${TARGET}" --verbose --all
if [ "$(architecture)" = "amd64" ] || [ "$(architecture)" = "i386" ]; then
cargo test --target "${TARGET}" --verbose --all
"$( dirname "${0}" )/test_complete.sh"
# Test a normal debug build.
cargo build --target "$TARGET" --verbose --all
# Show the output of the most recent build.rs stderr.
set +x
stderr="$(find "target/$TARGET/debug" -name stderr -print0 | xargs -0 ls -t | head -n1)"
if [ -s "$stderr" ]; then
echo "===== $stderr ====="
cat "$stderr"
echo "====="
fi
set -x
# 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
# ARM releases on a best effort basis?
if is_arm; then
return 0
fi
# Test that zsh completions are in sync with ripgrep's actual args.
"$(dirname "${0}")/test_complete.sh"
# Run tests for ripgrep and all sub-crates.
cargo test --target "$TARGET" --verbose --all
}
main

0
ci/sha256.sh Normal file → Executable file
View File

View File

@@ -1,5 +1,19 @@
mktempd() {
echo $(mktemp -d 2>/dev/null || mktemp -d -t tmp)
#!/bin/bash
# Various utility functions used through CI.
# Finds Cargo's `OUT_DIR` directory from the most recent build.
#
# This requires one parameter corresponding to the target directory
# to search for the build output.
cargo_out_dir() {
# This works by finding the most recent stamp file, which is produced by
# every ripgrep build.
target_dir="$1"
find "$target_dir" -name ripgrep-stamp -print0 \
| xargs -0 ls -t \
| head -n1 \
| xargs dirname
}
host() {
@@ -13,33 +27,8 @@ host() {
esac
}
gcc_prefix() {
case "$TARGET" in
aarch64-unknown-linux-gnu)
echo aarch64-linux-gnu-
;;
arm*-gnueabihf)
echo arm-linux-gnueabihf-
;;
*)
return
;;
esac
}
dobin() {
[ -z $MAKE_DEB ] && die 'dobin: $MAKE_DEB not set'
[ $# -lt 1 ] && die "dobin: at least one argument needed"
local f prefix=$(gcc_prefix)
for f in "$@"; do
install -m0755 $f $dtd/debian/usr/bin/
${prefix}strip -s $dtd/debian/usr/bin/$(basename $f)
done
}
architecture() {
case ${TARGET:?} in
case "$TARGET" in
x86_64-*)
echo amd64
;;
@@ -55,10 +44,48 @@ architecture() {
esac
}
is_ssse3_target() {
case "${TARGET}" in
i686-unknown-netbsd) return 1 ;; # i686-unknown-netbsd - SSE2
i686*|x86_64*) return 0 ;;
gcc_prefix() {
case "$(architecture)" in
armhf)
echo arm-linux-gnueabihf-
;;
*)
return
;;
esac
}
is_ssse3_target() {
case "$(architecture)" in
amd64) return 0 ;;
*) return 1 ;;
esac
}
is_x86() {
case "$(architecture)" in
amd64|i386) return 0 ;;
*) return 1 ;;
esac
}
is_arm() {
case "$(architecture)" in
armhf) return 0 ;;
*) return 1 ;;
esac
}
is_linux() {
case "$TRAVIS_OS_NAME" in
linux) return 0 ;;
*) return 1 ;;
esac
}
is_osx() {
case "$TRAVIS_OS_NAME" in
osx) return 0 ;;
*) return 1 ;;
esac
return 1
}

View File

@@ -1,8 +0,0 @@
#!/bin/sh
# export RUSTFLAGS="-C target-feature=+ssse3"
# cargo build --release --features 'simd-accel'
export RUSTFLAGS="-C target-cpu=native"
cargo build --release --features 'simd-accel avx-accel'
# cargo build --release --features 'simd-accel avx-accel' --target x86_64-unknown-linux-musl

View File

@@ -54,6 +54,7 @@ _rg() {
'(--mmap --no-mmap)--mmap[search using memory maps when possible]'
'(-H --with-filename --no-filename)--no-filename[suppress all file names]'
"(-p --heading --pretty --vimgrep)--no-heading[don't group matches by file name]"
"--no-config[don't load configuration files]"
"(--no-ignore-parent)--no-ignore[don't respect ignore files]"
"--no-ignore-parent[don't respect ignore files in parent directories]"
"--no-ignore-vcs[don't respect version control ignore files]"
@@ -124,7 +125,7 @@ _rg() {
[[ "${state}" == 'style' ]] &&
_values -S ':' 'style value' \
bold nobold intense nointense && return 0
bold nobold intense nointense underline nounderline && return 0
;;
typespec)

View File

@@ -1,5 +0,0 @@
#!/bin/sh -e
pandoc -s -f markdown-smart -t man rg.1.md -o rg.1
sed -i.bak 's/\.TH.*/.TH "rg" "1"/g' rg.1
rm -f rg.1.bak # BSD `sed` requires the creation of a back-up file

610
doc/rg.1
View File

@@ -1,610 +0,0 @@
.\" Automatically generated by Pandoc 2.0.6
.\"
.TH "rg" "1"
.hy
.SH NAME
.PP
rg \- recursively search current directory for lines matching a pattern
.SH SYNOPSIS
.PP
rg [\f[I]OPTIONS\f[]] \f[I]PATTERN\f[] [\f[I]PATH\f[] ...]
.PP
rg [\f[I]OPTIONS\f[]] [\-e \f[I]PATTERN\f[] ...] [\-f \f[I]FILE\f[] ...]
[\f[I]PATH\f[] ...]
.PP
rg [\f[I]OPTIONS\f[]] \-\-files [\f[I]PATH\f[] ...]
.PP
rg [\f[I]OPTIONS\f[]] \-\-type\-list
.PP
rg [\f[I]OPTIONS\f[]] \-\-help
.PP
rg [\f[I]OPTIONS\f[]] \-\-version
.SH DESCRIPTION
.PP
ripgrep (rg) combines the usability of The Silver Searcher (an ack
clone) with the raw speed of grep.
.PP
ripgrep\[aq]s regex engine uses finite automata and guarantees linear
time searching.
Because of this, features like backreferences and arbitrary lookaround
are not supported.
.PP
Note that ripgrep may abort unexpectedly when using default settings if
it searches a file that is simultaneously truncated.
This behavior can be avoided by passing the \-\-no\-mmap flag.
.PP
Project home page: https://github.com/BurntSushi/ripgrep
.SH POSITIONAL ARGUMENTS
.TP
.B \f[I]PATTERN\f[]
A regular expression used for searching.
To match a pattern beginning with a dash, use the \-e/\-\-regexp option.
.RS
.RE
.TP
.B \f[I]PATH\f[]
A file or directory to search.
Directories are searched recursively.
Paths specified expicitly on the command line override glob and ignore
rules.
.RS
.RE
.SH COMMON OPTIONS
.TP
.B \-a, \-\-text
Search binary files as if they were text.
.RS
.RE
.TP
.B \-c, \-\-count
Only show count of line matches for each file.
.RS
.RE
.TP
.B \-\-color \f[I]WHEN\f[]
Whether to use color in the output.
Valid values are never, auto, always or ansi.
The default is auto.
When always is used, coloring is attempted based on your environment.
When ansi is used, coloring is forcefully done using ANSI escape color
codes.
.RS
.RE
.TP
.B \-e, \-\-regexp \f[I]PATTERN\f[] ...
Use PATTERN to search.
This option can be provided multiple times, where all patterns given are
searched.
This is also useful when searching for patterns that start with a dash.
.RS
.RE
.TP
.B \-F, \-\-fixed\-strings
Treat the pattern as a literal string instead of a regular expression.
.RS
.RE
.TP
.B \-g, \-\-glob \f[I]GLOB\f[] ...
Include or exclude files for searching that match the given glob.
This always overrides any other ignore logic if there is a conflict, but
is otherwise applied in addition to ignore files (e.g., .gitignore or
\&.ignore).
Multiple glob flags may be used.
Globbing rules match .gitignore globs.
Precede a glob with a \[aq]!\[aq] to exclude it.
.RS
.PP
The \-\-glob flag subsumes the functionality of both the \-\-include and
\-\-exclude flags commonly found in other tools.
.PP
Values given to \-g must be quoted or your shell will expand them and
result in unexpected behavior.
.PP
Combine with the \-\-files flag to return matched filenames (i.e., to
replicate ack/ag\[aq]s \-g flag).
For example:
.IP
.nf
\f[C]
rg\ \-g\ \[aq]*.foo\[aq]\ \-\-files
\f[]
.fi
.RE
.TP
.B \-h, \-\-help
Show this usage message.
.RS
.RE
.TP
.B \-i, \-\-ignore\-case
Case insensitive search.
Overridden by \-\-case\-sensitive.
.RS
.RE
.TP
.B \-n, \-\-line\-number
Show line numbers (1\-based).
This is enabled by default at a tty.
.RS
.RE
.TP
.B \-N, \-\-no\-line\-number
Suppress line numbers.
.RS
.RE
.TP
.B \-q, \-\-quiet
Do not print anything to stdout.
If a match is found in a file, stop searching that file.
.RS
.RE
.TP
.B \-t, \-\-type \f[I]TYPE\f[] ...
Only search files matching TYPE.
Multiple type flags may be provided.
Use the \-\-type\-list flag to list all available types.
.RS
.RE
.TP
.B \-T, \-\-type\-not \f[I]TYPE\f[] ...
Do not search files matching TYPE.
Multiple not\-type flags may be provided.
.RS
.RE
.TP
.B \-u, \-\-unrestricted ...
Reduce the level of \[aq]smart\[aq] searching.
A single \-u doesn\[aq]t respect .gitignore (etc.) files.
Two \-u flags will search hidden files and directories.
Three \-u flags will search binary files.
\-uu is equivalent to \f[C]grep\ \-r\f[], and \-uuu is equivalent to
\f[C]grep\ \-a\ \-r\f[].
.RS
.PP
Note that the \-u flags are convenient aliases for other combinations of
flags.
\-u aliases \-\-no\-ignore.
\-uu aliases \-\-no\-ignore \-\-hidden.
\-uuu aliases \-\-no\-ignore \-\-hidden \-\-text.
.RE
.TP
.B \-v, \-\-invert\-match
Invert matching.
.RS
.RE
.TP
.B \-w, \-\-word\-regexp
Only show matches surrounded by word boundaries.
This is equivalent to putting \\b before and after the search pattern.
.RS
.RE
.TP
.B \-x, \-\-line\-regexp
Only show matches surrounded by line boundaries.
This is equivalent to putting ^...$ around the search pattern.
.RS
.RE
.TP
.B \-z, \-\-search\-zip
Search in compressed files.
Currently gz, bz2, xz and lzma formats are supported.
.RS
.PP
Note that ripgrep expects to find the decompression binaries for the
respective formats in your system\[aq]s PATH for use with this flag.
.RE
.SH LESS COMMON OPTIONS
.TP
.B \-A, \-\-after\-context \f[I]NUM\f[]
Show NUM lines after each match.
.RS
.RE
.TP
.B \-B, \-\-before\-context \f[I]NUM\f[]
Show NUM lines before each match.
.RS
.RE
.TP
.B \-C, \-\-context \f[I]NUM\f[]
Show NUM lines before and after each match.
.RS
.RE
.TP
.B \-\-colors \f[I]SPEC\f[] ...
This flag specifies color settings for use in the output.
This flag may be provided multiple times.
Settings are applied iteratively.
Colors are limited to one of eight choices: red, blue, green, cyan,
magenta, yellow, white and black.
Styles are limited to nobold, bold, nointense or intense.
.RS
.PP
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.
Value is either a color (for fg and bg) or a text style.
A special format, {type}:none, will clear all color settings for {type}.
.PP
For example, the following command will change the match color to
magenta and the background color for line numbers to yellow:
.IP
.nf
\f[C]
rg\ \-\-colors\ \[aq]match:fg:magenta\[aq]\ \-\-colors\ \[aq]line:bg:yellow\[aq]\ foo.
\f[]
.fi
.RE
.TP
.B \-\-column
Show column numbers (1 based) in output.
This only shows the column numbers for the first match on each line.
Note that this doesn\[aq]t try to account for Unicode.
One byte is equal to one column.
This implies \-\-line\-number.
.RS
.RE
.TP
.B \-\-context\-separator \f[I]SEPARATOR\f[]
The string to use when separating non\-continuous context lines.
Escape sequences may be used.
[default: \-\-]
.RS
.RE
.TP
.B \-\-debug
Show debug messages.
.RS
.RE
.TP
.B \-E, \-\-encoding \f[I]ENCODING\f[]
Specify the text encoding that ripgrep will use on all files searched.
The default value is \[aq]auto\[aq], which will cause ripgrep to do a
best effort automatic detection of encoding on a per\-file basis.
Other supported values can be found in the list of labels here:
https://encoding.spec.whatwg.org/#concept\-encoding\-get
.RS
.RE
.TP
.B \-f, \-\-file \f[I]FILE\f[] ...
Search for patterns from the given file, with one pattern per line.
When this flag is used or multiple times or in combination with the
\-e/\-\-regexp flag, then all patterns provided are searched.
Empty pattern lines will match all input lines, and the newline is not
counted as part of the pattern.
.RS
.RE
.TP
.B \-\-files
Print each file that would be searched (but don\[aq]t search).
.RS
.PP
Combine with the \-g flag to return matched paths, for example:
.IP
.nf
\f[C]
rg\ \-g\ \[aq]*.foo\[aq]\ \-\-files
\f[]
.fi
.RE
.TP
.B \-l, \-\-files\-with\-matches
Only show path of each file with matches.
.RS
.RE
.TP
.B \-\-files\-without\-match
Only show path of each file with no matches.
.RS
.RE
.TP
.B \-H, \-\-with\-filename
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
.B \-\-no\-filename
Never show the filename for a match.
This is the default when one file is searched.
.RS
.RE
.TP
.B \-\-heading
Show the file name above clusters of matches from each file instead of
showing the file name for every match.
This is the default mode at a tty.
.RS
.RE
.TP
.B \-\-no\-heading
Don\[aq]t group matches by each file.
If \-H/\-\-with\-filename is enabled, then file names will be shown for
every line matched.
This is the default mode when not at a tty.
.RS
.RE
.TP
.B \-\-hidden
Search hidden directories and files.
(Hidden directories and files are skipped by default.)
.RS
.RE
.TP
.B \-\-iglob \f[I]GLOB\f[] ...
Include or exclude files/directories case insensitively.
This always overrides any other ignore logic if there is a conflict, but
is otherwise applied in addition to ignore files (e.g., .gitignore or
\&.ignore).
Multiple glob flags may be used.
Globbing rules match .gitignore globs.
Precede a glob with a \[aq]!\[aq] to exclude it.
.RS
.RE
.TP
.B \-\-ignore\-file \f[I]FILE\f[] ...
Specify additional ignore files for filtering file paths.
Ignore files should be in the gitignore format and are matched relative
to the current working directory.
These ignore files have lower precedence than all other ignore files.
When specifying multiple ignore files, earlier files have lower
precedence than later files.
.RS
.RE
.TP
.B \-L, \-\-follow
Follow symlinks.
.RS
.RE
.TP
.B \-\-line\-number\-width \f[I]NUM\f[]
Specify a width for the displayed line number.
If number of digits in the line number is less than this number, it is
left padded with spaces.
Note: This setting has no effect if \-\-no\-line\-number is enabled.
.RS
.RE
.TP
.B \-M, \-\-max\-columns \f[I]NUM\f[]
Don\[aq]t print lines longer than this limit in bytes.
Longer lines are omitted, and only the number of matches in that line is
printed.
.RS
.RE
.TP
.B \-m, \-\-max\-count \f[I]NUM\f[]
Limit the number of matching lines per file searched to NUM.
.RS
.RE
.TP
.B \-\-max\-filesize \f[I]NUM\f[]+\f[I]SUFFIX\f[]?
Ignore files larger than \f[I]NUM\f[] in size.
Directories will never be ignored.
.RS
.PP
\f[I]SUFFIX\f[] is optional and may be one of K, M or G.
These correspond to kilobytes, megabytes and gigabytes respectively.
If omitted the input is treated as bytes.
.RE
.TP
.B \-\-maxdepth \f[I]NUM\f[]
Descend at most NUM directories below the command line arguments.
A value of zero searches only the starting\-points themselves.
.RS
.RE
.TP
.B \-\-mmap
Search using memory maps when possible.
This is enabled by default when ripgrep thinks it will be faster.
(Note that mmap searching doesn\[aq]t currently support the various
context related options.)
.RS
.RE
.TP
.B \-\-no\-messages
Suppress all error messages.
.RS
.RE
.TP
.B \-\-no\-mmap
Never use memory maps, even when they might be faster.
.RS
.RE
.TP
.B \-\-no\-ignore
Don\[aq]t respect ignore files (.gitignore, .ignore, etc.) This implies
\-\-no\-ignore\-parent.
.RS
.RE
.TP
.B \-\-no\-ignore\-parent
Don\[aq]t respect ignore files in parent directories.
.RS
.RE
.TP
.B \-\-no\-ignore\-vcs
Don\[aq]t respect version control ignore files (e.g., .gitignore).
Note that .ignore files will continue to be respected.
.RS
.RE
.TP
.B \-0, \-\-null
Whenever a file name is printed, follow it with a NUL byte.
This includes printing filenames before matches, and when printing a
list of matching files such as with \-\-count, \-\-files\-with\-matches
and \-\-files.
.RS
.RE
.TP
.B \-o, \-\-only\-matching
Print only the matched (non\-empty) parts of a matching line, with each
such part on a separate output line.
.RS
.RE
.TP
.B \-\-passthru, \-\-passthrough
Show both matching and non\-matching lines.
This option cannot be used with \-\-only\-matching or \-\-replace.
.RS
.RE
.TP
.B \-\-path\-separator \f[I]SEPARATOR\f[]
The path separator to use when printing file paths.
This defaults to your platform\[aq]s path separator, which is / on Unix
and \\ on Windows.
This flag is intended for overriding the default when the environment
demands it (e.g., cygwin).
A path separator is limited to a single byte.
.RS
.RE
.TP
.B \-p, \-\-pretty
Alias for \-\-color=always \-\-heading \-\-line\-number.
.RS
.RE
.TP
.B \-r, \-\-replace \f[I]ARG\f[]
Replace every match with the string given when printing search results.
Neither this flag nor any other flag will modify your files.
.RS
.PP
Capture group indices (e.g., $5) and names (e.g., $foo) are supported in
the replacement string.
.PP
Note that the replacement by default replaces each match, and NOT the
entire line.
To replace the entire line, you should match the entire line.
For example, to emit only the first phone numbers in each line:
.IP
.nf
\f[C]
rg\ \[aq]^.*([0\-9]{3}\-[0\-9]{3}\-[0\-9]{4}).*$\[aq]\ \-\-replace\ \[aq]$1\[aq]
\f[]
.fi
.RE
.TP
.B \-s, \-\-case\-sensitive
Search case sensitively (default).
Overrides \-\-ignore\-case and \-\-smart\-case.
.RS
.RE
.TP
.B \-S, \-\-smart\-case
Search case insensitively if the pattern is all lowercase.
Search case sensitively otherwise.
This is overridden by either \-\-case\-sensitive or \-\-ignore\-case.
Note: This feature is smart enough to treat simple classes like \\S as
lowercase, but may not handle more complex syntax like \\p{Ll} as
expected.
.RS
.RE
.TP
.B \-\-sort\-files
Sort results by file path.
Note that this currently disables all parallelism and runs search in a
single thread.
.RS
.RE
.TP
.B \-j, \-\-threads \f[I]ARG\f[]
The number of threads to use.
0 means use the number of logical CPUs (capped at 12).
[default: 0]
.RS
.RE
.TP
.B \-\-version
Show the version number of ripgrep and exit.
.RS
.RE
.TP
.B \-\-vimgrep
Show results with every match on its own line, including line numbers
and column numbers.
With this option, a line with more than one match will be printed more
than once.
.RS
.PP
Recommended .vimrc configuration:
.IP
.nf
\f[C]
\ \ set\ grepprg=rg\\\ \-\-vimgrep
\ \ set\ grepformat^=%f:%l:%c:%m
\f[]
.fi
.PP
Use :grep to grep for something, then :cn and :cp to navigate through
the matches.
.RE
.SH FILE TYPE MANAGEMENT OPTIONS
.TP
.B \-\-type\-list
Show all supported file types and their associated globs.
.RS
.RE
.TP
.B \-\-type\-add \f[I]ARG\f[] ...
Add a new glob for a particular file type.
Only one glob can be added at a time.
Multiple \-\-type\-add flags can be provided.
Unless \-\-type\-clear is used, globs are added to any existing globs
inside of ripgrep.
Note that this must be passed to every invocation of rg.
Type settings are NOT persisted.
Example:
.RS
.IP
.nf
\f[C]
\ \ rg\ \-\-type\-add\ \[aq]foo:*.foo\[aq]\ \-tfoo\ PATTERN
\f[]
.fi
.PP
\-\-type\-add can also be used to include rules from other types with
the special include directive.
The include directive permits specifying one or more other type names
(separated by a comma) that have been defined and its rules will
automatically be imported into the type specified.
For example, to create a type called src that matches C++, Python and
Markdown files, one can use:
.IP
.nf
\f[C]
\ \ \-\-type\-add\ \[aq]src:include:cpp,py,md\[aq]
\f[]
.fi
.PP
Additional glob rules can still be added to the src type by using the
\-\-type\-add flag again:
.IP
.nf
\f[C]
\ \ \-\-type\-add\ \[aq]src:include:cpp,py,md\[aq]\ \-\-type\-add\ \[aq]src:*.foo\[aq]
\f[]
.fi
.PP
Note that type names must consist only of Unicode letters or numbers.
Punctuation characters are not allowed.
.RE
.TP
.B \-\-type\-clear \f[I]TYPE\f[] ...
Clear the file type globs previously defined for TYPE.
This only clears the default type definitions that are found inside of
ripgrep.
Note that this must be passed to every invocation of rg.
.RS
.RE
.SH SHELL COMPLETION
.PP
Shell completion files are included in the release tarball for Bash,
Fish, Zsh and PowerShell.
.PP
For \f[B]bash\f[], move \f[C]rg.bash\-completion\f[] to
\f[C]$XDG_CONFIG_HOME/bash_completion\f[] or
\f[C]/etc/bash_completion.d/\f[].
.PP
For \f[B]fish\f[], move \f[C]rg.fish\f[] to
\f[C]$HOME/.config/fish/completions\f[].

View File

@@ -1,403 +0,0 @@
# NAME
rg - recursively search current directory for lines matching a pattern
# SYNOPSIS
rg [*OPTIONS*] *PATTERN* [*PATH* ...]
rg [*OPTIONS*] [-e *PATTERN* ...] [-f *FILE* ...] [*PATH* ...]
rg [*OPTIONS*] --files [*PATH* ...]
rg [*OPTIONS*] --type-list
rg [*OPTIONS*] --help
rg [*OPTIONS*] --version
# DESCRIPTION
ripgrep (rg) combines the usability of The Silver Searcher (an ack clone) with
the raw speed of grep.
ripgrep's regex engine uses finite automata and guarantees linear time
searching. Because of this, features like backreferences and arbitrary
lookaround are not supported.
Note that ripgrep may abort unexpectedly when using default settings if it
searches a file that is simultaneously truncated. This behavior can be avoided
by passing the --no-mmap flag.
Project home page: https://github.com/BurntSushi/ripgrep
# POSITIONAL ARGUMENTS
*PATTERN*
: A regular expression used for searching. To match a pattern beginning with a
dash, use the -e/--regexp option.
*PATH*
: A file or directory to search. Directories are searched recursively. Paths
specified expicitly on the command line override glob and ignore rules.
# COMMON OPTIONS
-a, --text
: Search binary files as if they were text.
-c, --count
: Only show count of line matches for each file.
--color *WHEN*
: Whether to use color in the output. Valid values are never, auto, always or
ansi. The default is auto. When always is used, coloring is attempted based
on your environment. When ansi is used, coloring is forcefully done using
ANSI escape color codes.
-e, --regexp *PATTERN* ...
: Use PATTERN to search. This option can be provided multiple times, where all
patterns given are searched. This is also useful when searching for patterns
that start with a dash.
-F, --fixed-strings
: Treat the pattern as a literal string instead of a regular expression.
-g, --glob *GLOB* ...
: Include or exclude files for searching that match the given glob. This always
overrides any other ignore logic if there is a conflict, but is otherwise
applied in addition to ignore files (e.g., .gitignore or .ignore). Multiple
glob flags may be used. Globbing rules match .gitignore globs. Precede a
glob with a '!' to exclude it.
The --glob flag subsumes the functionality of both the --include and
--exclude flags commonly found in other tools.
Values given to -g must be quoted or your shell will expand them and result
in unexpected behavior.
Combine with the --files flag to return matched filenames
(i.e., to replicate ack/ag's -g flag). For example:
rg -g '*.foo' --files
-h, --help
: Show this usage message.
-i, --ignore-case
: Case insensitive search. Overridden by --case-sensitive.
-n, --line-number
: Show line numbers (1-based). This is enabled by default at a tty.
-N, --no-line-number
: Suppress line numbers.
-q, --quiet
: Do not print anything to stdout. If a match is found in a file, stop
searching that file.
-t, --type *TYPE* ...
: Only search files matching TYPE. Multiple type flags may be provided. Use the
--type-list flag to list all available types.
-T, --type-not *TYPE* ...
: Do not search files matching TYPE. Multiple not-type flags may be provided.
-u, --unrestricted ...
: Reduce the level of 'smart' searching. A single -u doesn't respect .gitignore
(etc.) files. Two -u flags will search hidden files and directories. Three
-u flags will search binary files. -uu is equivalent to `grep -r`, and -uuu
is equivalent to `grep -a -r`.
Note that the -u flags are convenient aliases for other combinations of
flags. -u aliases --no-ignore. -uu aliases --no-ignore --hidden.
-uuu aliases --no-ignore --hidden --text.
-v, --invert-match
: Invert matching.
-w, --word-regexp
: Only show matches surrounded by word boundaries. This is equivalent to
putting \\b before and after the search pattern.
-x, --line-regexp
: Only show matches surrounded by line boundaries. This is equivalent to
putting ^...$ around the search pattern.
-z, --search-zip
: Search in compressed files. Currently gz, bz2, xz and lzma
formats are supported.
Note that ripgrep expects to find the decompression binaries for the
respective formats in your system's PATH for use with this flag.
# LESS COMMON OPTIONS
-A, --after-context *NUM*
: Show NUM lines after each match.
-B, --before-context *NUM*
: Show NUM lines before each match.
-C, --context *NUM*
: Show NUM lines before and after each match.
--colors *SPEC* ...
: This flag specifies color settings for use in the output. This flag may be
provided multiple times. Settings are applied iteratively. Colors are limited
to one of eight choices: red, blue, green, cyan, magenta, yellow, white and
black. Styles are limited to nobold, bold, nointense or intense.
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. Value
is either a color (for fg and bg) or a text style. A special format,
{type}:none, will clear all color settings for {type}.
For example, the following command will change the match color to magenta
and the background color for line numbers to yellow:
rg --colors 'match:fg:magenta' --colors 'line:bg:yellow' foo.
--column
: Show column numbers (1 based) in output. This only shows the column
numbers for the first match on each line. Note that this doesn't try
to account for Unicode. One byte is equal to one column. This implies
--line-number.
--context-separator *SEPARATOR*
: The string to use when separating non-continuous context lines. Escape
sequences may be used. [default: --]
--debug
: Show debug messages.
-E, --encoding *ENCODING*
: Specify the text encoding that ripgrep will use on all files
searched. The default value is 'auto', which will cause ripgrep to do
a best effort automatic detection of encoding on a per-file basis.
Other supported values can be found in the list of labels here:
https://encoding.spec.whatwg.org/#concept-encoding-get
-f, --file *FILE* ...
: Search for patterns from the given file, with one pattern per line. When this
flag is used or multiple times or in combination with the -e/--regexp flag,
then all patterns provided are searched. Empty pattern lines will match all
input lines, and the newline is not counted as part of the pattern.
--files
: Print each file that would be searched (but don't search).
Combine with the -g flag to return matched paths, for example:
rg -g '*.foo' --files
-l, --files-with-matches
: Only show path of each file with matches.
--files-without-match
: Only show path of each file with no matches.
-H, --with-filename
: 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
one file is searched.
--heading
: Show the file name above clusters of matches from each file instead of
showing the file name for every match. This is the default mode at a tty.
--no-heading
: Don't group matches by each file. If -H/--with-filename is enabled, then
file names will be shown for every line matched. This is the default mode
when not at a tty.
--hidden
: Search hidden directories and files. (Hidden directories and files are
skipped by default.)
--iglob *GLOB* ...
: Include or exclude files/directories case insensitively. This always
overrides any other ignore logic if there is a conflict, but is otherwise
applied in addition to ignore files (e.g., .gitignore or .ignore). Multiple
glob flags may be used. Globbing rules match .gitignore globs. Precede a
glob with a '!' to exclude it.
--ignore-file *FILE* ...
: Specify additional ignore files for filtering file paths.
Ignore files should be in the gitignore format and are matched
relative to the current working directory. These ignore files
have lower precedence than all other ignore files. When
specifying multiple ignore files, earlier files have lower
precedence than later files.
-L, --follow
: Follow symlinks.
--line-number-width *NUM*
: Specify a width for the displayed line number. If number of digits
in the line number is less than this number, it is left padded with
spaces. Note: This setting has no effect if --no-line-number is
enabled.
-M, --max-columns *NUM*
: Don't print lines longer than this limit in bytes. Longer lines are omitted,
and only the number of matches in that line is printed.
-m, --max-count *NUM*
: Limit the number of matching lines per file searched to NUM.
--max-filesize *NUM*+*SUFFIX*?
: Ignore files larger than *NUM* in size. Directories will never be ignored.
*SUFFIX* is optional and may be one of K, M or G. These correspond to
kilobytes, megabytes and gigabytes respectively. If omitted the input is
treated as bytes.
--maxdepth *NUM*
: Descend at most NUM directories below the command line arguments.
A value of zero searches only the starting-points themselves.
--mmap
: Search using memory maps when possible. This is enabled by default
when ripgrep thinks it will be faster. (Note that mmap searching
doesn't currently support the various context related options.)
--no-messages
: Suppress all error messages.
--no-mmap
: Never use memory maps, even when they might be faster.
--no-ignore
: Don't respect ignore files (.gitignore, .ignore, etc.)
This implies --no-ignore-parent.
--no-ignore-parent
: Don't respect ignore files in parent directories.
--no-ignore-vcs
: Don't respect version control ignore files (e.g., .gitignore).
Note that .ignore files will continue to be respected.
-0, --null
: Whenever a file name is printed, follow it with a NUL byte.
This includes printing filenames before matches, and when printing
a list of matching files such as with --count, --files-with-matches
and --files.
-o, --only-matching
: Print only the matched (non-empty) parts of a matching line, with each such
part on a separate output line.
--passthru, --passthrough
: Show both matching and non-matching lines. This option cannot be used with
--only-matching or --replace.
--path-separator *SEPARATOR*
: The path separator to use when printing file paths. This defaults to your
platform's path separator, which is / on Unix and \\ on Windows. This flag is
intended for overriding the default when the environment demands it (e.g.,
cygwin). A path separator is limited to a single byte.
-p, --pretty
: Alias for --color=always --heading --line-number.
-r, --replace *ARG*
: Replace every match with the string given when printing search results.
Neither this flag nor any other flag will modify your files.
Capture group indices (e.g., $5) and names (e.g., $foo) are supported
in the replacement string.
Note that the replacement by default replaces each match, and NOT the
entire line. To replace the entire line, you should match the entire line.
For example, to emit only the first phone numbers in each line:
rg '^.*([0-9]{3}-[0-9]{3}-[0-9]{4}).*$' --replace '$1'
-s, --case-sensitive
: Search case sensitively (default). Overrides --ignore-case and --smart-case.
-S, --smart-case
: Search case insensitively if the pattern is all lowercase.
Search case sensitively otherwise. This is overridden by either
--case-sensitive or --ignore-case. Note: This feature is smart enough
to treat simple classes like \\S as lowercase, but may not handle more
complex syntax like \\p{Ll} as expected.
--sort-files
: Sort results by file path. Note that this currently
disables all parallelism and runs search in a single thread.
-j, --threads *ARG*
: The number of threads to use. 0 means use the number of logical CPUs
(capped at 12). [default: 0]
--version
: Show the version number of ripgrep and exit.
--vimgrep
: Show results with every match on its own line, including
line numbers and column numbers. With this option, a line with
more than one match will be printed more than once.
Recommended .vimrc configuration:
set grepprg=rg\ --vimgrep
set grepformat^=%f:%l:%c:%m
Use :grep to grep for something, then :cn and :cp to navigate through the
matches.
# FILE TYPE MANAGEMENT OPTIONS
--type-list
: Show all supported file types and their associated globs.
--type-add *ARG* ...
: Add a new glob for a particular file type. Only one glob can be added
at a time. Multiple --type-add flags can be provided. Unless --type-clear
is used, globs are added to any existing globs inside of ripgrep. Note that
this must be passed to every invocation of rg. Type settings are NOT
persisted. Example:
rg --type-add 'foo:*.foo' -tfoo PATTERN
--type-add can also be used to include rules from other types
with the special include directive. The include directive
permits specifying one or more other type names (separated by a
comma) that have been defined and its rules will automatically
be imported into the type specified. For example, to create a
type called src that matches C++, Python and Markdown files, one
can use:
--type-add 'src:include:cpp,py,md'
Additional glob rules can still be added to the src type by
using the --type-add flag again:
--type-add 'src:include:cpp,py,md' --type-add 'src:*.foo'
Note that type names must consist only of Unicode letters or
numbers. Punctuation characters are not allowed.
--type-clear *TYPE* ...
: Clear the file type globs previously defined for TYPE. This only clears
the default type definitions that are found inside of ripgrep. Note
that this must be passed to every invocation of rg.
# SHELL COMPLETION
Shell completion files are included in the release tarball for Bash, Fish, Zsh
and PowerShell.
For **bash**, move `rg.bash-completion` to `$XDG_CONFIG_HOME/bash_completion`
or `/etc/bash_completion.d/`.
For **fish**, move `rg.fish` to `$HOME/.config/fish/completions`.

154
doc/rg.1.txt.tpl Normal file
View File

@@ -0,0 +1,154 @@
rg(1)
=====
Name
----
rg - recursively search current directory for lines matching a pattern
Synopsis
--------
*rg* [_OPTIONS_] _PATTERN_ [_PATH_...]
*rg* [_OPTIONS_] *-e* _PATTERN_... [_PATH_...]
*rg* [_OPTIONS_] *-f* _PATH_... [_PATH_...]
*rg* [_OPTIONS_] *--files* [_PATH_...]
*rg* [_OPTIONS_] *--type-list*
*rg* [_OPTIONS_] *--help*
*rg* [_OPTIONS_] *--version*
DESCRIPTION
-----------
ripgrep (rg) recursively searches your current directory for a regex pattern.
By default, ripgrep will respect your `.gitignore` and automatically skip
hidden files/directories and binary files.
ripgrep's regex engine uses finite automata and guarantees linear time
searching. Because of this, features like backreferences and arbitrary
lookaround are not supported.
REGEX SYNTAX
------------
ripgrep uses Rust's regex engine, which documents its syntax:
https://docs.rs/regex/0.2.5/regex/#syntax
ripgrep uses byte-oriented regexes, which has some additional documentation:
https://docs.rs/regex/0.2.5/regex/bytes/index.html#syntax
To a first approximation, ripgrep uses Perl-like regexes without look-around or
backreferences. This makes them very similar to the "extended" (ERE) regular
expressions supported by `egrep`, but with a few additional features like
Unicode character classes.
POSITIONAL ARGUMENTS
--------------------
_PATTERN_::
A regular expression used for searching. To match a pattern beginning with a
dash, use the -e/--regexp option.
_PATH_::
A file or directory to search. Directories are searched recursively. Paths
specified expicitly on the command line override glob and ignore rules.
OPTIONS
-------
{OPTIONS}
EXIT STATUS
-----------
If ripgrep finds a match, then the exit status of the program is 0. If no match
could be found, then the exit status is non-zero.
CONFIGURATION FILES
-------------------
ripgrep supports reading configuration files that change ripgrep's default
behavior. The format of the configuration file is an "rc" style and is very
simple. It is defined by two rules:
1. Every line is a shell argument, after trimming ASCII whitespace.
2. Lines starting with _#_ (optionally preceded by any amount of
ASCII whitespace) are ignored.
ripgrep will look for a single configuration file if and only if the
_RIPGREP_CONFIG_PATH_ environment variable is set and is non-empty.
ripgrep will parse shell arguments from this file on startup and will
behave as if the arguments in this file were prepended to any explicit
arguments given to ripgrep on the command line.
For example, if your ripgreprc file contained a single line:
--smart-case
then the following command
RIPGREP_CONFIG_PATH=wherever/.ripgreprc rg foo
would behave identically to the following command
rg --smart-case foo
ripgrep also provides a flag, *--no-config*, that when present will suppress
any and all support for configuration. This includes any future support
for auto-loading configuration files from pre-determined paths.
Conflicts between configuration files and explicit arguments are handled
exactly like conflicts in the same command line invocation. That is,
this command:
RIPGREP_CONFIG_PATH=wherever/.ripgreprc rg foo --case-sensitive
is exactly equivalent to
rg --smart-case foo --case-sensitive
in which case, the *--case-sensitive* flag would override the *--smart-case*
flag.
SHELL COMPLETION
----------------
Shell completion files are included in the release tarball for Bash, Fish, Zsh
and PowerShell.
For *bash*, move `rg.bash` to `$XDG_CONFIG_HOME/bash_completion`
or `/etc/bash_completion.d/`.
For *fish*, move `rg.fish` to `$HOME/.config/fish/completions`.
For *zsh*, move `_rg` to one of your `$fpath` directories.
CAVEATS
-------
ripgrep may abort unexpectedly when using default settings if it searches a
file that is simultaneously truncated. This behavior can be avoided by passing
the --no-mmap flag which will forcefully disable the use of memory maps in all
cases.
VERSION
-------
{VERSION}
HOMEPAGE
--------
https://github.com/BurntSushi/ripgrep
Please report bugs and feature requests in the issue tracker.
AUTHORS
-------
Andrew Gallant <jamslam@gmail.com>

View File

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

View File

@@ -1,4 +1,3 @@
use std::ffi::{OsStr, OsString};
use std::fmt;
use std::hash;
use std::iter;
@@ -28,7 +27,7 @@ pub enum MatchStrategy {
BasenameLiteral(String),
/// A pattern matches if and only if the file path's extension matches this
/// literal string.
Extension(OsString),
Extension(String),
/// A pattern matches if and only if this prefix literal is a prefix of the
/// candidate file path.
Prefix(String),
@@ -47,7 +46,7 @@ pub enum MatchStrategy {
/// extension. Note that this is a necessary but NOT sufficient criterion.
/// Namely, if the extension matches, then a full regex search is still
/// required.
RequiredExtension(OsString),
RequiredExtension(String),
/// A regex needs to be used for matching.
Regex,
}
@@ -154,7 +153,7 @@ impl GlobStrategic {
lit.as_bytes() == &*candidate.basename
}
MatchStrategy::Extension(ref ext) => {
candidate.ext == ext
ext.as_bytes() == &*candidate.ext
}
MatchStrategy::Prefix(ref pre) => {
starts_with(pre.as_bytes(), byte_path)
@@ -166,7 +165,8 @@ impl GlobStrategic {
ends_with(suffix.as_bytes(), byte_path)
}
MatchStrategy::RequiredExtension(ref ext) => {
candidate.ext == ext && self.re.is_match(byte_path)
let ext = ext.as_bytes();
&*candidate.ext == ext && self.re.is_match(byte_path)
}
MatchStrategy::Regex => self.re.is_match(byte_path),
}
@@ -295,7 +295,7 @@ impl Glob {
/// std::path::Path::extension returns. Namely, this extension includes
/// the '.'. Also, paths like `.rs` are considered to have an extension
/// of `.rs`.
fn ext(&self) -> Option<OsString> {
fn ext(&self) -> Option<String> {
if self.opts.case_insensitive {
return None;
}
@@ -319,11 +319,11 @@ impl Glob {
Some(&Token::Literal('.')) => {}
_ => return None,
}
let mut lit = OsStr::new(".").to_os_string();
let mut lit = ".".to_string();
for t in self.tokens[start + 2..].iter() {
match *t {
Token::Literal('.') | Token::Literal('/') => return None,
Token::Literal(c) => lit.push(c.to_string()),
Token::Literal(c) => lit.push(c),
_ => return None,
}
}
@@ -337,7 +337,7 @@ impl Glob {
/// This is like `ext`, but returns an extension even if it isn't sufficent
/// to imply a match. Namely, if an extension is returned, then it is
/// necessary but not sufficient for a match.
fn required_ext(&self) -> Option<OsString> {
fn required_ext(&self) -> Option<String> {
if self.opts.case_insensitive {
return None;
}
@@ -360,7 +360,7 @@ impl Glob {
None
} else {
ext.reverse();
Some(OsString::from(ext.into_iter().collect::<String>()))
Some(ext.into_iter().collect())
}
}
@@ -927,8 +927,6 @@ fn ends_with(needle: &[u8], haystack: &[u8]) -> bool {
#[cfg(test)]
mod tests {
use std::ffi::{OsStr, OsString};
use {GlobSetBuilder, ErrorKind};
use super::{Glob, GlobBuilder, Token};
use super::Token::*;
@@ -1021,7 +1019,6 @@ mod tests {
}
fn s(string: &str) -> String { string.to_string() }
fn os(string: &str) -> OsString { OsStr::new(string).to_os_string() }
fn class(s: char, e: char) -> Token {
Class { negated: false, ranges: vec![(s, e)] }
@@ -1155,6 +1152,7 @@ mod tests {
matches!(matchrec22, ".*/**", ".abc/abc");
matches!(matchrec23, "foo/**", "foo");
matches!(matchrec24, "**/foo/bar", "foo/bar");
matches!(matchrec25, "some/*/needle.txt", "some/one/needle.txt");
matches!(matchrange1, "a[0-9]b", "a0b");
matches!(matchrange2, "a[0-9]b", "a9b");
@@ -1243,6 +1241,13 @@ mod tests {
nmatches!(matchnot27, "a[^0-9]b", "a0b");
nmatches!(matchnot28, "a[^0-9]b", "a9b");
nmatches!(matchnot29, "[^-]", "-");
nmatches!(matchnot30, "some/*/needle.txt", "some/needle.txt");
nmatches!(
matchrec31,
"some/*/needle.txt", "some/one/two/needle.txt", SLASHLIT);
nmatches!(
matchrec32,
"some/*/needle.txt", "some/one/two/three/needle.txt", SLASHLIT);
macro_rules! extract {
($which:ident, $name:ident, $pat:expr, $expect:expr) => {
@@ -1311,19 +1316,19 @@ mod tests {
Literal('f'), Literal('o'), ZeroOrMore, Literal('o'),
]), SLASHLIT);
ext!(extract_ext1, "**/*.rs", Some(os(".rs")));
ext!(extract_ext1, "**/*.rs", Some(s(".rs")));
ext!(extract_ext2, "**/*.rs.bak", None);
ext!(extract_ext3, "*.rs", Some(os(".rs")));
ext!(extract_ext3, "*.rs", Some(s(".rs")));
ext!(extract_ext4, "a*.rs", None);
ext!(extract_ext5, "/*.c", None);
ext!(extract_ext6, "*.c", None, SLASHLIT);
ext!(extract_ext7, "*.c", Some(os(".c")));
ext!(extract_ext7, "*.c", Some(s(".c")));
required_ext!(extract_req_ext1, "*.rs", Some(os(".rs")));
required_ext!(extract_req_ext2, "/foo/bar/*.rs", Some(os(".rs")));
required_ext!(extract_req_ext3, "/foo/bar/*.rs", Some(os(".rs")));
required_ext!(extract_req_ext4, "/foo/bar/.rs", Some(os(".rs")));
required_ext!(extract_req_ext5, ".rs", Some(os(".rs")));
required_ext!(extract_req_ext1, "*.rs", Some(s(".rs")));
required_ext!(extract_req_ext2, "/foo/bar/*.rs", Some(s(".rs")));
required_ext!(extract_req_ext3, "/foo/bar/*.rs", Some(s(".rs")));
required_ext!(extract_req_ext4, "/foo/bar/.rs", Some(s(".rs")));
required_ext!(extract_req_ext5, ".rs", Some(s(".rs")));
required_ext!(extract_req_ext6, "./rs", None);
required_ext!(extract_req_ext7, "foo", None);
required_ext!(extract_req_ext8, ".foo/", None);

View File

@@ -108,7 +108,7 @@ extern crate regex;
use std::borrow::Cow;
use std::collections::{BTreeMap, HashMap};
use std::error::Error as StdError;
use std::ffi::{OsStr, OsString};
use std::ffi::OsStr;
use std::fmt;
use std::hash;
use std::path::Path;
@@ -458,7 +458,7 @@ impl GlobSetBuilder {
pub struct Candidate<'a> {
path: Cow<'a, [u8]>,
basename: Cow<'a, [u8]>,
ext: &'a OsStr,
ext: Cow<'a, [u8]>,
}
impl<'a> Candidate<'a> {
@@ -469,7 +469,7 @@ impl<'a> Candidate<'a> {
Candidate {
path: normalize_path(path_bytes(path)),
basename: os_str_bytes(basename),
ext: file_name_ext(basename).unwrap_or(OsStr::new("")),
ext: file_name_ext(basename).unwrap_or(Cow::Borrowed(b"")),
}
}
@@ -584,22 +584,22 @@ impl BasenameLiteralStrategy {
}
#[derive(Clone, Debug)]
struct ExtensionStrategy(HashMap<OsString, Vec<usize>, Fnv>);
struct ExtensionStrategy(HashMap<Vec<u8>, Vec<usize>, Fnv>);
impl ExtensionStrategy {
fn new() -> ExtensionStrategy {
ExtensionStrategy(HashMap::with_hasher(Fnv::default()))
}
fn add(&mut self, global_index: usize, ext: OsString) {
self.0.entry(ext).or_insert(vec![]).push(global_index);
fn add(&mut self, global_index: usize, ext: String) {
self.0.entry(ext.into_bytes()).or_insert(vec![]).push(global_index);
}
fn is_match(&self, candidate: &Candidate) -> bool {
if candidate.ext.is_empty() {
return false;
}
self.0.contains_key(candidate.ext)
self.0.contains_key(&*candidate.ext)
}
#[inline(never)]
@@ -607,7 +607,7 @@ impl ExtensionStrategy {
if candidate.ext.is_empty() {
return;
}
if let Some(hits) = self.0.get(candidate.ext) {
if let Some(hits) = self.0.get(&*candidate.ext) {
matches.extend(hits);
}
}
@@ -670,14 +670,14 @@ impl SuffixStrategy {
}
#[derive(Clone, Debug)]
struct RequiredExtensionStrategy(HashMap<OsString, Vec<(usize, Regex)>, Fnv>);
struct RequiredExtensionStrategy(HashMap<Vec<u8>, Vec<(usize, Regex)>, Fnv>);
impl RequiredExtensionStrategy {
fn is_match(&self, candidate: &Candidate) -> bool {
if candidate.ext.is_empty() {
return false;
}
match self.0.get(candidate.ext) {
match self.0.get(&*candidate.ext) {
None => false,
Some(regexes) => {
for &(_, ref re) in regexes {
@@ -695,7 +695,7 @@ impl RequiredExtensionStrategy {
if candidate.ext.is_empty() {
return;
}
if let Some(regexes) = self.0.get(candidate.ext) {
if let Some(regexes) = self.0.get(&*candidate.ext) {
for &(global_index, ref re) in regexes {
if re.is_match(&*candidate.path) {
matches.push(global_index);
@@ -775,7 +775,7 @@ impl MultiStrategyBuilder {
#[derive(Clone, Debug)]
struct RequiredExtensionStrategyBuilder(
HashMap<OsString, Vec<(usize, String)>>,
HashMap<Vec<u8>, Vec<(usize, String)>>,
);
impl RequiredExtensionStrategyBuilder {
@@ -783,8 +783,11 @@ impl RequiredExtensionStrategyBuilder {
RequiredExtensionStrategyBuilder(HashMap::new())
}
fn add(&mut self, global_index: usize, ext: OsString, regex: String) {
self.0.entry(ext).or_insert(vec![]).push((global_index, regex));
fn add(&mut self, global_index: usize, ext: String, regex: String) {
self.0
.entry(ext.into_bytes())
.or_insert(vec![])
.push((global_index, regex));
}
fn build(self) -> Result<RequiredExtensionStrategy, Error> {

View File

@@ -54,34 +54,28 @@ pub fn file_name<'a, P: AsRef<Path> + ?Sized>(
/// a pattern like `*.rs` is obviously trying to match files with a `rs`
/// extension, but it also matches files like `.rs`, which doesn't have an
/// extension according to std::path::Path::extension.
pub fn file_name_ext(name: &OsStr) -> Option<&OsStr> {
// Yes, these functions are awful, and yes, we are completely violating
// the abstraction barrier of std::ffi. The barrier we're violating is
// that an OsStr's encoding is *ASCII compatible*. While this is obviously
// true on Unix systems, it's also true on Windows because an OsStr uses
// WTF-8 internally: https://simonsapin.github.io/wtf-8/
//
// We should consider doing the same for the other path utility functions.
// Right now, we don't break any barriers, but Windows users are paying
// for it.
//
// Got any better ideas that don't cost anything? Hit me up. ---AG
unsafe fn os_str_as_u8_slice(s: &OsStr) -> &[u8] {
::std::mem::transmute(s)
}
unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr {
::std::mem::transmute(s)
}
pub fn file_name_ext(name: &OsStr) -> Option<Cow<[u8]>> {
if name.is_empty() {
return None;
}
let name = unsafe { os_str_as_u8_slice(name) };
for (i, &b) in name.iter().enumerate().rev() {
if b == b'.' {
return Some(unsafe { u8_slice_as_os_str(&name[i..]) });
let name = os_str_bytes(name);
let last_dot_at = {
let result = name
.iter().enumerate().rev()
.find(|&(_, &b)| b == b'.')
.map(|(i, _)| i);
match result {
None => return None,
Some(i) => i,
}
}
None
};
Some(match name {
Cow::Borrowed(name) => Cow::Borrowed(&name[last_dot_at..]),
Cow::Owned(mut name) => {
name.drain(..last_dot_at);
Cow::Owned(name)
}
})
}
/// Return raw bytes of a path, transcoded to UTF-8 if necessary.
@@ -144,7 +138,7 @@ mod tests {
#[test]
fn $name() {
let got = file_name_ext(OsStr::new($file_name));
assert_eq!($ext.map(OsStr::new), got);
assert_eq!($ext.map(|s| Cow::Borrowed(s.as_bytes())), got);
}
};
}

View File

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

View File

@@ -1,6 +1,6 @@
[package]
name = "ignore"
version = "0.3.1" #:version
version = "0.4.1" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """
A fast library for efficiently matching ignore files such as `.gitignore`
@@ -19,9 +19,9 @@ bench = false
[dependencies]
crossbeam = "0.3"
globset = { version = "0.2.1", path = "../globset" }
globset = { version = "0.3.0", path = "../globset" }
lazy_static = "1"
log = "0.3"
log = "0.4"
memchr = "2"
regex = "0.2.1"
same-file = "1"

View File

@@ -73,13 +73,6 @@ struct IgnoreOptions {
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.
#[derive(Clone, Debug)]
pub struct Ignore(Arc<IgnoreInner>);
@@ -267,6 +260,15 @@ impl Ignore {
(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
/// ignored or not.
///
@@ -295,7 +297,7 @@ impl Ignore {
}
}
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);
if mat.is_ignore() {
return mat;

View File

@@ -66,6 +66,12 @@ impl Glob {
pub fn is_only_dir(&self) -> bool {
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
@@ -278,7 +284,10 @@ impl Gitignore {
// 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
// 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) {
path = p;
// If we're left with a leading slash, get rid of it.
@@ -454,7 +463,7 @@ impl GitignoreBuilder {
// prefix.
if !literal_separator {
// ... 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);
}
}
@@ -620,6 +629,12 @@ mod tests {
ignored!(ig29, ROOT, "node_modules/ ", "node_modules", true);
ignored!(ig30, ROOT, "**/", "foo/bar", true);
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!(ignot2, ROOT, "monthsa", "months");

View File

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

View File

@@ -249,6 +249,14 @@ struct DirEntryRaw {
/// The underlying inode number (Unix only).
#[cfg(unix)]
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 {
@@ -274,6 +282,20 @@ impl DirEntryRaw {
}
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 {
fs::metadata(&self.path)
} else {
@@ -309,21 +331,29 @@ impl DirEntryRaw {
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(
depth: usize,
ent: &fs::DirEntry,
ty: fs::FileType,
) -> DirEntryRaw {
DirEntryRaw {
) -> Result<DirEntryRaw, Error> {
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(),
ty: ty,
follow_link: false,
depth: depth,
}
metadata: md,
})
}
#[cfg(unix)]
@@ -331,16 +361,16 @@ impl DirEntryRaw {
depth: usize,
ent: &fs::DirEntry,
ty: fs::FileType,
) -> DirEntryRaw {
) -> Result<DirEntryRaw, Error> {
use std::os::unix::fs::DirEntryExt;
DirEntryRaw {
Ok(DirEntryRaw {
path: ent.path(),
ty: ty,
follow_link: false,
depth: depth,
ino: ent.ino(),
}
})
}
#[cfg(not(unix))]
@@ -353,6 +383,7 @@ impl DirEntryRaw {
ty: md.file_type(),
follow_link: true,
depth: depth,
metadata: md,
})
}
@@ -1026,6 +1057,11 @@ impl Work {
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.
///
/// 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() {
// If the work is not a directory, then we can just execute the
// 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() {
self.quit_now();
return;
@@ -1585,6 +1621,26 @@ mod tests {
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]
fn gitignore() {
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
version '0.7.1'
desc "Search tool like grep and The Silver Searcher."
version '0.8.0'
desc "Recursively search directories for a regex pattern."
homepage "https://github.com/BurntSushi/ripgrep"
if OS.mac?
url "https://github.com/BurntSushi/ripgrep/releases/download/#{version}/ripgrep-#{version}-x86_64-apple-darwin.tar.gz"
sha256 "ee670b0fba46323ee9a2d1c5b8bee46fa3e45778f6f105f2e8e9ee29e8bd0d45"
sha256 "fb35e92fd57d28a1e68daf964764c3da7f027ad30cca7a07a1848224776f36b2"
elsif OS.linux?
url "https://github.com/BurntSushi/ripgrep/releases/download/#{version}/ripgrep-#{version}-x86_64-unknown-linux-musl.tar.gz"
sha256 "ac595c2239b9a30e0e0744578afa6b73e32cdd8ae61d4f1c0ee5d6b55adbadcf"
sha256 "621f2f16f65203aa37e7c10ecfb22384c4c01e70ebbd30a13c0d6944ffc6e59e"
end
conflicts_with "ripgrep"
def install
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"
zsh_completion.install "complete/_rg"
end

2163
src/app.rs

File diff suppressed because it is too large Load Diff

View File

@@ -3,14 +3,12 @@ use std::env;
use std::ffi::OsStr;
use std::fs;
use std::io::{self, BufRead};
use std::ops;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use clap;
use encoding_rs::Encoding;
use env_logger;
use grep::{Grep, GrepBuilder, Error as GrepError};
use log;
use num_cpus;
@@ -27,6 +25,8 @@ use printer::{ColorSpecs, Printer};
use unescape::unescape;
use worker::{Worker, WorkerBuilder};
use config;
use logger::Logger;
use Result;
/// `Args` are transformed/normalized from `ArgMatches`.
@@ -89,18 +89,59 @@ impl Args {
///
/// Also, initialize a global logger.
pub fn parse() -> Result<Args> {
let matches = app::app().get_matches();
// We parse the args given on CLI. This does not include args from
// the config. We use the CLI args as an initial configuration while
// trying to parse config files. If a config file exists and has
// arguments, then we re-parse argv, otherwise we just use the matches
// we have here.
let early_matches = ArgMatches(app::app().get_matches());
let mut logb = env_logger::LogBuilder::new();
if matches.is_present("debug") {
logb.filter(None, log::LogLevelFilter::Debug);
} else {
logb.filter(None, log::LogLevelFilter::Warn);
}
if let Err(err) = logb.init() {
if let Err(err) = Logger::init() {
errored!("failed to initialize logger: {}", err);
}
ArgMatches(matches).to_args()
if early_matches.is_present("debug") {
log::set_max_level(log::LevelFilter::Debug);
} else {
log::set_max_level(log::LevelFilter::Warn);
}
let matches = Args::matches(early_matches);
// The logging level may have changed if we brought in additional
// arguments from a configuration file, so recheck it and set the log
// level as appropriate.
if matches.is_present("debug") {
log::set_max_level(log::LevelFilter::Debug);
} else {
log::set_max_level(log::LevelFilter::Warn);
}
matches.to_args()
}
/// Run clap and return the matches. If clap determines a problem with the
/// user provided arguments (or if --help or --version are given), then an
/// error/usage/version will be printed and the process will exit.
///
/// If there are no additional arguments from the environment (e.g., a
/// config file), then the given matches are returned as is.
fn matches(early_matches: ArgMatches<'static>) -> ArgMatches<'static> {
// If the end user says no config, then respect it.
if early_matches.is_present("no-config") {
debug!("not reading config files because --no-config is present");
return early_matches;
}
// If the user wants ripgrep to use a config file, then parse args
// from that first.
let mut args = config::args(early_matches.is_present("no-messages"));
if args.is_empty() {
return early_matches;
}
let mut cliargs = env::args_os();
if let Some(bin) = cliargs.next() {
args.insert(0, bin);
}
args.extend(cliargs);
debug!("final argv: {:?}", args);
ArgMatches(app::app().get_matches_from(args))
}
/// Returns true if ripgrep should print the files it will search and exit
@@ -306,11 +347,6 @@ impl Args {
/// several options/flags.
struct ArgMatches<'a>(clap::ArgMatches<'a>);
impl<'a> ops::Deref for ArgMatches<'a> {
type Target = clap::ArgMatches<'a>;
fn deref(&self) -> &clap::ArgMatches<'a> { &self.0 }
}
impl<'a> ArgMatches<'a> {
/// Convert the result of parsing CLI arguments into ripgrep's
/// configuration.
@@ -345,8 +381,8 @@ impl<'a> ArgMatches<'a> {
line_number: line_number,
line_number_width: try!(self.usize_of("line-number-width")),
line_per_match: self.is_present("vimgrep"),
max_columns: self.usize_of("max-columns")?,
max_count: self.usize_of("max-count")?.map(|max| max as u64),
max_columns: self.usize_of_nonzero("max-columns")?,
max_count: self.usize_of("max-count")?.map(|n| n as u64),
max_filesize: self.max_filesize()?,
maxdepth: self.usize_of("maxdepth")?,
mmap: mmap,
@@ -377,7 +413,7 @@ impl<'a> ArgMatches<'a> {
/// Return all file paths that ripgrep should search.
fn paths(&self) -> Vec<PathBuf> {
let mut paths: Vec<PathBuf> = match self.values_of_os("PATH") {
let mut paths: Vec<PathBuf> = match self.values_of_os("path") {
None => vec![],
Some(vals) => vals.map(|p| Path::new(p).to_path_buf()).collect(),
};
@@ -386,7 +422,7 @@ impl<'a> ArgMatches<'a> {
if self.is_present("file")
|| self.is_present("files")
|| self.is_present("regexp") {
if let Some(path) = self.value_of_os("PATTERN") {
if let Some(path) = self.value_of_os("pattern") {
paths.insert(0, Path::new(path).to_path_buf());
}
}
@@ -452,7 +488,7 @@ impl<'a> ArgMatches<'a> {
match self.values_of_os("regexp") {
None => {
if self.values_of_os("file").is_none() {
if let Some(os_pat) = self.value_of_os("PATTERN") {
if let Some(os_pat) = self.value_of_os("pattern") {
pats.push(self.os_str_pattern(os_pat)?);
}
}
@@ -646,7 +682,7 @@ impl<'a> ArgMatches<'a> {
/// Returns the replacement string as UTF-8 bytes if it exists.
fn replace(&self) -> Option<Vec<u8>> {
self.value_of_lossy("replace").map(|s| s.into_owned().into_bytes())
self.value_of_lossy("replace").map(|s| s.into_bytes())
}
/// Returns the unescaped context separator in UTF-8 bytes.
@@ -696,9 +732,9 @@ impl<'a> ArgMatches<'a> {
/// Returns the user's color choice based on command line parameters and
/// environment.
fn color_choice(&self) -> termcolor::ColorChoice {
let preference = match self.0.value_of_lossy("color") {
let preference = match self.value_of_lossy("color") {
None => "auto".to_string(),
Some(v) => v.into_owned(),
Some(v) => v,
};
if preference == "always" {
termcolor::ColorChoice::Always
@@ -744,7 +780,7 @@ impl<'a> ArgMatches<'a> {
/// A `None` encoding implies that the encoding should be automatically
/// detected on a per-file basis.
fn encoding(&self) -> Result<Option<&'static Encoding>> {
match self.0.value_of_lossy("encoding") {
match self.value_of_lossy("encoding") {
None => Ok(None),
Some(label) => {
if label == "auto" {
@@ -935,6 +971,24 @@ impl<'a> ArgMatches<'a> {
self.values_of_lossy(name).unwrap_or_else(Vec::new)
}
/// Safely reads an arg value with the given name, and if it's present,
/// tries to parse it as a usize value.
///
/// If the number is zero, then it is considered absent and `None` is
/// returned.
fn usize_of_nonzero(&self, name: &str) -> Result<Option<usize>> {
match self.value_of_lossy(name) {
None => Ok(None),
Some(v) => v.parse().map_err(From::from).map(|n| {
if n == 0 {
None
} else {
Some(n)
}
}),
}
}
/// Safely reads an arg value with the given name, and if it's present,
/// tries to parse it as a usize value.
fn usize_of(&self, name: &str) -> Result<Option<usize>> {
@@ -943,6 +997,35 @@ impl<'a> ArgMatches<'a> {
Some(v) => v.parse().map(Some).map_err(From::from),
}
}
// The following methods mostly dispatch to the underlying clap methods
// directly. Methods that would otherwise get a single value will fetch
// all values and return the last one. (Clap returns the first one.) We
// only define the ones we need.
fn is_present(&self, name: &str) -> bool {
self.0.is_present(name)
}
fn occurrences_of(&self, name: &str) -> u64 {
self.0.occurrences_of(name)
}
fn value_of_lossy(&self, name: &str) -> Option<String> {
self.0.value_of_lossy(name).map(|s| s.into_owned())
}
fn values_of_lossy(&self, name: &str) -> Option<Vec<String>> {
self.0.values_of_lossy(name)
}
fn value_of_os(&'a self, name: &str) -> Option<&'a OsStr> {
self.0.value_of_os(name)
}
fn values_of_os(&'a self, name: &str) -> Option<clap::OsValues<'a>> {
self.0.values_of_os(name)
}
}
fn pattern_to_str(s: &OsStr) -> Result<&str> {

195
src/config.rs Normal file
View File

@@ -0,0 +1,195 @@
// This module provides routines for reading ripgrep config "rc" files. The
// primary output of these routines is a sequence of arguments, where each
// argument corresponds precisely to one shell argument.
use std::env;
use std::error::Error;
use std::fs::File;
use std::io::{self, BufRead};
use std::ffi::OsString;
use std::path::{Path, PathBuf};
use Result;
/// Return a sequence of arguments derived from ripgrep rc configuration files.
///
/// If no_messages is false and there was a problem reading a config file,
/// then errors are printed to stderr.
pub fn args(no_messages: bool) -> Vec<OsString> {
let config_path = match env::var_os("RIPGREP_CONFIG_PATH") {
None => return vec![],
Some(config_path) => {
if config_path.is_empty() {
return vec![];
}
PathBuf::from(config_path)
}
};
let (args, errs) = match parse(&config_path) {
Ok((args, errs)) => (args, errs),
Err(err) => {
if !no_messages {
eprintln!("{}", err);
}
return vec![];
}
};
if !no_messages && !errs.is_empty() {
for err in errs {
eprintln!("{}:{}", config_path.display(), err);
}
}
debug!(
"{}: arguments loaded from config file: {:?}",
config_path.display(), args);
args
}
/// Parse a single ripgrep rc file from the given path.
///
/// On success, this returns a set of shell arguments, in order, that should
/// be pre-pended to the arguments given to ripgrep at the command line.
///
/// If the file could not be read, then an error is returned. If there was
/// a problem parsing one or more lines in the file, then errors are returned
/// for each line in addition to successfully parsed arguments.
fn parse<P: AsRef<Path>>(
path: P,
) -> Result<(Vec<OsString>, Vec<Box<Error>>)> {
let path = path.as_ref();
match File::open(&path) {
Ok(file) => parse_reader(file),
Err(err) => errored!("{}: {}", path.display(), err),
}
}
/// Parse a single ripgrep rc file from the given reader.
///
/// Callers should not provided a buffered reader, as this routine will use its
/// own buffer internally.
///
/// On success, this returns a set of shell arguments, in order, that should
/// be pre-pended to the arguments given to ripgrep at the command line.
///
/// If the reader could not be read, then an error is returned. If there was a
/// problem parsing one or more lines, then errors are returned for each line
/// in addition to successfully parsed arguments.
fn parse_reader<R: io::Read>(
rdr: R,
) -> Result<(Vec<OsString>, Vec<Box<Error>>)> {
let mut bufrdr = io::BufReader::new(rdr);
let (mut args, mut errs) = (vec![], vec![]);
let mut line = vec![];
let mut line_number = 0;
while {
line.clear();
line_number += 1;
bufrdr.read_until(b'\n', &mut line)? > 0
} {
trim(&mut line);
if line.is_empty() || line[0] == b'#' {
continue;
}
match bytes_to_os_string(&line) {
Ok(osstr) => {
args.push(osstr);
}
Err(err) => {
errs.push(format!("{}: {}", line_number, err).into());
}
}
}
Ok((args, errs))
}
/// Trim the given bytes of whitespace according to the ASCII definition.
fn trim(x: &mut Vec<u8>) {
let upto = x.iter().take_while(|b| is_space(**b)).count();
x.drain(..upto);
let revto = x.len() - x.iter().rev().take_while(|b| is_space(**b)).count();
x.drain(revto..);
}
/// Returns true if and only if the given byte is an ASCII space character.
fn is_space(b: u8) -> bool {
b == b'\t'
|| b == b'\n'
|| b == b'\x0B'
|| b == b'\x0C'
|| b == b'\r'
|| b == b' '
}
/// On Unix, get an OsString from raw bytes.
#[cfg(unix)]
fn bytes_to_os_string(bytes: &[u8]) -> Result<OsString> {
use std::os::unix::ffi::OsStringExt;
Ok(OsString::from_vec(bytes.to_vec()))
}
/// On non-Unix (like Windows), require UTF-8.
#[cfg(not(unix))]
fn bytes_to_os_string(bytes: &[u8]) -> Result<OsString> {
String::from_utf8(bytes.to_vec()).map(OsString::from).map_err(From::from)
}
#[cfg(test)]
mod tests {
use std::ffi::OsString;
use super::parse_reader;
#[test]
fn basic() {
let (args, errs) = parse_reader(&b"\
# Test
--context=0
--smart-case
-u
# --bar
--foo
"[..]).unwrap();
assert!(errs.is_empty());
let args: Vec<String> =
args.into_iter().map(|s| s.into_string().unwrap()).collect();
assert_eq!(args, vec![
"--context=0", "--smart-case", "-u", "--foo",
]);
}
// We test that we can handle invalid UTF-8 on Unix-like systems.
#[test]
#[cfg(unix)]
fn error() {
use std::os::unix::ffi::OsStringExt;
let (args, errs) = parse_reader(&b"\
quux
foo\xFFbar
baz
"[..]).unwrap();
assert!(errs.is_empty());
assert_eq!(args, vec![
OsString::from("quux"),
OsString::from_vec(b"foo\xFFbar".to_vec()),
OsString::from("baz"),
]);
}
// ... but test that invalid UTF-8 fails on Windows.
#[test]
#[cfg(not(unix))]
fn error() {
let (args, errs) = parse_reader(&b"\
quux
foo\xFFbar
baz
"[..]).unwrap();
assert_eq!(errs.len(), 1);
assert_eq!(args, vec![
OsString::from("quux"),
OsString::from("baz"),
]);
}
}

57
src/logger.rs Normal file
View File

@@ -0,0 +1,57 @@
// This module defines a super simple logger that works with the `log` crate.
// We don't need anything fancy; just basic log levels and the ability to
// print to stderr. We therefore avoid bringing in extra dependencies just
// for this functionality.
use log::{self, Log};
/// The simplest possible logger that logs to stderr.
///
/// This logger does no filtering. Instead, it relies on the `log` crates
/// filtering via its global max_level setting.
#[derive(Debug)]
pub struct Logger(());
const LOGGER: &'static Logger = &Logger(());
impl Logger {
/// Create a new logger that logs to stderr and initialize it as the
/// global logger. If there was a problem setting the logger, then an
/// error is returned.
pub fn init() -> Result<(), log::SetLoggerError> {
log::set_logger(LOGGER)
}
}
impl Log for Logger {
fn enabled(&self, _: &log::Metadata) -> bool {
// We set the log level via log::set_max_level, so we don't need to
// implement filtering here.
true
}
fn log(&self, record: &log::Record) {
match (record.file(), record.line()) {
(Some(file), Some(line)) => {
eprintln!(
"{}/{}/{}:{}: {}",
record.level(), record.target(),
file, line, record.args());
}
(Some(file), None) => {
eprintln!(
"{}/{}/{}: {}",
record.level(), record.target(), file, record.args());
}
_ => {
eprintln!(
"{}/{}: {}",
record.level(), record.target(), record.args());
}
}
}
fn flush(&self) {
// We use eprintln! which is flushed on every call.
}
}

View File

@@ -3,7 +3,6 @@ extern crate bytecount;
#[macro_use]
extern crate clap;
extern crate encoding_rs;
extern crate env_logger;
extern crate globset;
extern crate grep;
extern crate ignore;
@@ -40,8 +39,10 @@ macro_rules! errored {
mod app;
mod args;
mod config;
mod decoder;
mod decompressor;
mod logger;
mod pathutil;
mod printer;
mod search_buffer;
@@ -49,7 +50,7 @@ mod search_stream;
mod unescape;
mod worker;
pub type Result<T> = result::Result<T, Box<Error + Send + Sync>>;
pub type Result<T> = result::Result<T, Box<Error>>;
fn main() {
reset_sigpipe();

View File

@@ -555,7 +555,8 @@ impl fmt::Display for Error {
}
Error::UnrecognizedStyle(ref name) => {
write!(f, "Unrecognized style attribute '{}'. Choose from: \
nobold, bold, nointense, intense.", name)
nobold, bold, nointense, intense, nounderline, \
underline.", name)
}
Error::InvalidFormat(ref original) => {
write!(
@@ -627,7 +628,8 @@ pub struct ColorSpecs {
/// Valid colors are `black`, `blue`, `green`, `red`, `cyan`, `magenta`,
/// `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)]
pub struct Spec {
ty: OutType,
@@ -668,6 +670,8 @@ enum Style {
NoBold,
Intense,
NoIntense,
Underline,
NoUnderline
}
impl ColorSpecs {
@@ -727,6 +731,8 @@ impl SpecValue {
Style::NoBold => { cspec.set_bold(false); }
Style::Intense => { cspec.set_intense(true); }
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),
"intense" => Ok(Style::Intense),
"nointense" => Ok(Style::NoIntense),
"underline" => Ok(Style::Underline),
"nounderline" => Ok(Style::NoUnderline),
_ => Err(Error::UnrecognizedStyle(s.to_string())),
}
}
@@ -859,6 +867,12 @@ mod tests {
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();
assert_eq!(spec, Spec {
ty: OutType::Line,

View File

@@ -1,6 +1,6 @@
[package]
name = "termcolor"
version = "0.3.3" #:version
version = "0.3.4" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """
A simple cross platform library for writing colored text to a terminal.
@@ -17,4 +17,4 @@ name = "termcolor"
bench = false
[target.'cfg(windows)'.dependencies]
wincolor = { version = "0.1.3", path = "../wincolor" }
wincolor = { version = "0.1.6", path = "../wincolor" }

View File

@@ -104,7 +104,7 @@ pub trait WriteColor: io::Write {
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 set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
(&mut **self).set_color(spec)
@@ -239,7 +239,7 @@ impl io::Write for IoStandardStream {
}
}
/// Same rigmarole 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>),
@@ -328,14 +328,17 @@ impl StandardStream {
/// the `WriteColor` trait.
#[cfg(windows)]
fn create(sty: StandardStreamType, choice: ColorChoice) -> StandardStream {
let con = match sty {
let mut con = match sty {
StandardStreamType::Stdout => wincolor::Console::stdout(),
StandardStreamType::Stderr => wincolor::Console::stderr(),
};
let is_win_console = con.is_ok();
let is_console_virtual = con.as_mut().map(|con| {
con.set_virtual_terminal_processing(true).is_ok()
}).unwrap_or(false);
let wtr =
if choice.should_attempt_color() {
if choice.should_ansi() {
if choice.should_ansi() || is_console_virtual {
WriterInner::Ansi(Ansi(IoStandardStream::new(sty)))
} else if let Ok(console) = con {
WriterInner::Windows {
@@ -612,10 +615,18 @@ impl BufferWriter {
/// the buffers themselves.
#[cfg(windows)]
fn create(sty: StandardStreamType, choice: ColorChoice) -> BufferWriter {
let con = match sty {
let mut con = match sty {
StandardStreamType::Stdout => wincolor::Console::stdout(),
StandardStreamType::Stderr => wincolor::Console::stderr(),
}.ok().map(Mutex::new);
}.ok();
let is_console_virtual = con.as_mut().map(|con| {
con.set_virtual_terminal_processing(true).is_ok()
}).unwrap_or(false);
// If we can enable ANSI on Windows, then we don't need the console
// anymore.
if is_console_virtual {
con = None;
}
let stream = LossyStandardStream::new(IoStandardStream::new(sty))
.is_console(con.is_some());
BufferWriter {
@@ -623,7 +634,7 @@ impl BufferWriter {
printed: AtomicBool::new(false),
separator: None,
color_choice: choice,
console: con,
console: con.map(Mutex::new),
}
}
@@ -969,6 +980,9 @@ impl<W: io::Write> WriteColor for Ansi<W> {
if spec.bold {
self.write_str("\x1B[1m")?;
}
if spec.underline {
self.write_str("\x1B[4m")?;
}
Ok(())
}
@@ -1201,6 +1215,7 @@ pub struct ColorSpec {
bg_color: Option<Color>,
bold: bool,
intense: bool,
underline: bool,
}
impl ColorSpec {
@@ -1240,10 +1255,37 @@ impl ColorSpec {
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.
///
/// 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 }
/// 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 {
self.intense = yes;
self
@@ -1251,7 +1293,8 @@ impl ColorSpec {
/// Returns true if this color specification has no colors or styles.
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.
@@ -1259,6 +1302,7 @@ impl ColorSpec {
self.fg_color = None;
self.bg_color = None;
self.bold = false;
self.underline = false;
}
/// Writes this color spec to the given Windows console.
@@ -1293,7 +1337,18 @@ impl ColorSpec {
/// on Windows using the console. If they are used on Windows, then they are
/// silently ignored and no colors will be emitted.
///
/// Note that this set may expand over time.
/// This set may expand over time.
///
/// This type has a `FromStr` impl that can parse colors from their human
/// readable form. The format is as follows:
///
/// 1. Any of the explicitly listed colors in English. They are matched
/// case insensitively.
/// 2. A single 8-bit integer, in either decimal or hexadecimal format.
/// 3. A triple of 8-bit integers separated by a comma, where each integer is
/// in decimal or hexadecimal format.
///
/// Hexadecimal numbers are written with a `0x` prefix.
#[allow(missing_docs)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Color {
@@ -1311,9 +1366,9 @@ pub enum Color {
__Nonexhaustive,
}
#[cfg(windows)]
impl Color {
/// Translate this color to a wincolor::Color.
#[cfg(windows)]
fn to_windows(&self) -> Option<wincolor::Color> {
match *self {
Color::Black => Some(wincolor::Color::Black),
@@ -1329,6 +1384,68 @@ impl Color {
Color::__Nonexhaustive => unreachable!(),
}
}
/// Parses a numeric color string, either ANSI or RGB.
fn from_str_numeric(s: &str) -> Result<Color, ParseColorError> {
// The "ansi256" format is a single number (decimal or hex)
// corresponding to one of 256 colors.
//
// The "rgb" format is a triple of numbers (decimal or hex) delimited
// by a comma corresponding to one of 256^3 colors.
fn parse_number(s: &str) -> Option<u8> {
use std::u8;
if s.starts_with("0x") {
u8::from_str_radix(&s[2..], 16).ok()
} else {
u8::from_str_radix(s, 10).ok()
}
}
let codes: Vec<&str> = s.split(',').collect();
if codes.len() == 1 {
if let Some(n) = parse_number(&codes[0]) {
Ok(Color::Ansi256(n))
} else {
if s.chars().all(|c| c.is_digit(16)) {
Err(ParseColorError {
kind: ParseColorErrorKind::InvalidAnsi256,
given: s.to_string(),
})
} else {
Err(ParseColorError {
kind: ParseColorErrorKind::InvalidName,
given: s.to_string(),
})
}
}
} else if codes.len() == 3 {
let mut v = vec![];
for code in codes {
let n = parse_number(code).ok_or_else(|| {
ParseColorError {
kind: ParseColorErrorKind::InvalidRgb,
given: s.to_string(),
}
})?;
v.push(n);
}
Ok(Color::Rgb(v[0], v[1], v[2]))
} else {
Err(if s.contains(",") {
ParseColorError {
kind: ParseColorErrorKind::InvalidRgb,
given: s.to_string(),
}
} else {
ParseColorError {
kind: ParseColorErrorKind::InvalidName,
given: s.to_string(),
}
})
}
}
}
/// An error from parsing an invalid color specification.
@@ -1373,13 +1490,13 @@ impl fmt::Display for ParseColorError {
}
InvalidAnsi256 => {
write!(f, "unrecognized ansi256 color number, \
should be '[0-255]', but is '{}'",
should be '[0-255]' (or a hex number), but is '{}'",
self.given)
}
InvalidRgb => {
write!(f, "unrecognized RGB color triple, \
should be '[0-255],[0-255],[0-255]', but is '{}'",
self.given)
should be '[0-255],[0-255],[0-255]' (or a hex \
triple), but is '{}'", self.given)
}
}
}
@@ -1398,52 +1515,7 @@ impl FromStr for Color {
"magenta" => Ok(Color::Magenta),
"yellow" => Ok(Color::Yellow),
"white" => Ok(Color::White),
_ => {
// - Ansi256: '[0-255]'
// - Rgb: '[0-255],[0-255],[0-255]'
let codes: Vec<&str> = s.split(',').collect();
if codes.len() == 1 {
if let Ok(n) = codes[0].parse::<u8>() {
Ok(Color::Ansi256(n))
} else {
if s.chars().all(|c| c.is_digit(10)) {
Err(ParseColorError {
kind: ParseColorErrorKind::InvalidAnsi256,
given: s.to_string(),
})
} else {
Err(ParseColorError {
kind: ParseColorErrorKind::InvalidName,
given: s.to_string(),
})
}
}
} else if codes.len() == 3 {
let mut v = vec![];
for code in codes {
let n = code.parse::<u8>().map_err(|_| {
ParseColorError {
kind: ParseColorErrorKind::InvalidRgb,
given: s.to_string(),
}
})?;
v.push(n);
}
Ok(Color::Rgb(v[0], v[1], v[2]))
} else {
Err(if s.contains(",") {
ParseColorError {
kind: ParseColorErrorKind::InvalidRgb,
given: s.to_string(),
}
} else {
ParseColorError {
kind: ParseColorErrorKind::InvalidName,
given: s.to_string(),
}
})
}
}
_ => Color::from_str_numeric(s),
}
}
}
@@ -1550,9 +1622,11 @@ mod tests {
let color = "7".parse::<Color>();
assert_eq!(color, Ok(Color::Ansi256(7)));
// In range of standard color codes
let color = "32".parse::<Color>();
assert_eq!(color, Ok(Color::Ansi256(32)));
let color = "0xFF".parse::<Color>();
assert_eq!(color, Ok(Color::Ansi256(0xFF)));
}
#[test]
@@ -1571,6 +1645,12 @@ mod tests {
let color = "0,128,255".parse::<Color>();
assert_eq!(color, Ok(Color::Rgb(0, 128, 255)));
let color = "0x0,0x0,0x0".parse::<Color>();
assert_eq!(color, Ok(Color::Rgb(0, 0, 0)));
let color = "0x33,0x66,0xFF".parse::<Color>();
assert_eq!(color, Ok(Color::Rgb(0x33, 0x66, 0xFF)));
}
#[test]

View File

@@ -1152,7 +1152,8 @@ clean!(regression_428_unrecognized_style, "Sherlok", ".",
let output = cmd.output().unwrap();
let err = String::from_utf8_lossy(&output.stderr);
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);
});
@@ -1166,6 +1167,49 @@ clean!(regression_493, " 're ", "input.txt", |wd: WorkDir, mut cmd: Command| {
assert_eq!(lines, " 're \n");
});
// See: https://github.com/BurntSushi/ripgrep/issues/553
sherlock!(regression_553_switch, "sherlock", ".",
|wd: WorkDir, mut cmd: Command| {
cmd.arg("-i");
let lines: String = wd.stdout(&mut cmd);
let expected = "\
sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock
sherlock:be, to a very large extent, the result of luck. Sherlock Holmes
";
assert_eq!(lines, expected);
// This repeats the `-i` flag.
cmd.arg("-i");
let lines: String = wd.stdout(&mut cmd);
let expected = "\
sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock
sherlock:be, to a very large extent, the result of luck. Sherlock Holmes
";
assert_eq!(lines, expected);
});
sherlock!(regression_553_flag, "world|attached",
|wd: WorkDir, mut cmd: Command| {
cmd.arg("-C").arg("1");
let lines: String = wd.stdout(&mut cmd);
let expected = "\
For the Doctor Watsons of this world, as opposed to the Sherlock
Holmeses, success in the province of detective work must always
--
but Doctor Watson has to have it taken out for him and dusted,
and exhibited clearly, with a label attached.
";
assert_eq!(lines, expected);
cmd.arg("-C").arg("0");
let lines: String = wd.stdout(&mut cmd);
let expected = "\
For the Doctor Watsons of this world, as opposed to the Sherlock
and exhibited clearly, with a label attached.
";
assert_eq!(lines, expected);
});
// 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");
@@ -1189,6 +1233,19 @@ clean!(regression_599, "^$", "input.txt", |wd: WorkDir, mut cmd: Command| {
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
clean!(feature_1_sjis, "Шерлок Холмс", ".", |wd: WorkDir, mut cmd: Command| {
let sherlock =
@@ -1711,6 +1768,22 @@ fn compressed_failing_gzip() {
assert_eq!(err.contains("not in gzip format"), true);
}
sherlock!(feature_196_persistent_config, "sherlock",
|wd: WorkDir, mut cmd: Command| {
// Make sure we get no matches by default.
wd.assert_err(&mut cmd);
// Now add our config file, and make sure it impacts ripgrep.
wd.create(".ripgreprc", "--ignore-case");
cmd.env("RIPGREP_CONFIG_PATH", ".ripgreprc");
let lines: String = wd.stdout(&mut cmd);
let expected = "\
For the Doctor Watsons of this world, as opposed to the Sherlock
be, to a very large extent, the result of luck. Sherlock Holmes
";
assert_eq!(lines, expected);
});
#[test]
fn feature_740_passthru() {
let wd = WorkDir::new("feature_740");

View File

@@ -93,6 +93,7 @@ impl WorkDir {
/// this working directory.
pub fn command(&self) -> process::Command {
let mut cmd = process::Command::new(&self.bin());
cmd.env_remove("RIPGREP_CONFIG_PATH");
cmd.current_dir(&self.dir);
cmd
}

View File

@@ -1,6 +1,6 @@
[package]
name = "wincolor"
version = "0.1.5" #:version
version = "0.1.6" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """
A simple Windows specific API for controlling text color in a Windows console.
@@ -16,5 +16,6 @@ license = "Unlicense/MIT"
name = "wincolor"
bench = false
[dependencies]
winapi = { version = "0.3", features = ["minwindef", "processenv", "winbase", "wincon"] }
[dependencies.winapi]
version = "0.3"
features = ["consoleapi", "minwindef", "processenv", "winbase", "wincon"]

View File

@@ -2,6 +2,7 @@ use std::io;
use std::mem;
use winapi::shared::minwindef::{DWORD, WORD};
use winapi::um::consoleapi;
use winapi::um::processenv;
use winapi::um::winbase::{STD_ERROR_HANDLE, STD_OUTPUT_HANDLE};
use winapi::um::wincon::{
@@ -115,6 +116,41 @@ impl Console {
self.cur_attr = self.start_attr;
self.set()
}
/// Toggle virtual terminal processing.
///
/// This method attempts to toggle virtual terminal processing for this
/// console. If there was a problem toggling it, then an error returned.
/// On success, the caller may assume that toggling it was successful.
///
/// When virtual terminal processing is enabled, characters emitted to the
/// console are parsed for VT100 and similar control character sequences
/// that control color and other similar operations.
pub fn set_virtual_terminal_processing(
&mut self,
yes: bool,
) -> io::Result<()> {
let vt = wincon::ENABLE_VIRTUAL_TERMINAL_PROCESSING;
let mut old_mode = 0;
let handle = unsafe { processenv::GetStdHandle(self.handle_id) };
if unsafe { consoleapi::GetConsoleMode(handle, &mut old_mode) } == 0 {
return Err(io::Error::last_os_error());
}
let new_mode =
if yes {
old_mode | vt
} else {
old_mode & !vt
};
if old_mode == new_mode {
return Ok(());
}
if unsafe { consoleapi::SetConsoleMode(handle, new_mode) } == 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
/// A representation of text attributes for the Windows console.