Compare commits

..

18 Commits

Author SHA1 Message Date
Andrew Gallant
ac1c95a6d9 0.5.1 2017-04-09 09:47:00 -04:00
Andrew Gallant
685b431d80 bump deps 2017-04-09 09:46:37 -04:00
Andrew Gallant
487713aa34 bump ignore 2017-04-09 09:45:00 -04:00
Andrew Gallant
e300541701 changelog 0.5.1 2017-04-09 09:43:16 -04:00
Andrew Gallant
e9df420d2f Add ability to colorize column numbers.
Fixes #377
2017-04-09 09:08:49 -04:00
Andrew Gallant
201b4fc757 update man page 2017-04-09 08:49:19 -04:00
Roman Proskuryakov
90a11dec5e Add -o/--only-matching flag.
Currently, the `--only-matching` flag conflicts with the `--replace`
flag. In the future, this restriction may be relaxed.

Fixes #34
2017-04-09 08:47:35 -04:00
Douman
9456d95e8f Add short note on Windows Tips 2017-04-09 08:32:23 -04:00
Kevin K
0c298f60a6 updates clap and removes home rolled -h/--help distinction
This commit updates clap to v2.23.0

The update contained a bug fix in clap that results in broken code in
ripgrep. ripgrep was relying on the bug, but this commit fixes that
issue. The bug centered around not being able to override the
auto-generated help message by supplying a flag with a long of `help`.

Normally, supplying a flag with a long of `help` means whenever the user
passes `--help`, the consuming code (e.g. ripgrep) is responsible for
displaying the help message. However, due to the bug in clap this wasn't
necessary for ripgrep to do unless the user passed `-h`. With the bug
fixed, it meant the user passing `--help` and clap expected ripgrep to
display the help, yet ripgrep expected clap to display the help. This
has been fixed in this commit of ripgrep.

All well now!

v2.23.0 also brings the abilty to use `Arg::help` or `Arg::long_help`
allowing one to distinguish between `-h` and `--help`. This commit
leaves all doc strings in the `lazy_static!` hashmap however only for
aesthetic reasons.

This means all home rolled handling of `-h`/`--help` has been removed
from ripgrep, yet functionality *and* appearances are 100% the same.
2017-04-05 11:38:58 -04:00
Kosta Welke
79271fcb33 fix typo in comment 2017-04-05 07:06:58 -04:00
Andrew Gallant
fc975af8e9 Enforce 79 column limit. Grr. 2017-03-31 15:59:04 -04:00
Roman Proskuryakov
1425d6735e Bamp clap to 2.22.2
Fixes #426 , #418
2017-03-31 15:56:10 -04:00
Roman Proskuryakov
aed3ccb9c7 Improves Printer, fixes some bugs 2017-03-31 14:44:13 -04:00
Andrew Gallant
33c95d2919 bump deps 2017-03-30 12:33:31 -04:00
Roman Proskuryakov
01deac9427 Add -0 shortcut for --null
Fixes #419
2017-03-28 18:37:40 -04:00
Andrew Gallant
b4bc3b6349 remove uninstall step 2017-03-28 12:14:15 -04:00
Andrew Gallant
685cc6c562 Add vim type.
It's the same as the vimscript type, but shorter and more obvious.

Fixes #415
2017-03-21 07:56:49 -04:00
Andrew Gallant
08c017330f bump termcolor dep 2017-03-15 07:15:39 -04:00
16 changed files with 311 additions and 170 deletions

View File

