From 904c75bd302311fe9e5e5a7238299e0105e19c8b Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Tue, 6 Feb 2018 18:49:30 -0500 Subject: [PATCH] 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. --- Cargo.toml | 2 +- FAQ.md | 369 ++++++++++++++++++++++++++ GUIDE.md | 676 +++++++++++++++++++++++++++++++++++++++++++++++ README.md | 430 +++++------------------------- doc/rg.1.txt.tpl | 22 +- src/app.rs | 14 +- 6 files changed, 1144 insertions(+), 369 deletions(-) create mode 100644 FAQ.md create mode 100644 GUIDE.md diff --git a/Cargo.toml b/Cargo.toml index c7c9dfa3..db337d82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ members = ["grep", "globset", "ignore", "termcolor", "wincolor"] atty = "0.2.2" bytecount = "0.3.1" encoding_rs = "0.7" +globset = { version = "0.2.1", path = "globset" } grep = { version = "0.1.7", path = "grep" } ignore = { version = "0.3.1", path = "ignore" } lazy_static = "1" @@ -47,7 +48,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" } [dependencies.clap] version = "2.29.4" diff --git a/FAQ.md b/FAQ.md new file mode 100644 index 00000000..063a7888 --- /dev/null +++ b/FAQ.md @@ -0,0 +1,369 @@ +## 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 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) + + +

+Does ripgrep support configuration files? +

+ +Yes. See the [guide's section on configuration files](#configuration-file). + + +

+What's changed in ripgrep recently? +

+ +Please consult ripgrep's [CHANGELOG](CHANGELOG.md). + + +

+When is the next release? +

+ +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. + + +

+Does ripgrep have a man page? +

+ +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). + + +

+Does ripgrep have support for shell auto-completion? +

+ +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. + + +

+How can I get results in a consistent order? +

+ +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 + + +

+How do I search files that aren't UTF-8? +

+ +See the [guide's section on file encoding](GUIDE.md#file-encoding). + + +

+How do I search compressed files? +

+ +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. + + +

+How do I search over multiple lines? +

+ +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). + + +

+How do I use lookaround and/or backreferences? +

+ +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. + + +

+How do I stop ripgrep from messing up colors when I kill it? +

+ +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). + + +

+How do I get around the regex size limit? +

+ +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. + + +

+How do I make the -f/--file flag faster? +

+ +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.) + + +

+How do I make the output look like The Silver Searcher's output? +

+ +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 +``` + + +

+When I run rg, why does it execute 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'`. + + +

+How do I create an alias for ripgrep on Windows? +

+ +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`. + + +

+How do I create a 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 +[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. + + +

+How do I pipe non-ASCII content to ripgrep on Windows? +

+ +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. diff --git a/GUIDE.md b/GUIDE.md new file mode 100644 index 00000000..c1e58313 --- /dev/null +++ b/GUIDE.md @@ -0,0 +1,676 @@ +## 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. +``` + +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 { +250: fn write(&mut self, b: &[u8]) -> io::Result { +428: fn write(&mut self, b: &[u8]) -> io::Result { self.wtr.write(b) } +441: fn write(&mut self, b: &[u8]) -> io::Result { self.wtr.write(b) } +454: fn write(&mut self, buf: &[u8]) -> io::Result { +511: fn write(&mut self, buf: &[u8]) -> io::Result { +848: fn write(&mut self, buf: &[u8]) -> io::Result { +915: fn write(&mut self, buf: &[u8]) -> io::Result { +949: fn write(&mut self, buf: &[u8]) -> io::Result { +1114: fn write(&mut self, buf: &[u8]) -> io::Result { +1348: fn write(&mut self, buf: &[u8]) -> io::Result { +1353: fn write(&mut self, buf: &[u8]) -> io::Result { +``` + +(**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\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. diff --git a/README.md b/README.md index 502cfa5c..ca1ed5ce 100644 --- a/README.md +++ b/README.md @@ -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`? + +### 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 +* 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,11 +158,19 @@ 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. @@ -179,53 +197,53 @@ $ 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 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). @@ -234,8 +252,8 @@ If you're an **Ubuntu** user, `ripgrep` can be installed from the `snap` store. 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,189 +263,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[A-Z][a-z]+)\s+(?P[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). - -### 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 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 @@ -437,8 +281,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' @@ -447,144 +291,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'` diff --git a/doc/rg.1.txt.tpl b/doc/rg.1.txt.tpl index a1068c09..911cba71 100644 --- a/doc/rg.1.txt.tpl +++ b/doc/rg.1.txt.tpl @@ -10,7 +10,9 @@ Synopsis -------- *rg* [_OPTIONS_] _PATTERN_ [_PATH_...] -*rg* [_OPTIONS_] [*-e* _PATTERN_...] [*-f* _PATH_...] [_PATH_...] +*rg* [_OPTIONS_] *-e* _PATTERN_... [_PATH_...] + +*rg* [_OPTIONS_] *-f* _PATH_... [_PATH_...] *rg* [_OPTIONS_] *--files* [_PATH_...] @@ -32,6 +34,20 @@ 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_:: @@ -105,11 +121,13 @@ 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` +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 ------- diff --git a/src/app.rs b/src/app.rs index 0e0a7a76..f2f214d3 100644 --- a/src/app.rs +++ b/src/app.rs @@ -13,15 +13,13 @@ use clap::{self, App, AppSettings}; const ABOUT: &str = " 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. -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. - ripgrep supports configuration files. Set RIPGREP_CONFIG_PATH to a configuration file. The file can specify one shell argument per line. Lines starting with '#' are ignored. For more details, see the man page or the @@ -857,9 +855,9 @@ fn flag_files_without_match(args: &mut Vec) { const SHORT: &str = "Only print the paths that contain zero matches."; const LONG: &str = long!("\ Only print the paths that contain zero matches. This inverts/negates the ---file-with-matches flag. +--files-with-matches flag. -This overrides --file-with-matches. +This overrides --files-with-matches. "); let arg = RGArg::switch("files-without-match") .help(SHORT).long_help(LONG) @@ -900,7 +898,7 @@ This flag can be disabled with --no-follow. } fn flag_glob(args: &mut Vec) { - const SHORT: &str = "Include or exclude files and directories."; + const SHORT: &str = "Include or exclude files."; const LONG: &str = long!("\ Include or exclude files and directories for searching that match the given glob. This always overrides any other ignore logic. Multiple glob flags may be @@ -964,7 +962,7 @@ This flag can be disabled with --no-hidden. fn flag_iglob(args: &mut Vec) { const SHORT: &str = - "Include or exclude files and directories case insensitively."; + "Include or exclude files case insensitively."; const LONG: &str = long!("\ Include or exclude files and directories for searching that match the given glob. This always overrides any other ignore logic. Multiple glob flags may be