@@ -1,3 +1,26 @@
0.5.1 (2017-04-09)
==================
Feature enhancements:
* Added or improved file type filtering for vim.
* [FEATURE #34](https://github.com/BurntSushi/ripgrep/issues/34):
Add a `-o/--only-matching` flag.
* [FEATURE #377](https://github.com/BurntSushi/ripgrep/issues/377):
Column numbers can now be customized with a color. (The default is
no color.)
* [FEATURE #419](https://github.com/BurntSushi/ripgrep/issues/419):
Added `-0` short flag option for `--null`.
Bug fixes:
* [BUG #381](https://github.com/BurntSushi/ripgrep/issues/381):
Include license text in all subcrates.
* [BUG #418](https://github.com/BurntSushi/ripgrep/issues/418),
[BUG #426](https://github.com/BurntSushi/ripgrep/issues/426),
[BUG #439](https://github.com/BurntSushi/ripgrep/issues/439):
Fix a few bugs with `-h/--help` output.
0.5.0 (2017-03-12) 0.5.0 (2017-03-12)
================== ==================
This is a new minor version release of ripgrep that includes one minor breaking This is a new minor version release of ripgrep that includes one minor breaking

38
Cargo.lock generated
View File

@@ -1,15 +1,15 @@
[root] [root]
name = "ripgrep" name = "ripgrep"
version = "0.5.0" version = "0.5.1"
dependencies = [ dependencies = [
"atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"bytecount 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "bytecount 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.23.1 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding_rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "encoding_rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"grep 0.1.6", "grep 0.1.6",
"ignore 0.1.8", "ignore 0.1.9",
"lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -17,12 +17,12 @@ dependencies = [
"num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 0.3.1", "termcolor 0.3.2",
] ]
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "0.6.2" version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -45,7 +45,7 @@ dependencies = [
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "0.8.0" version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@@ -63,12 +63,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "clap" name = "clap"
version = "2.21.1" version = "2.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -116,7 +116,7 @@ dependencies = [
name = "globset" name = "globset"
version = "0.1.4" version = "0.1.4"
dependencies = [ dependencies = [
"aho-corasick 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -135,11 +135,11 @@ dependencies = [
[[package]] [[package]]
name = "ignore" name = "ignore"
version = "0.1.8" version = "0.1.9"
dependencies = [ dependencies = [
"crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"globset 0.1.4", "globset 0.1.4",
"lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -158,7 +158,7 @@ dependencies = [
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "0.2.4" version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@@ -203,7 +203,7 @@ name = "regex"
version = "0.2.1" version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"aho-corasick 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"simd 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "simd 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -247,7 +247,7 @@ dependencies = [
[[package]] [[package]]
name = "termcolor" name = "termcolor"
version = "0.3.1" version = "0.3.2"
dependencies = [ dependencies = [
"wincolor 0.1.3", "wincolor 0.1.3",
] ]
@@ -332,20 +332,20 @@ dependencies = [
] ]
[metadata] [metadata]
"checksum aho-corasick 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0638fd549427caa90c499814196d1b9e3725eb4d15d7339d6de073a680ed0ca2" "checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699"
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159" "checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159"
"checksum bitflags 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e1ab483fc81a8143faa7203c4a3c02888ebd1a782e37e41fa34753ba9a162" "checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4"
"checksum bytecount 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1e8f09fbc8c6726a4b616dcfbd4f54491068d6bb1b93ac03c78ac18ff9a5924a" "checksum bytecount 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1e8f09fbc8c6726a4b616dcfbd4f54491068d6bb1b93ac03c78ac18ff9a5924a"
"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c" "checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
"checksum clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "74a80f603221c9cd9aa27a28f52af452850051598537bb6b359c38a7d61e5cda" "checksum clap 2.23.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d480c39a2e5f9b3a3798c661613e1b0e7a7ae71e005102d4aa910fc3289df484"
"checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97" "checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97"
"checksum encoding_rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a1cca0a26f904955d80d70b9bff1019e4f4cbc06f2fcbccf8bd3d889cc1c9b7" "checksum encoding_rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a1cca0a26f904955d80d70b9bff1019e4f4cbc06f2fcbccf8bd3d889cc1c9b7"
"checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83" "checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83"
"checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344" "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
"checksum fs2 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34edaee07555859dc13ca387e6ae05686bb4d0364c95d649b6dab959511f4baf" "checksum fs2 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34edaee07555859dc13ca387e6ae05686bb4d0364c95d649b6dab959511f4baf"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7291b1dd97d331f752620b02dfdbc231df7fc01bf282a00769e1cdb963c460dc" "checksum lazy_static 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2f61b8421c7a4648c391611625d56fdd5c7567da05af1be655fd8cacc643abb3"
"checksum libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "88ee81885f9f04bff991e306fea7c1c60a5f0f9e409e99f6b40e3311a3363135" "checksum libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "88ee81885f9f04bff991e306fea7c1c60a5f0f9e409e99f6b40e3311a3363135"
"checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad" "checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad"
"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "ripgrep" name = "ripgrep"
version = "0.5.0" #:version version = "0.5.1" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"] authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """ description = """
Line oriented search tool using Rust's regex library. Combines the raw Line oriented search tool using Rust's regex library. Combines the raw
@@ -28,11 +28,11 @@ path = "tests/tests.rs"
[dependencies] [dependencies]
atty = "0.2.2" atty = "0.2.2"
bytecount = "0.1.4" bytecount = "0.1.4"
clap = "2.20.5" clap = "2.23.1"
encoding_rs = "0.5.0" encoding_rs = "0.5.0"
env_logger = { version = "0.4", default-features = false } env_logger = { version = "0.4", default-features = false }
grep = { version = "0.1.5", path = "grep" } grep = { version = "0.1.5", path = "grep" }
ignore = { version = "0.1.7", path = "ignore" } ignore = { version = "0.1.9", path = "ignore" }
lazy_static = "0.2" lazy_static = "0.2"
libc = "0.2" libc = "0.2"
log = "0.3" log = "0.3"
@@ -44,7 +44,7 @@ same-file = "0.1.1"
termcolor = { version = "0.3.0", path = "termcolor" } termcolor = { version = "0.3.0", path = "termcolor" }
[build-dependencies] [build-dependencies]
clap = "2.18" clap = "2.23.1"
lazy_static = "0.2" lazy_static = "0.2"
[features] [features]

View File

@@ -378,6 +378,51 @@ $ cargo test
from the repository root. from the repository root.
### Tips
#### Windows Powershell
##### Powershell Profile
To customize powershell on start-up there is a special powershell script that has to be created.
In order to find its location run command `Get-Command $profile | Select-Object -ExpandProperty Definition`
See [more](https://technet.microsoft.com/en-us/library/bb613488(v=vs.85).aspx) for profile details.
Any powershell code in this file gets evaluated at the start of console.
This way you can have own aliases to be created at start.
##### Setup function alias
Often you can find a need to make alias for the favourite utility.
But powershell function aliases do not behave like your typical linux shell alias.
You always need to propagate arguments and **Stdin** input.
But it cannot be done simply as `function grep() { $input | rg.exe --hidden $args }`
Use below example as reference to how setup alias in powershell.
```powershell
function grep {
$count = @($input).Count
$input.Reset()
if ($count) {
$input | rg.exe --hidden $args
}
else {
rg.exe --hidden $args
}
}
```
Powershell special variables:
* input - is powershell **Stdin** object that allows you to access its content.
* args - is array of arguments passed to this function.
This alias checks whether there is **Stdin** input and propagates only if there is some lines.
Otherwise empty `$input` will make powershell to trigger `rg` to search empty **Stdin**
### Known issues ### Known issues
#### I just hit Ctrl+C in the middle of ripgrep's output and now my terminal's foreground color is wrong! #### I just hit Ctrl+C in the middle of ripgrep's output and now my terminal's foreground color is wrong!

View File

@@ -19,7 +19,7 @@ fn main() {
}; };
fs::create_dir_all(&outdir).unwrap(); fs::create_dir_all(&outdir).unwrap();
let mut app = app::app_short(); let mut app = app::app();
app.gen_completions("rg", Shell::Bash, &outdir); app.gen_completions("rg", Shell::Bash, &outdir);
app.gen_completions("rg", Shell::Fish, &outdir); app.gen_completions("rg", Shell::Fish, &outdir);
app.gen_completions("rg", Shell::Zsh, &outdir); app.gen_completions("rg", Shell::Zsh, &outdir);

View File

@@ -17,9 +17,6 @@ install_c_toolchain() {
} }
install_rustup() { install_rustup() {
# uninstall the rust toolchain installed by travis, we are going to use rustup
sh ~/rust/lib/rustlib/uninstall.sh
curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=$TRAVIS_RUST_VERSION curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=$TRAVIS_RUST_VERSION
rustc -V rustc -V

View File

@@ -181,7 +181,7 @@ Styles are limited to nobold, bold, nointense or intense.
.RS .RS
.PP .PP
The format of the flag is {type}:{attribute}:{value}. The format of the flag is {type}:{attribute}:{value}.
{type} should be one of path, line or match. {type} should be one of path, line, column or match.
{attribute} can be fg, bg or style. {attribute} can be fg, bg or style.
Value is either a color (for fg and bg) or a text style. Value is either a color (for fg and bg) or a text style.
A special format, {type}:none, will clear all color settings for {type}. A special format, {type}:none, will clear all color settings for {type}.
@@ -299,6 +299,13 @@ Follow symlinks.
.RS .RS
.RE .RE
.TP .TP
.B \-M, \-\-max\-columns \f[I]NUM\f[]
Don\[aq]t print lines longer than this limit in bytes.
Longer lines are omitted, and only the number of matches in that line is
printed.
.RS
.RE
.TP
.B \-m, \-\-max\-count \f[I]NUM\f[] .B \-m, \-\-max\-count \f[I]NUM\f[]
Limit the number of matching lines per file searched to NUM. Limit the number of matching lines per file searched to NUM.
.RS .RS
@@ -355,7 +362,7 @@ Note that .ignore files will continue to be respected.
.RS .RS
.RE .RE
.TP .TP
.B \-\-null .B \-0, \-\-null
Whenever a file name is printed, follow it with a NUL byte. Whenever a file name is printed, follow it with a NUL byte.
This includes printing filenames before matches, and when printing a This includes printing filenames before matches, and when printing a
list of matching files such as with \-\-count, \-\-files\-with\-matches list of matching files such as with \-\-count, \-\-files\-with\-matches
@@ -363,6 +370,12 @@ and \-\-files.
.RS .RS
.RE .RE
.TP .TP
.B \-o, \-\-only\-matching
Print only the matched (non\-empty) parts of a matching line, with each
such part on a separate output line.
.RS
.RE
.TP
.B \-\-path\-separator \f[I]SEPARATOR\f[] .B \-\-path\-separator \f[I]SEPARATOR\f[]
The path separator to use when printing file paths. The path separator to use when printing file paths.
This defaults to your platform\[aq]s path separator, which is / on Unix This defaults to your platform\[aq]s path separator, which is / on Unix

View File

@@ -123,9 +123,9 @@ Project home page: https://github.com/BurntSushi/ripgrep
black. Styles are limited to nobold, bold, nointense or intense. black. Styles are limited to nobold, bold, nointense or intense.
The format of the flag is {type}:{attribute}:{value}. {type} should be one The format of the flag is {type}:{attribute}:{value}. {type} should be one
of path, line or match. {attribute} can be fg, bg or style. Value is either of path, line, column or match. {attribute} can be fg, bg or style. Value
a color (for fg and bg) or a text style. A special format, {type}:none, is either a color (for fg and bg) or a text style. A special format,
will clear all color settings for {type}. {type}:none, will clear all color settings for {type}.
For example, the following command will change the match color to magenta For example, the following command will change the match color to magenta
and the background color for line numbers to yellow: and the background color for line numbers to yellow:
@@ -243,12 +243,16 @@ Project home page: https://github.com/BurntSushi/ripgrep
: Don't respect version control ignore files (e.g., .gitignore). : Don't respect version control ignore files (e.g., .gitignore).
Note that .ignore files will continue to be respected. Note that .ignore files will continue to be respected.
--null -0, --null
: Whenever a file name is printed, follow it with a NUL byte. : Whenever a file name is printed, follow it with a NUL byte.
This includes printing filenames before matches, and when printing This includes printing filenames before matches, and when printing
a list of matching files such as with --count, --files-with-matches a list of matching files such as with --count, --files-with-matches
and --files. and --files.
-o, --only-matching
: Print only the matched (non-empty) parts of a matching line, with each such
part on a separate output line.
--path-separator *SEPARATOR* --path-separator *SEPARATOR*
: The path separator to use when printing file paths. This defaults to your : The path separator to use when printing file paths. This defaults to your
platform's path separator, which is / on Unix and \\ on Windows. This flag is platform's path separator, which is / on Unix and \\ on Windows. This flag is

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "ignore" name = "ignore"
version = "0.1.8" #:version version = "0.1.9" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"] authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """ description = """
A fast library for efficiently matching ignore files such as `.gitignore` A fast library for efficiently matching ignore files such as `.gitignore`

View File

@@ -191,6 +191,7 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
("twig", &["*.twig"]), ("twig", &["*.twig"]),
("vala", &["*.vala"]), ("vala", &["*.vala"]),
("vb", &["*.vb"]), ("vb", &["*.vb"]),
("vim", &["*.vim"]),
("vimscript", &["*.vim"]), ("vimscript", &["*.vim"]),
("wiki", &["*.mediawiki", "*.wiki"]), ("wiki", &["*.mediawiki", "*.wiki"]),
("xml", &["*.xml"]), ("xml", &["*.xml"]),

View File

@@ -32,16 +32,6 @@ ARGS:
OPTIONS: OPTIONS:
{unified}"; {unified}";
/// Build a clap application with short help strings.
pub fn app_short() -> App<'static, 'static> {
app(false, |k| USAGES[k].short)
}
/// Build a clap application with long help strings.
pub fn app_long() -> App<'static, 'static> {
app(true, |k| USAGES[k].long)
}
/// Build a clap application parameterized by usage strings. /// Build a clap application parameterized by usage strings.
/// ///
/// The function given should take a clap argument name and return a help /// The function given should take a clap argument name and return a help
@@ -49,10 +39,9 @@ pub fn app_long() -> App<'static, 'static> {
/// ///
/// This is an intentionally stand-alone module so that it can be used easily /// This is an intentionally stand-alone module so that it can be used easily
/// in a `build.rs` script to build shell completion files. /// in a `build.rs` script to build shell completion files.
fn app<F>(next_line_help: bool, doc: F) -> App<'static, 'static> pub fn app() -> App<'static, 'static> {
where F: Fn(&'static str) -> &'static str {
let arg = |name| { let arg = |name| {
Arg::with_name(name).help(doc(name)).next_line_help(next_line_help) Arg::with_name(name).help(USAGES[name].short).long_help(USAGES[name].long)
}; };
let flag = |name| arg(name).long(name); let flag = |name| arg(name).long(name);
@@ -64,11 +53,7 @@ fn app<F>(next_line_help: bool, doc: F) -> App<'static, 'static>
.setting(AppSettings::UnifiedHelpMessage) .setting(AppSettings::UnifiedHelpMessage)
.usage(USAGE) .usage(USAGE)
.template(TEMPLATE) .template(TEMPLATE)
// Handle help/version manually to make their output formatting .help_message("Prints help information. Use --help for more details.")
// consistent with short/long views.
.arg(arg("help-short").short("h"))
.arg(flag("help"))
.arg(arg("ripgrep-version").long("version").short("V"))
// First, set up primary positional/flag arguments. // First, set up primary positional/flag arguments.
.arg(arg("pattern") .arg(arg("pattern")
.required_unless_one(&[ .required_unless_one(&[
@@ -158,7 +143,8 @@ fn app<F>(next_line_help: bool, doc: F) -> App<'static, 'static>
.arg(flag("no-ignore")) .arg(flag("no-ignore"))
.arg(flag("no-ignore-parent")) .arg(flag("no-ignore-parent"))
.arg(flag("no-ignore-vcs")) .arg(flag("no-ignore-vcs"))
.arg(flag("null")) .arg(flag("null").short("0"))
.arg(flag("only-matching").short("o").conflicts_with("replace"))
.arg(flag("path-separator").value_name("SEPARATOR").takes_value(true)) .arg(flag("path-separator").value_name("SEPARATOR").takes_value(true))
.arg(flag("pretty").short("p")) .arg(flag("pretty").short("p"))
.arg(flag("replace").short("r").value_name("ARG").takes_value(true)) .arg(flag("replace").short("r").value_name("ARG").takes_value(true))
@@ -249,12 +235,12 @@ lazy_static! {
red, blue, green, cyan, magenta, yellow, white and black. \ red, blue, green, cyan, magenta, yellow, white and black. \
Styles are limited to nobold, bold, nointense or intense.\n\n\ Styles are limited to nobold, bold, nointense or intense.\n\n\
The format of the flag is {type}:{attribute}:{value}. {type} \ The format of the flag is {type}:{attribute}:{value}. {type} \
should be one of path, line or match. {attribute} can be fg, bg \ should be one of path, line, column or match. {attribute} can \
or style. {value} is either a color (for fg and bg) or a text \ be fg, bg or style. {value} is either a color (for fg and bg) \
style. A special format, {type}:none, will clear all color \ or a text style. A special format, {type}:none, will clear all \
settings for {type}.\n\nFor example, the following command will \ color settings for {type}.\n\nFor example, the following \
change the match color to magenta and the background color for \ command will change the match color to magenta and the \
line numbers to yellow:\n\n\ background color for line numbers to yellow:\n\n\
rg --colors 'match:fg:magenta' --colors 'line:bg:yellow' foo."); rg --colors 'match:fg:magenta' --colors 'line:bg:yellow' foo.");
doc!(h, "encoding", doc!(h, "encoding",
"Specify the text encoding of files to search.", "Specify the text encoding of files to search.",
@@ -388,10 +374,11 @@ lazy_static! {
"Limit the number of matching lines per file searched to NUM."); "Limit the number of matching lines per file searched to NUM.");
doc!(h, "max-filesize", doc!(h, "max-filesize",
"Ignore files larger than NUM in size.", "Ignore files larger than NUM in size.",
"Ignore files larger than NUM in size. Does not ignore directories. \ "Ignore files larger than NUM in size. Does not ignore \
directories. \
\n\nThe input format accepts suffixes of K, M or G which \ \n\nThe input format accepts suffixes of K, M or G which \
correspond to kilobytes, megabytes and gigabytes. If no suffix is \ correspond to kilobytes, megabytes and gigabytes. If no suffix \
provided the input is treated as bytes. \ is provided the input is treated as bytes. \
\n\nExample: --max-filesize 50K or --max-filesize 80M"); \n\nExample: --max-filesize 50K or --max-filesize 80M");
doc!(h, "maxdepth", doc!(h, "maxdepth",
"Descend at most NUM directories.", "Descend at most NUM directories.",
@@ -435,6 +422,10 @@ lazy_static! {
printing a list of matching files such as with --count, \ printing a list of matching files such as with --count, \
--files-with-matches and --files. This option is useful for use \ --files-with-matches and --files. This option is useful for use \
with xargs."); with xargs.");
doc!(h, "only-matching",
"Print only matched parts of a line.",
"Print only the matched (non-empty) parts of a matching line, \
with each such part on a separate output line.");
doc!(h, "path-separator", doc!(h, "path-separator",
"Path separator to use when printing file paths.", "Path separator to use when printing file paths.",
"The path separator to use when printing file paths. This \ "The path separator to use when printing file paths. This \
@@ -496,8 +487,8 @@ lazy_static! {
permits specifying one or more other type names (separated by a \ permits specifying one or more other type names (separated by a \
comma) that have been defined and its rules will automatically \ comma) that have been defined and its rules will automatically \
be imported into the type specified. For example, to create a \ be imported into the type specified. For example, to create a \
type called src that matches C++, Python and Markdown files, one \ type called src that matches C++, Python and Markdown files, \
can use:\n\n\ one can use:\n\n\
--type-add 'src:include:cpp,py,md'\n\n\ --type-add 'src:include:cpp,py,md'\n\n\
Additional glob rules can still be added to the src type by \ Additional glob rules can still be added to the src type by \
using the --type-add flag again:\n\n\ using the --type-add flag again:\n\n\

View File

@@ -5,7 +5,6 @@ use std::fs;
use std::io::{self, BufRead}; use std::io::{self, BufRead};
use std::ops; use std::ops;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process;
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
@@ -66,6 +65,7 @@ pub struct Args {
no_ignore_vcs: bool, no_ignore_vcs: bool,
no_messages: bool, no_messages: bool,
null: bool, null: bool,
only_matching: bool,
path_separator: Option<u8>, path_separator: Option<u8>,
quiet: bool, quiet: bool,
quiet_matched: QuietMatched, quiet_matched: QuietMatched,
@@ -88,26 +88,7 @@ impl Args {
/// ///
/// Also, initialize a global logger. /// Also, initialize a global logger.
pub fn parse() -> Result<Args> { pub fn parse() -> Result<Args> {
use clap::ErrorKind::*; let matches = app::app().get_matches();
let matches = match app::app_short().get_matches_safe() {
Ok(matches) => matches,
Err(clap::Error { kind: HelpDisplayed, .. }) => {
let _ = ::app::app_long().print_help();
println!("");
process::exit(0);
}
Err(err) => err.exit(),
};
if matches.is_present("help-short") {
let _ = ::app::app_short().print_help();
println!("");
process::exit(0);
}
if matches.is_present("ripgrep-version") {
println!("ripgrep {}", crate_version!());
process::exit(0);
}
let mut logb = env_logger::LogBuilder::new(); let mut logb = env_logger::LogBuilder::new();
if matches.is_present("debug") { if matches.is_present("debug") {
@@ -161,6 +142,7 @@ impl Args {
.heading(self.heading) .heading(self.heading)
.line_per_match(self.line_per_match) .line_per_match(self.line_per_match)
.null(self.null) .null(self.null)
.only_matching(self.only_matching)
.path_separator(self.path_separator) .path_separator(self.path_separator)
.with_filename(self.with_filename) .with_filename(self.with_filename)
.max_columns(self.max_columns); .max_columns(self.max_columns);
@@ -365,6 +347,7 @@ impl<'a> ArgMatches<'a> {
no_ignore_vcs: self.no_ignore_vcs(), no_ignore_vcs: self.no_ignore_vcs(),
no_messages: self.is_present("no-messages"), no_messages: self.is_present("no-messages"),
null: self.is_present("null"), null: self.is_present("null"),
only_matching: self.is_present("only-matching"),
path_separator: try!(self.path_separator()), path_separator: try!(self.path_separator()),
quiet: quiet, quiet: quiet,
quiet_matched: QuietMatched::new(quiet), quiet_matched: QuietMatched::new(quiet),
@@ -837,7 +820,7 @@ impl<'a> ArgMatches<'a> {
let caps = try!(re.captures(&max_filesize) let caps = try!(re.captures(&max_filesize)
.ok_or("invalid format for max-filesize argument")); .ok_or("invalid format for max-filesize argument"));
let value = try!(caps[1].parse::<u64>().map_err(|err| err.to_string())); let value = try!(caps[1].parse::<u64>().map_err(|err|err.to_string()));
let suffix = caps.get(2).map(|x| x.as_str()); let suffix = caps.get(2).map(|x| x.as_str());
match suffix { match suffix {

View File

@@ -447,7 +447,8 @@ mod tests {
test_trans_simple!(trans_simple_utf16be, "utf-16be", b"\x04\x16", "Ж"); test_trans_simple!(trans_simple_utf16be, "utf-16be", b"\x04\x16", "Ж");
test_trans_simple!(trans_simple_chinese, "chinese", b"\xA7\xA8", "Ж"); test_trans_simple!(trans_simple_chinese, "chinese", b"\xA7\xA8", "Ж");
test_trans_simple!(trans_simple_korean, "korean", b"\xAC\xA8", "Ж"); test_trans_simple!(trans_simple_korean, "korean", b"\xAC\xA8", "Ж");
test_trans_simple!(trans_simple_big5_hkscs, "big5-hkscs", b"\xC7\xFA", "Ж"); test_trans_simple!(
trans_simple_big5_hkscs, "big5-hkscs", b"\xC7\xFA", "Ж");
test_trans_simple!(trans_simple_gbk, "gbk", b"\xA7\xA8", "Ж"); test_trans_simple!(trans_simple_gbk, "gbk", b"\xA7\xA8", "Ж");
test_trans_simple!(trans_simple_sjis, "sjis", b"\x84\x47", "Ж"); test_trans_simple!(trans_simple_sjis, "sjis", b"\x84\x47", "Ж");
test_trans_simple!(trans_simple_eucjp, "euc-jp", b"\xA7\xA8", "Ж"); test_trans_simple!(trans_simple_eucjp, "euc-jp", b"\xA7\xA8", "Ж");

View File

@@ -58,6 +58,8 @@ pub struct Printer<W> {
/// Whether to print NUL bytes after a file path instead of new lines /// Whether to print NUL bytes after a file path instead of new lines
/// or `:`. /// or `:`.
null: bool, null: bool,
/// Print only the matched (non-empty) parts of a matching line
only_matching: bool,
/// A string to use as a replacement of each match in a matching line. /// A string to use as a replacement of each match in a matching line.
replace: Option<Vec<u8>>, replace: Option<Vec<u8>>,
/// Whether to prefix each match with the corresponding file name. /// Whether to prefix each match with the corresponding file name.
@@ -83,6 +85,7 @@ impl<W: WriteColor> Printer<W> {
heading: false, heading: false,
line_per_match: false, line_per_match: false,
null: false, null: false,
only_matching: false,
replace: None, replace: None,
with_filename: false, with_filename: false,
colors: ColorSpecs::default(), colors: ColorSpecs::default(),
@@ -144,6 +147,12 @@ impl<W: WriteColor> Printer<W> {
self self
} }
/// Print only the matched (non-empty) parts of a matching line
pub fn only_matching(mut self, yes: bool) -> Printer<W> {
self.only_matching = yes;
self
}
/// A separator to use when printing file paths. When empty, use the /// A separator to use when printing file paths. When empty, use the
/// default separator for the current platform. (/ on Unix, \ on Windows.) /// default separator for the current platform. (/ on Unix, \ on Windows.)
pub fn path_separator(mut self, sep: Option<u8>) -> Printer<W> { pub fn path_separator(mut self, sep: Option<u8>) -> Printer<W> {
@@ -153,9 +162,6 @@ impl<W: WriteColor> Printer<W> {
/// Replace every match in each matching line with the replacement string /// Replace every match in each matching line with the replacement string
/// given. /// given.
///
/// The replacement string syntax is documented here:
/// https://doc.rust-lang.org/regex/regex/bytes/struct.Captures.html#method.expand
pub fn replace(mut self, replacement: Vec<u8>) -> Printer<W> { pub fn replace(mut self, replacement: Vec<u8>) -> Printer<W> {
self.replace = Some(replacement); self.replace = Some(replacement);
self self
@@ -204,22 +210,14 @@ impl<W: WriteColor> Printer<W> {
pub fn path<P: AsRef<Path>>(&mut self, path: P) { pub fn path<P: AsRef<Path>>(&mut self, path: P) {
let path = strip_prefix("./", path.as_ref()).unwrap_or(path.as_ref()); let path = strip_prefix("./", path.as_ref()).unwrap_or(path.as_ref());
self.write_path(path); self.write_path(path);
if self.null { self.write_path_eol();
self.write(b"\x00");
} else {
self.write_eol();
}
} }
/// Prints the given path and a count of the number of matches found. /// Prints the given path and a count of the number of matches found.
pub fn path_count<P: AsRef<Path>>(&mut self, path: P, count: u64) { pub fn path_count<P: AsRef<Path>>(&mut self, path: P, count: u64) {
if self.with_filename { if self.with_filename {
self.write_path(path); self.write_path(path);
if self.null { self.write_path_sep(b':');
self.write(b"\x00");
} else {
self.write(b":");
}
} }
self.write(count.to_string().as_bytes()); self.write(count.to_string().as_bytes());
self.write_eol(); self.write_eol();
@@ -227,13 +225,11 @@ impl<W: WriteColor> Printer<W> {
/// Prints the context separator. /// Prints the context separator.
pub fn context_separate(&mut self) { pub fn context_separate(&mut self) {
// N.B. We can't use `write` here because of borrowing restrictions.
if self.context_separator.is_empty() { if self.context_separator.is_empty() {
return; return;
} }
self.has_printed = true;
let _ = self.wtr.write_all(&self.context_separator); let _ = self.wtr.write_all(&self.context_separator);
let _ = self.wtr.write_all(&[self.eol]); self.write_eol();
} }
pub fn matched<P: AsRef<Path>>( pub fn matched<P: AsRef<Path>>(
@@ -245,7 +241,7 @@ impl<W: WriteColor> Printer<W> {
end: usize, end: usize,
line_number: Option<u64>, line_number: Option<u64>,
) { ) {
if !self.line_per_match { if !self.line_per_match && !self.only_matching {
let column = let column =
if self.column { if self.column {
Some(re.find(&buf[start..end]) Some(re.find(&buf[start..end])
@@ -280,16 +276,17 @@ impl<W: WriteColor> Printer<W> {
) { ) {
if self.heading && self.with_filename && !self.has_printed { if self.heading && self.with_filename && !self.has_printed {
self.write_file_sep(); self.write_file_sep();
self.write_heading(path.as_ref()); self.write_path(path);
self.write_path_eol();
} else if !self.heading && self.with_filename { } else if !self.heading && self.with_filename {
self.write_non_heading_path(path.as_ref()); self.write_path(path);
self.write_path_sep(b':');
} }
if let Some(line_number) = line_number { if let Some(line_number) = line_number {
self.line_number(line_number, b':'); self.line_number(line_number, b':');
} }
if let Some(c) = column { if let Some(c) = column {
self.write((c + 1).to_string().as_bytes()); self.column_number(c + 1, b':');
self.write(b":");
} }
if self.replace.is_some() { if self.replace.is_some() {
let mut count = 0; let mut count = 0;
@@ -299,11 +296,9 @@ impl<W: WriteColor> Printer<W> {
re.replace_all(&buf[start..end], replacer) re.replace_all(&buf[start..end], replacer)
}; };
if self.max_columns.map_or(false, |m| line.len() > m) { if self.max_columns.map_or(false, |m| line.len() > m) {
let _ = self.wtr.set_color(self.colors.matched());
let msg = format!( let msg = format!(
"[Omitted long line with {} replacements]", count); "[Omitted long line with {} replacements]", count);
self.write(msg.as_bytes()); self.write_colored(msg.as_bytes(), |colors| colors.matched());
let _ = self.wtr.reset();
self.write_eol(); self.write_eol();
return; return;
} }
@@ -312,7 +307,13 @@ impl<W: WriteColor> Printer<W> {
self.write_eol(); self.write_eol();
} }
} else { } else {
self.write_matched_line(re, &buf[start..end]); let line_buf = if self.only_matching {
let m = re.find(&buf[start..end]).unwrap();
&buf[start + m.start()..start + m.end()]
} else {
&buf[start..end]
};
self.write_matched_line(re, line_buf);
// write_matched_line guarantees to write a newline. // write_matched_line guarantees to write a newline.
} }
} }
@@ -320,10 +321,8 @@ impl<W: WriteColor> Printer<W> {
fn write_matched_line(&mut self, re: &Regex, buf: &[u8]) { fn write_matched_line(&mut self, re: &Regex, buf: &[u8]) {
if self.max_columns.map_or(false, |m| buf.len() > m) { if self.max_columns.map_or(false, |m| buf.len() > m) {
let count = re.find_iter(buf).count(); let count = re.find_iter(buf).count();
let _ = self.wtr.set_color(self.colors.matched());
let msg = format!("[Omitted long line with {} matches]", count); let msg = format!("[Omitted long line with {} matches]", count);
self.write(msg.as_bytes()); self.write_colored(msg.as_bytes(), |colors| colors.matched());
let _ = self.wtr.reset();
self.write_eol(); self.write_eol();
return; return;
} }
@@ -333,9 +332,8 @@ impl<W: WriteColor> Printer<W> {
let mut last_written = 0; let mut last_written = 0;
for m in re.find_iter(buf) { for m in re.find_iter(buf) {
self.write(&buf[last_written..m.start()]); self.write(&buf[last_written..m.start()]);
let _ = self.wtr.set_color(self.colors.matched()); self.write_colored(
self.write(&buf[m.start()..m.end()]); &buf[m.start()..m.end()], |colors| colors.matched());
let _ = self.wtr.reset();
last_written = m.end(); last_written = m.end();
} }
self.write(&buf[last_written..]); self.write(&buf[last_written..]);
@@ -355,14 +353,11 @@ impl<W: WriteColor> Printer<W> {
) { ) {
if self.heading && self.with_filename && !self.has_printed { if self.heading && self.with_filename && !self.has_printed {
self.write_file_sep(); self.write_file_sep();
self.write_heading(path.as_ref()); self.write_path(path);
self.write_path_eol();
} else if !self.heading && self.with_filename { } else if !self.heading && self.with_filename {
self.write_path(path.as_ref()); self.write_path(path);
if self.null { self.write_path_sep(b'-');
self.write(b"\x00");
} else {
self.write(b"-");
}
} }
if let Some(line_number) = line_number { if let Some(line_number) = line_number {
self.line_number(line_number, b'-'); self.line_number(line_number, b'-');
@@ -378,10 +373,19 @@ impl<W: WriteColor> Printer<W> {
} }
} }
fn write_heading<P: AsRef<Path>>(&mut self, path: P) { fn separator(&mut self, sep: &[u8]) {
let _ = self.wtr.set_color(self.colors.path()); self.write(&sep);
self.write_path(path.as_ref()); }
let _ = self.wtr.reset();
fn write_path_sep(&mut self, sep: u8) {
if self.null {
self.write(b"\x00");
} else {
self.separator(&[sep]);
}
}
fn write_path_eol(&mut self) {
if self.null { if self.null {
self.write(b"\x00"); self.write(b"\x00");
} else { } else {
@@ -389,52 +393,43 @@ impl<W: WriteColor> Printer<W> {
} }
} }
fn write_non_heading_path<P: AsRef<Path>>(&mut self, path: P) {
let _ = self.wtr.set_color(self.colors.path());
self.write_path(path.as_ref());
let _ = self.wtr.reset();
if self.null {
self.write(b"\x00");
} else {
self.write(b":");
}
}
fn line_number(&mut self, n: u64, sep: u8) {
let _ = self.wtr.set_color(self.colors.line());
self.write(n.to_string().as_bytes());
let _ = self.wtr.reset();
self.write(&[sep]);
}
#[cfg(unix)] #[cfg(unix)]
fn write_path<P: AsRef<Path>>(&mut self, path: P) { fn write_path<P: AsRef<Path>>(&mut self, path: P) {
use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStrExt;
let path = path.as_ref().as_os_str().as_bytes(); let path = path.as_ref().as_os_str().as_bytes();
match self.path_separator { self.write_path_replace_separator(path);
None => self.write(path),
Some(sep) => self.write_path_with_sep(path, sep),
}
} }
#[cfg(not(unix))] #[cfg(not(unix))]
fn write_path<P: AsRef<Path>>(&mut self, path: P) { fn write_path<P: AsRef<Path>>(&mut self, path: P) {
let path = path.as_ref().to_string_lossy(); let path = path.as_ref().to_string_lossy();
self.write_path_replace_separator(path.as_bytes());
}
fn write_path_replace_separator(&mut self, path: &[u8]) {
match self.path_separator { match self.path_separator {
None => self.write(path.as_bytes()), None => self.write_colored(path, |colors| colors.path()),
Some(sep) => self.write_path_with_sep(path.as_bytes(), sep), Some(sep) => {
let transformed_path: Vec<_> = path.iter().map(|&b| {
if b == b'/' || (cfg!(windows) && b == b'\\') {
sep
} else {
b
}
}).collect();
self.write_colored(&transformed_path, |colors| colors.path());
}
} }
} }
fn write_path_with_sep(&mut self, path: &[u8], sep: u8) { fn line_number(&mut self, n: u64, sep: u8) {
let mut path = path.to_vec(); self.write_colored(n.to_string().as_bytes(), |colors| colors.line());
for b in &mut path { self.separator(&[sep]);
if *b == b'/' || (cfg!(windows) && *b == b'\\') { }
*b = sep;
} fn column_number(&mut self, n: u64, sep: u8) {
} self.write_colored(n.to_string().as_bytes(), |colors| colors.column());
self.write(&path); self.separator(&[sep]);
} }
fn write(&mut self, buf: &[u8]) { fn write(&mut self, buf: &[u8]) {
@@ -447,6 +442,14 @@ impl<W: WriteColor> Printer<W> {
self.write(&[eol]); self.write(&[eol]);
} }
fn write_colored<F>(&mut self, buf: &[u8], get_color: F)
where F: Fn(&ColorSpecs) -> &ColorSpec
{
let _ = self.wtr.set_color( get_color(&self.colors) );
self.write(buf);
let _ = self.wtr.reset();
}
fn write_file_sep(&mut self) { fn write_file_sep(&mut self) {
if let Some(ref sep) = self.file_separator { if let Some(ref sep) = self.file_separator {
self.has_printed = true; self.has_printed = true;
@@ -492,7 +495,7 @@ impl fmt::Display for Error {
match *self { match *self {
Error::UnrecognizedOutType(ref name) => { Error::UnrecognizedOutType(ref name) => {
write!(f, "Unrecognized output type '{}'. Choose from: \ write!(f, "Unrecognized output type '{}'. Choose from: \
path, line, match.", name) path, line, column, match.", name)
} }
Error::UnrecognizedSpecType(ref name) => { Error::UnrecognizedSpecType(ref name) => {
write!(f, "Unrecognized spec type '{}'. Choose from: \ write!(f, "Unrecognized spec type '{}'. Choose from: \
@@ -503,12 +506,14 @@ impl fmt::Display for Error {
} }
Error::UnrecognizedStyle(ref name) => { Error::UnrecognizedStyle(ref name) => {
write!(f, "Unrecognized style attribute '{}'. Choose from: \ write!(f, "Unrecognized style attribute '{}'. Choose from: \
nobold, bold.", name) nobold, bold, nointense, intense.", name)
} }
Error::InvalidFormat(ref original) => { Error::InvalidFormat(ref original) => {
write!(f, "Invalid color speci format: '{}'. Valid format \ write!(
is '(path|line|match):(fg|bg|style):(value)'.", f,
original) "Invalid color speci format: '{}'. Valid format \
is '(path|line|column|match):(fg|bg|style):(value)'.",
original)
} }
} }
} }
@@ -525,6 +530,7 @@ impl From<ParseColorError> for Error {
pub struct ColorSpecs { pub struct ColorSpecs {
path: ColorSpec, path: ColorSpec,
line: ColorSpec, line: ColorSpec,
column: ColorSpec,
matched: ColorSpec, matched: ColorSpec,
} }
@@ -554,7 +560,7 @@ pub struct ColorSpecs {
/// The format of a `Spec` is a triple: `{type}:{attribute}:{value}`. Each /// The format of a `Spec` is a triple: `{type}:{attribute}:{value}`. Each
/// component is defined as follows: /// component is defined as follows:
/// ///
/// * `{type}` can be one of `path`, `line` or `match`. /// * `{type}` can be one of `path`, `line`, `column` or `match`.
/// * `{attribute}` can be one of `fg`, `bg` or `style`. `{attribute}` may also /// * `{attribute}` can be one of `fg`, `bg` or `style`. `{attribute}` may also
/// be the special value `none`, in which case, `{value}` can be omitted. /// be the special value `none`, in which case, `{value}` can be omitted.
/// * `{value}` is either a color name (for `fg`/`bg`) or a style instruction. /// * `{value}` is either a color name (for `fg`/`bg`) or a style instruction.
@@ -593,6 +599,7 @@ enum SpecValue {
enum OutType { enum OutType {
Path, Path,
Line, Line,
Column,
Match, Match,
} }
@@ -623,6 +630,7 @@ impl ColorSpecs {
match user_spec.ty { match user_spec.ty {
OutType::Path => user_spec.merge_into(&mut specs.path), OutType::Path => user_spec.merge_into(&mut specs.path),
OutType::Line => user_spec.merge_into(&mut specs.line), OutType::Line => user_spec.merge_into(&mut specs.line),
OutType::Column => user_spec.merge_into(&mut specs.column),
OutType::Match => user_spec.merge_into(&mut specs.matched), OutType::Match => user_spec.merge_into(&mut specs.matched),
} }
} }
@@ -639,6 +647,11 @@ impl ColorSpecs {
&self.line &self.line
} }
/// Return the color specification for coloring column numbers.
fn column(&self) -> &ColorSpec {
&self.column
}
/// Return the color specification for coloring matched text. /// Return the color specification for coloring matched text.
fn matched(&self) -> &ColorSpec { fn matched(&self) -> &ColorSpec {
&self.matched &self.matched
@@ -714,6 +727,7 @@ impl FromStr for OutType {
match &*s.to_lowercase() { match &*s.to_lowercase() {
"path" => Ok(OutType::Path), "path" => Ok(OutType::Path),
"line" => Ok(OutType::Line), "line" => Ok(OutType::Line),
"column" => Ok(OutType::Column),
"match" => Ok(OutType::Match), "match" => Ok(OutType::Match),
_ => Err(Error::UnrecognizedOutType(s.to_string())), _ => Err(Error::UnrecognizedOutType(s.to_string())),
} }
@@ -765,6 +779,7 @@ mod tests {
assert_eq!(ColorSpecs::new(user_specs), ColorSpecs { assert_eq!(ColorSpecs::new(user_specs), ColorSpecs {
path: ColorSpec::default(), path: ColorSpec::default(),
line: ColorSpec::default(), line: ColorSpec::default(),
column: ColorSpec::default(),
matched: expect_matched, matched: expect_matched,
}); });
} }
@@ -800,6 +815,12 @@ mod tests {
ty: OutType::Line, ty: OutType::Line,
value: SpecValue::None, value: SpecValue::None,
}); });
let spec: Spec = "column:bg:green".parse().unwrap();
assert_eq!(spec, Spec {
ty: OutType::Column,
value: SpecValue::Bg(Color::Green),
});
} }
#[test] #[test]

View File

@@ -3,8 +3,8 @@ The `search_buffer` module is responsible for searching a single file all in a
single buffer. Typically, the source of the buffer is a memory map. This can single buffer. Typically, the source of the buffer is a memory map. This can
be useful for when memory maps are faster than streaming search. be useful for when memory maps are faster than streaming search.
Note that this module doesn't quite support everything that `search_stream` does. Note that this module doesn't quite support everything that `search_stream`
Notably, showing contexts. does. Notably, showing contexts.
*/ */
use std::cmp; use std::cmp;
use std::path::Path; use std::path::Path;

View File

@@ -1057,6 +1057,33 @@ clean!(regression_405, "test", ".", |wd: WorkDir, mut cmd: Command| {
assert_eq!(lines, format!("{}:test\n", path("bar/foo/file2.txt"))); assert_eq!(lines, format!("{}:test\n", path("bar/foo/file2.txt")));
}); });
// See: https://github.com/BurntSushi/ripgrep/issues/428
clean!(regression_428_color_context_path, "foo", ".", |wd: WorkDir, mut cmd: Command| {
wd.create("sherlock", "foo\nbar");
cmd.arg("-A1").arg("-H").arg("--no-heading").arg("-N")
.arg("--colors=match:none").arg("--color=always");
let lines: String = wd.stdout(&mut cmd);
let expected = format!("\
{colored_path}:foo
{colored_path}-bar
", colored_path=format!("\x1b\x5b\x6d\x1b\x5b\x33\x35\x6d{path}\x1b\x5b\x6d", path=path("sherlock")));
assert_eq!(lines, expected);
});
// See: https://github.com/BurntSushi/ripgrep/issues/428
clean!(regression_428_unrecognized_style, "Sherlok", ".", |wd: WorkDir, mut cmd: Command| {
cmd.arg("--colors=match:style:");
wd.assert_err(&mut cmd);
let output = cmd.output().unwrap();
let err = String::from_utf8_lossy(&output.stderr);
let expected = "\
Unrecognized style attribute ''. Choose from: nobold, bold, nointense, intense.
";
assert_eq!(err, expected);
});
// See: https://github.com/BurntSushi/ripgrep/issues/1 // See: https://github.com/BurntSushi/ripgrep/issues/1
clean!(feature_1_sjis, "Шерлок Холмс", ".", |wd: WorkDir, mut cmd: Command| { clean!(feature_1_sjis, "Шерлок Холмс", ".", |wd: WorkDir, mut cmd: Command| {
let sherlock = let sherlock =
@@ -1139,6 +1166,32 @@ be, to a very large extent, the result of luck. Sherlock Holmes
assert_eq!(lines, expected); assert_eq!(lines, expected);
}); });
// See: https://github.com/BurntSushi/ripgrep/issues/34
sherlock!(feature_34_only_matching, "Sherlock", ".",
|wd: WorkDir, mut cmd: Command| {
cmd.arg("--only-matching");
let lines: String = wd.stdout(&mut cmd);
let expected = "\
sherlock:Sherlock
sherlock:Sherlock
";
assert_eq!(lines, expected);
});
// See: https://github.com/BurntSushi/ripgrep/issues/34
sherlock!(feature_34_only_matching_line_column, "Sherlock", ".",
|wd: WorkDir, mut cmd: Command| {
cmd.arg("--only-matching").arg("--column").arg("--line-number");
let lines: String = wd.stdout(&mut cmd);
let expected = "\
sherlock:1:57:Sherlock
sherlock:3:49:Sherlock
";
assert_eq!(lines, expected);
});
// See: https://github.com/BurntSushi/ripgrep/issues/45 // See: https://github.com/BurntSushi/ripgrep/issues/45
sherlock!(feature_45_relative_cwd, "test", ".", sherlock!(feature_45_relative_cwd, "test", ".",
|wd: WorkDir, mut cmd: Command| { |wd: WorkDir, mut cmd: Command| {
@@ -1390,6 +1443,15 @@ clean!(feature_275_pathsep, "test", ".", |wd: WorkDir, mut cmd: Command| {
assert_eq!(lines, "fooZbar:test\n"); assert_eq!(lines, "fooZbar:test\n");
}); });
// See: https://github.com/BurntSushi/ripgrep/issues/419
sherlock!(feature_419_zero_as_shortcut_for_null, "Sherlock", ".",
|wd: WorkDir, mut cmd: Command| {
cmd.arg("-0").arg("--count");
let lines: String = wd.stdout(&mut cmd);
assert_eq!(lines, "sherlock\x002\n");
});
#[test] #[test]
fn binary_nosearch() { fn binary_nosearch() {
let wd = WorkDir::new("binary_nosearch"); let wd = WorkDir::new("binary_nosearch");