mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2025-08-19 14:13:49 -07:00
Compare commits
480 Commits
grep-pcre2
...
grep-searc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
120e55e7c7 | ||
|
|
3941a7701d | ||
|
|
96e130fbf9 | ||
|
|
180c4eaf8b | ||
|
|
81529288cf | ||
|
|
bcc7473a87 | ||
|
|
bc78c644db | ||
|
|
dc7267a0fb | ||
|
|
3224324e25 | ||
|
|
0f61f08eb1 | ||
|
|
a0e8dbe9df | ||
|
|
e95254a86f | ||
|
|
2f484d8ce5 | ||
|
|
364772ddd2 | ||
|
|
2e207833bc | ||
|
|
92b35a65f8 | ||
|
|
ac8fecbbf2 | ||
|
|
8596817374 | ||
|
|
28bff84a0a | ||
|
|
61101289fa | ||
|
|
13faa39b66 | ||
|
|
6b61271bbb | ||
|
|
1be86392e0 | ||
|
|
63058453fa | ||
|
|
7f23cd63a5 | ||
|
|
8905d54a9f | ||
|
|
25a4eaf5ae | ||
|
|
0000157917 | ||
|
|
65b1b0e38a | ||
|
|
c032cda4b7 | ||
|
|
eab044d829 | ||
|
|
55e62a4411 | ||
|
|
5b2f614aad | ||
|
|
4386b8e805 | ||
|
|
6b012d8129 | ||
|
|
a928ca4221 | ||
|
|
d1570defbf | ||
|
|
b732c23e36 | ||
|
|
49965703fa | ||
|
|
609838aebd | ||
|
|
515f120b5c | ||
|
|
a66315d232 | ||
|
|
bdf10ab7c0 | ||
|
|
a02678800b | ||
|
|
387df97d85 | ||
|
|
a9d97a1dda | ||
|
|
3bb71b0cb8 | ||
|
|
87b33c96c0 | ||
|
|
5e975c43f8 | ||
|
|
7efa2e46d3 | ||
|
|
db0b92b62d | ||
|
|
33b81cac48 | ||
|
|
6a13a4f64d | ||
|
|
b13d835d95 | ||
|
|
d53506b7f7 | ||
|
|
78a35d4d43 | ||
|
|
a933d0bc90 | ||
|
|
2cae30e399 | ||
|
|
8e57989cd2 | ||
|
|
b9f5835534 | ||
|
|
e70778e89d | ||
|
|
87c4a2b4b1 | ||
|
|
0aa31676e3 | ||
|
|
9f0e88bcb1 | ||
|
|
eb4b389846 | ||
|
|
dc337bab0a | ||
|
|
2cfb338530 | ||
|
|
48646e3451 | ||
|
|
985394a19e | ||
|
|
ec36f8c3ff | ||
|
|
a726d03641 | ||
|
|
91afd4214a | ||
|
|
4dc6c73c5a | ||
|
|
36d03b4101 | ||
|
|
d161acb0a3 | ||
|
|
30ee6f08ee | ||
|
|
ced5b92aa9 | ||
|
|
191315a2ea | ||
|
|
5370064f00 | ||
|
|
b6189c659e | ||
|
|
0b36942f68 | ||
|
|
7e05cde008 | ||
|
|
418d048b27 | ||
|
|
009dda1488 | ||
|
|
ba535fb5a3 | ||
|
|
427aaeeb2e | ||
|
|
f5cff746bc | ||
|
|
457f53b7ee | ||
|
|
eb35f7978e | ||
|
|
fc69bd366c | ||
|
|
9b01a8f9ae | ||
|
|
0ff5dd2360 | ||
|
|
3c7819301b | ||
|
|
699e651db2 | ||
|
|
9eddb71b8e | ||
|
|
abf115228e | ||
|
|
fdfc418be5 | ||
|
|
5bf74362b9 | ||
|
|
431ea38620 | ||
|
|
caba5c4348 | ||
|
|
07f97d42cf | ||
|
|
e33d6e73f5 | ||
|
|
478da4f271 | ||
|
|
7ce66f73cf | ||
|
|
bc76a30c23 | ||
|
|
5e81c60b35 | ||
|
|
b3e5ae9d28 | ||
|
|
a024f14fdd | ||
|
|
8c30c8294a | ||
|
|
c44d263419 | ||
|
|
af6b6c543b | ||
|
|
1a4fec8b4a | ||
|
|
c8d8ab8ded | ||
|
|
1d53ed2744 | ||
|
|
29696d1455 | ||
|
|
57ce623a57 | ||
|
|
f1c656de40 | ||
|
|
dd47582619 | ||
|
|
9b88cf8b72 | ||
|
|
6668d7ba8a | ||
|
|
008da5dca4 | ||
|
|
a34df1f690 | ||
|
|
7f3fd6f7ce | ||
|
|
6331a7ac18 | ||
|
|
cd4386bd9b | ||
|
|
cdc20c5685 | ||
|
|
0cf2b98df2 | ||
|
|
9efdbf74a1 | ||
|
|
53cb9a779e | ||
|
|
14860b0f16 | ||
|
|
0eb1a1e7c9 | ||
|
|
5631e5c7a0 | ||
|
|
21644408f2 | ||
|
|
0ee85a89f5 | ||
|
|
ed9d37959f | ||
|
|
9f924ee187 | ||
|
|
35c5db6d1a | ||
|
|
e824531e38 | ||
|
|
af54069c51 | ||
|
|
77a9e99964 | ||
|
|
459a9c5637 | ||
|
|
e4c4540f6a | ||
|
|
5d0f2b0fc0 | ||
|
|
079a23b515 | ||
|
|
6e27649af1 | ||
|
|
df83b8b444 | ||
|
|
e48a17e189 | ||
|
|
fbb2cfed28 | ||
|
|
af8b27ffae | ||
|
|
8a4071eea9 | ||
|
|
ee23ab5173 | ||
|
|
efd9cfb2fc | ||
|
|
656aa12649 | ||
|
|
fc31aedcf3 | ||
|
|
578e1992fa | ||
|
|
46d0130597 | ||
|
|
7534d5144f | ||
|
|
a28e664abd | ||
|
|
0ca96e004c | ||
|
|
2295061e80 | ||
|
|
53c4855517 | ||
|
|
121e0135c1 | ||
|
|
c53c4c0ade | ||
|
|
4566882521 | ||
|
|
12dd455ee9 | ||
|
|
e6cac8b119 | ||
|
|
0f502a9439 | ||
|
|
51d2db7f19 | ||
|
|
b3a6a69f9d | ||
|
|
26a29c750e | ||
|
|
beda5f70dc | ||
|
|
5af7707a35 | ||
|
|
3f33a83a5f | ||
|
|
35b52d33b9 | ||
|
|
a77b914e7a | ||
|
|
2e2af50a4d | ||
|
|
229d1a8d41 | ||
|
|
8ec6ef373f | ||
|
|
581a35e568 | ||
|
|
ba965962fe | ||
|
|
94e4b8e301 | ||
|
|
2af77242c5 | ||
|
|
3f4c4188c1 | ||
|
|
ce4b587055 | ||
|
|
be63122508 | ||
|
|
92286ad4d2 | ||
|
|
4ebe8375ec | ||
|
|
7923d25228 | ||
|
|
1c3eebefec | ||
|
|
64ac2ebe0f | ||
|
|
46fb77c20c | ||
|
|
6a1c3253e0 | ||
|
|
c7730d1f3a | ||
|
|
c5ea5a13df | ||
|
|
9c8d873a75 | ||
|
|
7899a4b931 | ||
|
|
ae55a4e872 | ||
|
|
3a1780d841 | ||
|
|
a6d05475fb | ||
|
|
020c5453a5 | ||
|
|
873abecbf1 | ||
|
|
8c73833efc | ||
|
|
44e69ba627 | ||
|
|
13d77ab646 | ||
|
|
d97fb72d84 | ||
|
|
d6365117e2 | ||
|
|
f32e906012 | ||
|
|
59644d4592 | ||
|
|
3ca324fda7 | ||
|
|
8782f8200c | ||
|
|
2819212f89 | ||
|
|
810be0b348 | ||
|
|
a28bb1e953 | ||
|
|
3ef63dacbe | ||
|
|
e1ac18ef06 | ||
|
|
ba3f9673ad | ||
|
|
c777e2cd57 | ||
|
|
e5639cf22d | ||
|
|
86c843a44b | ||
|
|
2b1637d1db | ||
|
|
6301e20ee4 | ||
|
|
145cef2eff | ||
|
|
20534fad04 | ||
|
|
de0c24f31c | ||
|
|
c55e7af675 | ||
|
|
5ebb3ad039 | ||
|
|
b0066274cb | ||
|
|
def993bad1 | ||
|
|
f511849c81 | ||
|
|
e6e50054b0 | ||
|
|
11c7b2ae17 | ||
|
|
ac7d4c99b9 | ||
|
|
b5681e3694 | ||
|
|
fc2a99bb1f | ||
|
|
ffd4c9ccba | ||
|
|
a16bfcb3d6 | ||
|
|
1b2c1dc675 | ||
|
|
b1e3de246c | ||
|
|
bb36fc1bf8 | ||
|
|
7cb211378a | ||
|
|
a73c0a21d9 | ||
|
|
0b965f900c | ||
|
|
a2f90747c9 | ||
|
|
f97cc623f7 | ||
|
|
f35de5c523 | ||
|
|
c9bb78ceba | ||
|
|
72bdde6771 | ||
|
|
d66712a452 | ||
|
|
e8822ce97a | ||
|
|
a700b75843 | ||
|
|
b72ad8f8aa | ||
|
|
1980630f17 | ||
|
|
1e9a481a66 | ||
|
|
bacfca174e | ||
|
|
6162b000a3 | ||
|
|
2658bd4e46 | ||
|
|
4b8e1f030e | ||
|
|
72807462e8 | ||
|
|
08dee094dd | ||
|
|
caa53b7b09 | ||
|
|
c5d6141562 | ||
|
|
c0f0492b98 | ||
|
|
568018386b | ||
|
|
6219d29c24 | ||
|
|
b458cf39f2 | ||
|
|
3fd2694fbc | ||
|
|
b56315ea84 | ||
|
|
fac47906e6 | ||
|
|
e02bb6b99a | ||
|
|
16a1221fc7 | ||
|
|
793c1179cc | ||
|
|
df7a3bfc7f | ||
|
|
28f2a93cae | ||
|
|
0eb2501b6e | ||
|
|
184c15882e | ||
|
|
64a4dee495 | ||
|
|
50840ea43b | ||
|
|
17dcc2bf51 | ||
|
|
9a858e4909 | ||
|
|
cbfbe9312f | ||
|
|
7ed9a31819 | ||
|
|
a2e6aec7a4 | ||
|
|
73103df6d9 | ||
|
|
139f186e57 | ||
|
|
afb325f733 | ||
|
|
40af352d74 | ||
|
|
3f1d4b397d | ||
|
|
a75b4d122a | ||
|
|
f51b762c6d | ||
|
|
49de7b119c | ||
|
|
1c4b5adb7b | ||
|
|
3d6a58faff | ||
|
|
5b6ca04e39 | ||
|
|
47f20c2661 | ||
|
|
1d5b1011e5 | ||
|
|
1bb30b72fc | ||
|
|
09a4b75baf | ||
|
|
58c428827d | ||
|
|
b9bb04b793 | ||
|
|
4dfea016b9 | ||
|
|
3193d57ac1 | ||
|
|
67c0f576b6 | ||
|
|
543f99dbf1 | ||
|
|
0ea65efd6d | ||
|
|
20deae6497 | ||
|
|
655e33219a | ||
|
|
8ba6ccd159 | ||
|
|
34edb8123a | ||
|
|
5b30c2aed6 | ||
|
|
bf1027a83e | ||
|
|
031264e5fb | ||
|
|
b9cd95faf1 | ||
|
|
92daa34eb3 | ||
|
|
a8c1fb7c88 | ||
|
|
52ec68799c | ||
|
|
c0d78240df | ||
|
|
cda9acb876 | ||
|
|
1ece50694e | ||
|
|
f3a966bcbc | ||
|
|
a38913b63a | ||
|
|
e772a95b58 | ||
|
|
9dd4bf8d7f | ||
|
|
c4c43c733e | ||
|
|
447506ebe0 | ||
|
|
12e4180985 | ||
|
|
daa8319398 | ||
|
|
3a6a24a52a | ||
|
|
aab3d80374 | ||
|
|
1856cda77b | ||
|
|
7340d8dbbe | ||
|
|
50d2047ae2 | ||
|
|
227436624f | ||
|
|
5bfdd3a652 | ||
|
|
ecec6147d1 | ||
|
|
db7a8cdcb5 | ||
|
|
eef7a7e7ff | ||
|
|
4176050cdd | ||
|
|
109460fce2 | ||
|
|
da3431b478 | ||
|
|
f314b0d55f | ||
|
|
fab5c812f3 | ||
|
|
c824d095a7 | ||
|
|
ee21897ebd | ||
|
|
0373f6ddb0 | ||
|
|
b44554c803 | ||
|
|
0874aa115c | ||
|
|
fdd8510fdd | ||
|
|
0bc4f0447b | ||
|
|
c95f29e3ba | ||
|
|
3644208b03 | ||
|
|
66f045e055 | ||
|
|
3d59bd98aa | ||
|
|
52d7f47420 | ||
|
|
75cbe88fa2 | ||
|
|
711426a632 | ||
|
|
01eeec56bb | ||
|
|
322fc75a3d | ||
|
|
b435eaafc8 | ||
|
|
f8e70294d5 | ||
|
|
578e2d47a8 | ||
|
|
9f7c2ebc09 | ||
|
|
5c1eac41a3 | ||
|
|
6f2b79f584 | ||
|
|
0c3b673e4c | ||
|
|
297b428c8c | ||
|
|
804b43ecd8 | ||
|
|
2263b8ac92 | ||
|
|
cd8ec38a68 | ||
|
|
6a0e0147e0 | ||
|
|
ad97e9c93f | ||
|
|
24f8a3e5ec | ||
|
|
1bdb767851 | ||
|
|
a4897eca23 | ||
|
|
a070722ff2 | ||
|
|
4628d77808 | ||
|
|
f8418c6a52 | ||
|
|
040ca45ba0 | ||
|
|
91470572cd | ||
|
|
027adbf485 | ||
|
|
e71eedf0eb | ||
|
|
88f46d12f1 | ||
|
|
a18cf6ec39 | ||
|
|
c78c3236a8 | ||
|
|
7cf21600cd | ||
|
|
647b0d3977 | ||
|
|
e572fc1683 | ||
|
|
9cb93abd11 | ||
|
|
41695c66fa | ||
|
|
cb0dfda936 | ||
|
|
74d1fe59e9 | ||
|
|
9fd1e202e0 | ||
|
|
e76807b1b5 | ||
|
|
f8fb65f7e3 | ||
|
|
98de8d248a | ||
|
|
c358700dfb | ||
|
|
8670a4a969 | ||
|
|
e3b1f86908 | ||
|
|
46b07bb2ee | ||
|
|
8bdf84e3a8 | ||
|
|
5a6e17fcc1 | ||
|
|
00bfcd14a6 | ||
|
|
bf0ddc4675 | ||
|
|
0fb3f6a159 | ||
|
|
837fb5e21f | ||
|
|
2e1815606e | ||
|
|
cb2f6ddc61 | ||
|
|
bd7a42602f | ||
|
|
528ce56e1b | ||
|
|
8892bf648c | ||
|
|
8cb7271b64 | ||
|
|
4858267f3b | ||
|
|
5011dba2fd | ||
|
|
e14f9195e5 | ||
|
|
ef0e7af56a | ||
|
|
b266818aa5 | ||
|
|
81415ae52d | ||
|
|
5c4584aa7c | ||
|
|
0972c6e7c7 | ||
|
|
0a372bf2e4 | ||
|
|
345124a7fa | ||
|
|
31807f805a | ||
|
|
4de227fd9a | ||
|
|
d7ce274722 | ||
|
|
5b10328f41 | ||
|
|
813c676eca | ||
|
|
f625d72b6f | ||
|
|
3de31f7527 | ||
|
|
e402d6c260 | ||
|
|
48b5bdc441 | ||
|
|
709ca91f50 | ||
|
|
9c220f9a9b | ||
|
|
9085bed139 | ||
|
|
931ab35f76 | ||
|
|
b5e5979ff1 | ||
|
|
052c857da0 | ||
|
|
5e84e784c8 | ||
|
|
01e8e11621 | ||
|
|
9268ff8e8d | ||
|
|
c2cb0a4de4 | ||
|
|
adb9332f52 | ||
|
|
bc37c32717 | ||
|
|
08ae4da2b7 | ||
|
|
7ac95c1f50 | ||
|
|
7a6903bd4e | ||
|
|
9801fae29f | ||
|
|
abdf7140d7 | ||
|
|
b83e7968ef | ||
|
|
8ebc113847 | ||
|
|
785c1f1766 | ||
|
|
8b734cb490 | ||
|
|
b93762ea7a | ||
|
|
34677d2622 | ||
|
|
d1389db2e3 | ||
|
|
50bcb7409e | ||
|
|
7b9972c308 | ||
|
|
9f000c2910 | ||
|
|
392682d352 | ||
|
|
7d3f794588 | ||
|
|
290fd2a7b6 | ||
|
|
d1e4d28f30 | ||
|
|
5ce2d7351d | ||
|
|
9dcfd9a205 | ||
|
|
36b276c6d0 | ||
|
|
03bf37ff4a | ||
|
|
e7829c05d3 | ||
|
|
a6222939f9 | ||
|
|
6ffd434232 | ||
|
|
1f1cd9b467 | ||
|
|
973de50c9e | ||
|
|
5f8805a496 | ||
|
|
fdde2bcd38 | ||
|
|
7b3fe6b325 | ||
|
|
b3dd3ae203 | ||
|
|
f3083e4574 | ||
|
|
d03e30707e | ||
|
|
d7f57d9aab | ||
|
|
1a2a24ea74 | ||
|
|
d66610b295 | ||
|
|
019ae1989b | ||
|
|
36d3f235dc |
8
.cargo/config.toml
Normal file
8
.cargo/config.toml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# On Windows MSVC, statically link the C runtime so that the resulting EXE does
|
||||||
|
# not depend on the vcruntime DLL.
|
||||||
|
#
|
||||||
|
# See: https://github.com/BurntSushi/ripgrep/pull/1613
|
||||||
|
[target.x86_64-pc-windows-msvc]
|
||||||
|
rustflags = ["-C", "target-feature=+crt-static"]
|
||||||
|
[target.i686-pc-windows-msvc]
|
||||||
|
rustflags = ["-C", "target-feature=+crt-static"]
|
||||||
@@ -1,3 +1,12 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: An issue with ripgrep or any of its crates (ignore, globset, etc.)
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
#### What version of ripgrep are you using?
|
#### What version of ripgrep are you using?
|
||||||
|
|
||||||
Replace this text with the output of `rg --version`.
|
Replace this text with the output of `rg --version`.
|
||||||
@@ -12,18 +21,11 @@ Github binary releases.
|
|||||||
|
|
||||||
Replace this text with your operating system and version.
|
Replace this text with your operating system and version.
|
||||||
|
|
||||||
#### Describe your question, feature request, or bug.
|
#### Describe your bug.
|
||||||
|
|
||||||
If a question, please describe the problem you're trying to solve and give
|
Give a high level description of the bug.
|
||||||
as much context as possible.
|
|
||||||
|
|
||||||
If a feature request, please describe the behavior you want and the motivation.
|
#### What are the steps to reproduce the behavior?
|
||||||
Please also provide an example of how ripgrep would be used if your feature
|
|
||||||
request were added.
|
|
||||||
|
|
||||||
If a bug, please see below.
|
|
||||||
|
|
||||||
#### If this is a bug, what are the steps to reproduce the behavior?
|
|
||||||
|
|
||||||
If possible, please include both your search patterns and the corpus on which
|
If possible, please include both your search patterns and the corpus on which
|
||||||
you are searching. Unless the bug is very obvious, then it is unlikely that it
|
you are searching. Unless the bug is very obvious, then it is unlikely that it
|
||||||
@@ -32,7 +34,7 @@ will be fixed if the ripgrep maintainers cannot reproduce it.
|
|||||||
If the corpus is too big and you cannot decrease its size, file the bug anyway
|
If the corpus is too big and you cannot decrease its size, file the bug anyway
|
||||||
and the ripgrep maintainers will help figure out next steps.
|
and the ripgrep maintainers will help figure out next steps.
|
||||||
|
|
||||||
#### If this is a bug, what is the actual behavior?
|
#### What is the actual behavior?
|
||||||
|
|
||||||
Show the command you ran and the actual output. Include the `--debug` flag in
|
Show the command you ran and the actual output. Include the `--debug` flag in
|
||||||
your invocation of ripgrep.
|
your invocation of ripgrep.
|
||||||
@@ -48,6 +50,6 @@ goes
|
|||||||
here
|
here
|
||||||
```
|
```
|
||||||
|
|
||||||
#### If this is a bug, what is the expected behavior?
|
#### What is the expected behavior?
|
||||||
|
|
||||||
What do you think ripgrep should have done?
|
What do you think ripgrep should have done?
|
||||||
6
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
6
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
blank_issues_enabled: true
|
||||||
|
contact_links:
|
||||||
|
- name: Ask a question
|
||||||
|
about: |
|
||||||
|
You've come to seek help or want to discuss something related to ripgrep.
|
||||||
|
url: https://github.com/BurntSushi/ripgrep/discussions/new
|
||||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest a new feature for ripgrep
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
#### Describe your feature request
|
||||||
|
|
||||||
|
Please describe the behavior you want and the motivation. Please also provide
|
||||||
|
examples of how ripgrep would be used if your feature request were added.
|
||||||
|
|
||||||
|
If you're not sure what to write here, then try imagining what the ideal
|
||||||
|
documentation of your new feature would look like in ripgrep's man page. Then
|
||||||
|
try to write it.
|
||||||
|
|
||||||
|
If you're requesting the addition or change of default file types, please open
|
||||||
|
a PR. We can discuss it there if necessary.
|
||||||
6
.github/dependabot.yml
vendored
Normal file
6
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
206
.github/workflows/ci.yml
vendored
Normal file
206
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
name: ci
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
schedule:
|
||||||
|
- cron: '00 01 * * *'
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: test
|
||||||
|
env:
|
||||||
|
# For some builds, we use cross to test on 32-bit and big-endian
|
||||||
|
# systems.
|
||||||
|
CARGO: cargo
|
||||||
|
# When CARGO is set to CROSS, this is set to `--target matrix.target`.
|
||||||
|
TARGET_FLAGS:
|
||||||
|
# When CARGO is set to CROSS, TARGET_DIR includes matrix.target.
|
||||||
|
TARGET_DIR: ./target
|
||||||
|
# Emit backtraces on panics.
|
||||||
|
RUST_BACKTRACE: 1
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
build:
|
||||||
|
# We test ripgrep on a pinned version of Rust, along with the moving
|
||||||
|
# targets of 'stable' and 'beta' for good measure.
|
||||||
|
- pinned
|
||||||
|
- stable
|
||||||
|
- beta
|
||||||
|
# Our release builds are generated by a nightly compiler to take
|
||||||
|
# advantage of the latest optimizations/compile time improvements. So
|
||||||
|
# we test all of them here. (We don't do mips releases, but test on
|
||||||
|
# mips for big-endian coverage.)
|
||||||
|
- nightly
|
||||||
|
- nightly-musl
|
||||||
|
- nightly-32
|
||||||
|
- nightly-mips
|
||||||
|
- nightly-arm
|
||||||
|
- macos
|
||||||
|
- win-msvc
|
||||||
|
- win-gnu
|
||||||
|
include:
|
||||||
|
- build: pinned
|
||||||
|
os: ubuntu-22.04
|
||||||
|
rust: 1.65.0
|
||||||
|
- build: stable
|
||||||
|
os: ubuntu-22.04
|
||||||
|
rust: stable
|
||||||
|
- build: beta
|
||||||
|
os: ubuntu-22.04
|
||||||
|
rust: beta
|
||||||
|
- build: nightly
|
||||||
|
os: ubuntu-22.04
|
||||||
|
rust: nightly
|
||||||
|
- build: nightly-musl
|
||||||
|
os: ubuntu-22.04
|
||||||
|
rust: nightly
|
||||||
|
target: x86_64-unknown-linux-musl
|
||||||
|
- build: nightly-32
|
||||||
|
os: ubuntu-22.04
|
||||||
|
rust: nightly
|
||||||
|
target: i686-unknown-linux-gnu
|
||||||
|
- build: nightly-mips
|
||||||
|
os: ubuntu-22.04
|
||||||
|
rust: nightly
|
||||||
|
target: mips64-unknown-linux-gnuabi64
|
||||||
|
- build: nightly-arm
|
||||||
|
os: ubuntu-22.04
|
||||||
|
rust: nightly
|
||||||
|
# For stripping release binaries:
|
||||||
|
# docker run --rm -v $PWD/target:/target:Z \
|
||||||
|
# rustembedded/cross:arm-unknown-linux-gnueabihf \
|
||||||
|
# arm-linux-gnueabihf-strip \
|
||||||
|
# /target/arm-unknown-linux-gnueabihf/debug/rg
|
||||||
|
target: arm-unknown-linux-gnueabihf
|
||||||
|
- build: macos
|
||||||
|
os: macos-12
|
||||||
|
rust: nightly
|
||||||
|
- build: win-msvc
|
||||||
|
os: windows-2022
|
||||||
|
rust: nightly
|
||||||
|
- build: win-gnu
|
||||||
|
os: windows-2022
|
||||||
|
rust: nightly-x86_64-gnu
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install packages (Ubuntu)
|
||||||
|
if: matrix.os == 'ubuntu-22.04'
|
||||||
|
run: |
|
||||||
|
ci/ubuntu-install-packages
|
||||||
|
|
||||||
|
- name: Install packages (macOS)
|
||||||
|
if: matrix.os == 'macos-12'
|
||||||
|
run: |
|
||||||
|
ci/macos-install-packages
|
||||||
|
|
||||||
|
- name: Install Rust
|
||||||
|
uses: dtolnay/rust-toolchain@master
|
||||||
|
with:
|
||||||
|
toolchain: ${{ matrix.rust }}
|
||||||
|
|
||||||
|
- name: Use Cross
|
||||||
|
if: matrix.target != ''
|
||||||
|
run: |
|
||||||
|
cargo install cross
|
||||||
|
echo "CARGO=cross" >> $GITHUB_ENV
|
||||||
|
echo "TARGET_FLAGS=--target ${{ matrix.target }}" >> $GITHUB_ENV
|
||||||
|
echo "TARGET_DIR=./target/${{ matrix.target }}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Show command used for Cargo
|
||||||
|
run: |
|
||||||
|
echo "cargo command is: ${{ env.CARGO }}"
|
||||||
|
echo "target flag is: ${{ env.TARGET_FLAGS }}"
|
||||||
|
|
||||||
|
- name: Build ripgrep and all crates
|
||||||
|
run: ${{ env.CARGO }} build --verbose --workspace ${{ env.TARGET_FLAGS }}
|
||||||
|
|
||||||
|
- name: Build ripgrep with PCRE2
|
||||||
|
run: ${{ env.CARGO }} build --verbose --workspace --features pcre2 ${{ env.TARGET_FLAGS }}
|
||||||
|
|
||||||
|
# This is useful for debugging problems when the expected build artifacts
|
||||||
|
# (like shell completions and man pages) aren't generated.
|
||||||
|
- name: Show build.rs stderr
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set +x
|
||||||
|
stderr="$(find "${{ env.TARGET_DIR }}/debug" -name stderr -print0 | xargs -0 ls -t | head -n1)"
|
||||||
|
if [ -s "$stderr" ]; then
|
||||||
|
echo "===== $stderr ===== "
|
||||||
|
cat "$stderr"
|
||||||
|
echo "====="
|
||||||
|
fi
|
||||||
|
set -x
|
||||||
|
|
||||||
|
- name: Run tests with PCRE2 (sans cross)
|
||||||
|
if: matrix.target == ''
|
||||||
|
run: ${{ env.CARGO }} test --verbose --workspace --features pcre2 ${{ env.TARGET_FLAGS }}
|
||||||
|
|
||||||
|
- name: Run tests without PCRE2 (with cross)
|
||||||
|
# These tests should actually work, but they almost double the runtime.
|
||||||
|
# Every integration test spins up qemu to run 'rg', and when PCRE2 is
|
||||||
|
# enabled, every integration test is run twice: one with the default
|
||||||
|
# regex engine and once with PCRE2.
|
||||||
|
if: matrix.target != ''
|
||||||
|
run: ${{ env.CARGO }} test --verbose --workspace ${{ env.TARGET_FLAGS }}
|
||||||
|
|
||||||
|
- name: Test for existence of build artifacts (Windows)
|
||||||
|
if: matrix.os == 'windows-2022'
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
outdir="$(ci/cargo-out-dir "${{ env.TARGET_DIR }}")"
|
||||||
|
ls "$outdir/_rg.ps1" && file "$outdir/_rg.ps1"
|
||||||
|
|
||||||
|
- name: Test for existence of build artifacts (Unix)
|
||||||
|
if: matrix.os != 'windows-2022'
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
outdir="$(ci/cargo-out-dir "${{ env.TARGET_DIR }}")"
|
||||||
|
# TODO: Check for the man page generation here. For whatever reason,
|
||||||
|
# it seems to be intermittently failing in CI. No idea why.
|
||||||
|
# for f in rg.bash rg.fish rg.1; do
|
||||||
|
for f in rg.bash rg.fish; do
|
||||||
|
# We could use file -E here, but it isn't supported on macOS.
|
||||||
|
ls "$outdir/$f" && file "$outdir/$f"
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Test zsh shell completions (Unix, sans cross)
|
||||||
|
# We could test this when using Cross, but we'd have to execute the
|
||||||
|
# 'rg' binary (done in test-complete) with qemu, which is a pain and
|
||||||
|
# doesn't really gain us much. If shell completion works in one place,
|
||||||
|
# it probably works everywhere.
|
||||||
|
if: matrix.target == '' && matrix.os != 'windows-2022'
|
||||||
|
shell: bash
|
||||||
|
run: ci/test-complete
|
||||||
|
|
||||||
|
rustfmt:
|
||||||
|
name: rustfmt
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Install Rust
|
||||||
|
uses: dtolnay/rust-toolchain@master
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
components: rustfmt
|
||||||
|
- name: Check formatting
|
||||||
|
run: cargo fmt --all --check
|
||||||
|
|
||||||
|
docs:
|
||||||
|
name: Docs
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Install Rust
|
||||||
|
uses: dtolnay/rust-toolchain@master
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
- name: Check documentation
|
||||||
|
env:
|
||||||
|
RUSTDOCFLAGS: -D warnings
|
||||||
|
run: cargo doc --no-deps --document-private-items --workspace
|
||||||
180
.github/workflows/release.yml
vendored
Normal file
180
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
# The way this works is the following:
|
||||||
|
#
|
||||||
|
# The create-release job runs purely to initialize the GitHub release itself
|
||||||
|
# and to output upload_url for the following job.
|
||||||
|
#
|
||||||
|
# The build-release job runs only once create-release is finished. It gets the
|
||||||
|
# release upload URL from create-release job outputs, then builds the release
|
||||||
|
# executables for each supported platform and attaches them as release assets
|
||||||
|
# to the previously created release.
|
||||||
|
#
|
||||||
|
# The key here is that we create the release only once.
|
||||||
|
#
|
||||||
|
# Reference:
|
||||||
|
# https://eugene-babichenko.github.io/blog/2020/05/09/github-actions-cross-platform-auto-releases/
|
||||||
|
|
||||||
|
name: release
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
# Enable when testing release infrastructure on a branch.
|
||||||
|
# branches:
|
||||||
|
# - ag/work
|
||||||
|
tags:
|
||||||
|
- "[0-9]+.[0-9]+.[0-9]+"
|
||||||
|
jobs:
|
||||||
|
create-release:
|
||||||
|
name: create-release
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
# env:
|
||||||
|
# Set to force version number, e.g., when no tag exists.
|
||||||
|
# RG_VERSION: TEST-0.0.0
|
||||||
|
outputs:
|
||||||
|
upload_url: ${{ steps.release.outputs.upload_url }}
|
||||||
|
rg_version: ${{ env.RG_VERSION }}
|
||||||
|
steps:
|
||||||
|
- name: Get the release version from the tag
|
||||||
|
shell: bash
|
||||||
|
if: env.RG_VERSION == ''
|
||||||
|
run: |
|
||||||
|
# Apparently, this is the right way to get a tag name. Really?
|
||||||
|
#
|
||||||
|
# See: https://github.community/t5/GitHub-Actions/How-to-get-just-the-tag-name/m-p/32167/highlight/true#M1027
|
||||||
|
echo "RG_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
||||||
|
echo "version is: ${{ env.RG_VERSION }}"
|
||||||
|
- name: Create GitHub release
|
||||||
|
id: release
|
||||||
|
uses: actions/create-release@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.RG_VERSION }}
|
||||||
|
release_name: ${{ env.RG_VERSION }}
|
||||||
|
|
||||||
|
build-release:
|
||||||
|
name: build-release
|
||||||
|
needs: ['create-release']
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
env:
|
||||||
|
# For some builds, we use cross to test on 32-bit and big-endian
|
||||||
|
# systems.
|
||||||
|
CARGO: cargo
|
||||||
|
# When CARGO is set to CROSS, this is set to `--target matrix.target`.
|
||||||
|
TARGET_FLAGS: ""
|
||||||
|
# When CARGO is set to CROSS, TARGET_DIR includes matrix.target.
|
||||||
|
TARGET_DIR: ./target
|
||||||
|
# Emit backtraces on panics.
|
||||||
|
RUST_BACKTRACE: 1
|
||||||
|
# Build static releases with PCRE2.
|
||||||
|
PCRE2_SYS_STATIC: 1
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
build: [linux, linux-arm, macos, win-msvc, win-gnu, win32-msvc]
|
||||||
|
include:
|
||||||
|
- build: linux
|
||||||
|
os: ubuntu-22.04
|
||||||
|
rust: nightly
|
||||||
|
target: x86_64-unknown-linux-musl
|
||||||
|
- build: linux-arm
|
||||||
|
os: ubuntu-22.04
|
||||||
|
rust: nightly
|
||||||
|
target: arm-unknown-linux-gnueabihf
|
||||||
|
- build: macos
|
||||||
|
os: macos-12
|
||||||
|
rust: nightly
|
||||||
|
target: x86_64-apple-darwin
|
||||||
|
- build: win-msvc
|
||||||
|
os: windows-2022
|
||||||
|
rust: nightly
|
||||||
|
target: x86_64-pc-windows-msvc
|
||||||
|
- build: win-gnu
|
||||||
|
os: windows-2022
|
||||||
|
rust: nightly-x86_64-gnu
|
||||||
|
target: x86_64-pc-windows-gnu
|
||||||
|
- build: win32-msvc
|
||||||
|
os: windows-2022
|
||||||
|
rust: nightly
|
||||||
|
target: i686-pc-windows-msvc
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install packages (Ubuntu)
|
||||||
|
if: matrix.os == 'ubuntu-22.04'
|
||||||
|
run: |
|
||||||
|
ci/ubuntu-install-packages
|
||||||
|
|
||||||
|
- name: Install packages (macOS)
|
||||||
|
if: matrix.os == 'macos-12'
|
||||||
|
run: |
|
||||||
|
ci/macos-install-packages
|
||||||
|
|
||||||
|
- name: Install Rust
|
||||||
|
uses: dtolnay/rust-toolchain@master
|
||||||
|
with:
|
||||||
|
toolchain: ${{ matrix.rust }}
|
||||||
|
target: ${{ matrix.target }}
|
||||||
|
|
||||||
|
- name: Use Cross
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
cargo install cross
|
||||||
|
echo "CARGO=cross" >> $GITHUB_ENV
|
||||||
|
echo "TARGET_FLAGS=--target ${{ matrix.target }}" >> $GITHUB_ENV
|
||||||
|
echo "TARGET_DIR=./target/${{ matrix.target }}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Show command used for Cargo
|
||||||
|
run: |
|
||||||
|
echo "cargo command is: ${{ env.CARGO }}"
|
||||||
|
echo "target flag is: ${{ env.TARGET_FLAGS }}"
|
||||||
|
echo "target dir is: ${{ env.TARGET_DIR }}"
|
||||||
|
|
||||||
|
- name: Build release binary
|
||||||
|
run: ${{ env.CARGO }} build --verbose --release --features pcre2 ${{ env.TARGET_FLAGS }}
|
||||||
|
|
||||||
|
- name: Strip release binary (linux and macos)
|
||||||
|
if: matrix.build == 'linux' || matrix.build == 'macos'
|
||||||
|
run: strip "target/${{ matrix.target }}/release/rg"
|
||||||
|
|
||||||
|
- name: Strip release binary (arm)
|
||||||
|
if: matrix.build == 'linux-arm'
|
||||||
|
run: |
|
||||||
|
docker run --rm -v \
|
||||||
|
"$PWD/target:/target:Z" \
|
||||||
|
rustembedded/cross:arm-unknown-linux-gnueabihf \
|
||||||
|
arm-linux-gnueabihf-strip \
|
||||||
|
/target/arm-unknown-linux-gnueabihf/release/rg
|
||||||
|
|
||||||
|
- name: Build archive
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
outdir="$(ci/cargo-out-dir "${{ env.TARGET_DIR }}")"
|
||||||
|
staging="ripgrep-${{ needs.create-release.outputs.rg_version }}-${{ matrix.target }}"
|
||||||
|
mkdir -p "$staging"/{complete,doc}
|
||||||
|
|
||||||
|
cp {README.md,COPYING,UNLICENSE,LICENSE-MIT} "$staging/"
|
||||||
|
cp {CHANGELOG.md,FAQ.md,GUIDE.md} "$staging/doc/"
|
||||||
|
cp "$outdir"/{rg.bash,rg.fish,_rg.ps1} "$staging/complete/"
|
||||||
|
cp complete/_rg "$staging/complete/"
|
||||||
|
|
||||||
|
if [ "${{ matrix.os }}" = "windows-2022" ]; then
|
||||||
|
cp "target/${{ matrix.target }}/release/rg.exe" "$staging/"
|
||||||
|
7z a "$staging.zip" "$staging"
|
||||||
|
echo "ASSET=$staging.zip" >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
# The man page is only generated on Unix systems. ¯\_(ツ)_/¯
|
||||||
|
cp "$outdir"/rg.1 "$staging/doc/"
|
||||||
|
cp "target/${{ matrix.target }}/release/rg" "$staging/"
|
||||||
|
tar czf "$staging.tar.gz" "$staging"
|
||||||
|
echo "ASSET=$staging.tar.gz" >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Upload release archive
|
||||||
|
uses: actions/upload-release-asset@v1.0.2
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ needs.create-release.outputs.upload_url }}
|
||||||
|
asset_path: ${{ env.ASSET }}
|
||||||
|
asset_name: ${{ env.ASSET }}
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -15,3 +15,7 @@ parts
|
|||||||
*.snap
|
*.snap
|
||||||
*.pyc
|
*.pyc
|
||||||
ripgrep*_source.tar.bz2
|
ripgrep*_source.tar.bz2
|
||||||
|
|
||||||
|
# Cargo timings
|
||||||
|
cargo-timing-*.html
|
||||||
|
cargo-timing.html
|
||||||
|
|||||||
110
.travis.yml
110
.travis.yml
@@ -1,110 +0,0 @@
|
|||||||
language: rust
|
|
||||||
dist: xenial
|
|
||||||
env:
|
|
||||||
global:
|
|
||||||
- PROJECT_NAME: ripgrep
|
|
||||||
- RUST_BACKTRACE: full
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
# For generating man page.
|
|
||||||
- libxslt1-dev
|
|
||||||
- asciidoc
|
|
||||||
- docbook-xsl
|
|
||||||
- xsltproc
|
|
||||||
- libxml2-utils
|
|
||||||
# Needed for completion-function test.
|
|
||||||
- zsh
|
|
||||||
# Needed for testing decompression search.
|
|
||||||
- xz-utils
|
|
||||||
- liblz4-tool
|
|
||||||
# For building MUSL static builds on Linux.
|
|
||||||
- musl-tools
|
|
||||||
matrix:
|
|
||||||
fast_finish: true
|
|
||||||
include:
|
|
||||||
# Nightly channel.
|
|
||||||
# All *nix releases are done on the nightly channel to take advantage
|
|
||||||
# of the regex library's multiple pattern SIMD search.
|
|
||||||
- os: linux
|
|
||||||
rust: nightly
|
|
||||||
env: TARGET=i686-unknown-linux-musl
|
|
||||||
- os: linux
|
|
||||||
rust: nightly
|
|
||||||
env: TARGET=x86_64-unknown-linux-musl
|
|
||||||
- os: osx
|
|
||||||
rust: nightly
|
|
||||||
# XML_CATALOG_FILES is apparently necessary for asciidoc on macOS.
|
|
||||||
env: TARGET=x86_64-apple-darwin XML_CATALOG_FILES=/usr/local/etc/xml/catalog
|
|
||||||
- os: linux
|
|
||||||
rust: nightly
|
|
||||||
env: TARGET=arm-unknown-linux-gnueabihf GCC_VERSION=4.8
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- gcc-4.8-arm-linux-gnueabihf
|
|
||||||
- binutils-arm-linux-gnueabihf
|
|
||||||
- libc6-armhf-cross
|
|
||||||
- libc6-dev-armhf-cross
|
|
||||||
# For generating man page.
|
|
||||||
- libxslt1-dev
|
|
||||||
- asciidoc
|
|
||||||
- docbook-xsl
|
|
||||||
- xsltproc
|
|
||||||
- libxml2-utils
|
|
||||||
# Beta channel. We enable these to make sure there are no regressions in
|
|
||||||
# Rust beta releases.
|
|
||||||
- os: linux
|
|
||||||
rust: beta
|
|
||||||
env: TARGET=x86_64-unknown-linux-musl
|
|
||||||
- os: linux
|
|
||||||
rust: beta
|
|
||||||
env: TARGET=x86_64-unknown-linux-gnu
|
|
||||||
# Minimum Rust supported channel. We enable these to make sure ripgrep
|
|
||||||
# continues to work on the advertised minimum Rust version.
|
|
||||||
- os: linux
|
|
||||||
rust: 1.34.0
|
|
||||||
env: TARGET=x86_64-unknown-linux-gnu
|
|
||||||
- os: linux
|
|
||||||
rust: 1.34.0
|
|
||||||
env: TARGET=x86_64-unknown-linux-musl
|
|
||||||
- os: linux
|
|
||||||
rust: 1.34.0
|
|
||||||
env: TARGET=arm-unknown-linux-gnueabihf GCC_VERSION=4.8
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- gcc-4.8-arm-linux-gnueabihf
|
|
||||||
- binutils-arm-linux-gnueabihf
|
|
||||||
- libc6-armhf-cross
|
|
||||||
- libc6-dev-armhf-cross
|
|
||||||
# For generating man page.
|
|
||||||
- libxslt1-dev
|
|
||||||
- asciidoc
|
|
||||||
- docbook-xsl
|
|
||||||
- xsltproc
|
|
||||||
- libxml2-utils
|
|
||||||
install: ci/install.sh
|
|
||||||
script: ci/script.sh
|
|
||||||
before_deploy: ci/before_deploy.sh
|
|
||||||
deploy:
|
|
||||||
provider: releases
|
|
||||||
file_glob: true
|
|
||||||
file: deployment/${PROJECT_NAME}-${TRAVIS_TAG}-${TARGET}.tar.gz
|
|
||||||
skip_cleanup: true
|
|
||||||
on:
|
|
||||||
condition: $TRAVIS_RUST_VERSION = nightly
|
|
||||||
branch: master # i guess we do need this after all?
|
|
||||||
tags: true
|
|
||||||
api_key:
|
|
||||||
secure: "IbSnsbGkxSydR/sozOf1/SRvHplzwRUHzcTjM7BKnr7GccL86gRPUrsrvD103KjQUGWIc1TnK1YTq5M0Onswg/ORDjqa1JEJPkPdPnVh9ipbF7M2De/7IlB4X4qXLKoApn8+bx2x/mfYXu4G+G1/2QdbaKK2yfXZKyjz0YFx+6CNrVCT2Nk8q7aHvOOzAL58vsG8iPDpupuhxlMDDn/UhyOWVInmPPQ0iJR1ZUJN8xJwXvKvBbfp3AhaBiAzkhXHNLgBR8QC5noWWMXnuVDMY3k4f3ic0V+p/qGUCN/nhptuceLxKFicMCYObSZeUzE5RAI0/OBW7l3z2iCoc+TbAnn+JrX/ObJCfzgAOXAU3tLaBFMiqQPGFKjKg1ltSYXomOFP/F7zALjpvFp4lYTBajRR+O3dqaxA9UQuRjw27vOeUpMcga4ZzL4VXFHzrxZKBHN//XIGjYAVhJ1NSSeGpeJV5/+jYzzWKfwSagRxQyVCzMooYFFXzn8Yxdm3PJlmp3GaAogNkdB9qKcrEvRINCelalzALPi0hD/HUDi8DD2PNTCLLMo6VSYtvc685Zbe+KgNzDV1YyTrRCUW6JotrS0r2ULLwnsh40hSB//nNv3XmwNmC/CmW5QAnIGj8cBMF4S2t6ohADIndojdAfNiptmaZOIT6owK7bWMgPMyopo="
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
# Pushes and PR to the master branch
|
|
||||||
- master
|
|
||||||
# Ruby regex to match tags. Required, or travis won't trigger deploys when
|
|
||||||
# a new tag is pushed.
|
|
||||||
- /^\d+\.\d+\.\d+.*$/
|
|
||||||
notifications:
|
|
||||||
email:
|
|
||||||
on_success: never
|
|
||||||
362
CHANGELOG.md
362
CHANGELOG.md
@@ -1,5 +1,353 @@
|
|||||||
11.0.0 (TBD)
|
TBD
|
||||||
============
|
===
|
||||||
|
Unreleased changes. Release notes have not yet been written.
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* [BUG #1891](https://github.com/BurntSushi/ripgrep/issues/1891):
|
||||||
|
Fix bug when using `-w` with a regex that can match the empty string.
|
||||||
|
* [BUG #1911](https://github.com/BurntSushi/ripgrep/issues/1911):
|
||||||
|
Disable mmap searching in all non-64-bit environments.
|
||||||
|
* [BUG #2236](https://github.com/BurntSushi/ripgrep/issues/2236):
|
||||||
|
Fix gitignore parsing bug where a trailing `\/` resulted in an error.
|
||||||
|
|
||||||
|
|
||||||
|
13.0.0 (2021-06-12)
|
||||||
|
===================
|
||||||
|
ripgrep 13 is a new major version release of ripgrep that primarily contains
|
||||||
|
bug fixes, some performance improvements and a few minor breaking changes.
|
||||||
|
There is also a fix for a security vulnerability on Windows
|
||||||
|
([CVE-2021-3013](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3013)).
|
||||||
|
|
||||||
|
Some highlights:
|
||||||
|
|
||||||
|
A new short flag, `-.`, has been added. It is an alias for the `--hidden` flag,
|
||||||
|
which instructs ripgrep to search hidden files and directories.
|
||||||
|
|
||||||
|
ripgrep is now using a new
|
||||||
|
[vectorized implementation of `memmem`](https://github.com/BurntSushi/memchr/pull/82),
|
||||||
|
which accelerates many common searches. If you notice any performance
|
||||||
|
regressions (or major improvements), I'd love to hear about them through an
|
||||||
|
issue report!
|
||||||
|
|
||||||
|
Also, for Windows users targeting MSVC, Cargo will now build fully static
|
||||||
|
executables of ripgrep. The release binaries for ripgrep 13 have been compiled
|
||||||
|
using this configuration.
|
||||||
|
|
||||||
|
**BREAKING CHANGES**:
|
||||||
|
|
||||||
|
**Binary detection output has changed slightly.**
|
||||||
|
|
||||||
|
In this release, a small tweak has been made to the output format when a binary
|
||||||
|
file is detected. Previously, it looked like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
Binary file FOO matches (found "\0" byte around offset XXX)
|
||||||
|
```
|
||||||
|
|
||||||
|
Now it looks like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
FOO: binary file matches (found "\0" byte around offset XXX)
|
||||||
|
```
|
||||||
|
|
||||||
|
**vimgrep output in multi-line now only prints the first line for each match.**
|
||||||
|
|
||||||
|
See [issue 1866](https://github.com/BurntSushi/ripgrep/issues/1866) for more
|
||||||
|
discussion on this. Previously, every line in a match was duplicated, even
|
||||||
|
when it spanned multiple lines. There are no changes to vimgrep output when
|
||||||
|
multi-line mode is disabled.
|
||||||
|
|
||||||
|
**In multi-line mode, --count is now equivalent to --count-matches.**
|
||||||
|
|
||||||
|
This appears to match how `pcre2grep` implements `--count`. Previously, ripgrep
|
||||||
|
would produce outright incorrect counts. Another alternative would be to simply
|
||||||
|
count the number of lines---even if it's more than the number of matches---but
|
||||||
|
that seems highly unintuitive.
|
||||||
|
|
||||||
|
**FULL LIST OF FIXES AND IMPROVEMENTS:**
|
||||||
|
|
||||||
|
Security fixes:
|
||||||
|
|
||||||
|
* [CVE-2021-3013](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3013):
|
||||||
|
Fixes a security hole on Windows where running ripgrep with either the
|
||||||
|
`-z/--search-zip` or `--pre` flags can result in running arbitrary
|
||||||
|
executables from the current directory.
|
||||||
|
* [VULN #1773](https://github.com/BurntSushi/ripgrep/issues/1773):
|
||||||
|
This is the public facing issue tracking CVE-2021-3013. ripgrep's README
|
||||||
|
now contains a section describing how to report a vulnerability.
|
||||||
|
|
||||||
|
Performance improvements:
|
||||||
|
|
||||||
|
* [PERF #1657](https://github.com/BurntSushi/ripgrep/discussions/1657):
|
||||||
|
Check if a file should be ignored first before issuing stat calls.
|
||||||
|
* [PERF memchr#82](https://github.com/BurntSushi/memchr/pull/82):
|
||||||
|
ripgrep now uses a new vectorized implementation of `memmem`.
|
||||||
|
|
||||||
|
Feature enhancements:
|
||||||
|
|
||||||
|
* Added or improved file type filtering for ASP, Bazel, dvc, FlatBuffers,
|
||||||
|
Futhark, minified files, Mint, pofiles (from GNU gettext) Racket, Red, Ruby,
|
||||||
|
VCL, Yang.
|
||||||
|
* [FEATURE #1404](https://github.com/BurntSushi/ripgrep/pull/1404):
|
||||||
|
ripgrep now prints a warning if nothing is searched.
|
||||||
|
* [FEATURE #1613](https://github.com/BurntSushi/ripgrep/pull/1613):
|
||||||
|
Cargo will now produce static executables on Windows when using MSVC.
|
||||||
|
* [FEATURE #1680](https://github.com/BurntSushi/ripgrep/pull/1680):
|
||||||
|
Add `-.` as a short flag alias for `--hidden`.
|
||||||
|
* [FEATURE #1842](https://github.com/BurntSushi/ripgrep/issues/1842):
|
||||||
|
Add `--field-{context,match}-separator` for customizing field delimiters.
|
||||||
|
* [FEATURE #1856](https://github.com/BurntSushi/ripgrep/pull/1856):
|
||||||
|
The README now links to a
|
||||||
|
[Spanish translation](https://github.com/UltiRequiem/traducciones/tree/master/ripgrep).
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* [BUG #1277](https://github.com/BurntSushi/ripgrep/issues/1277):
|
||||||
|
Document cygwin path translation behavior in the FAQ.
|
||||||
|
* [BUG #1739](https://github.com/BurntSushi/ripgrep/issues/1739):
|
||||||
|
Fix bug where replacements were buggy if the regex matched a line terminator.
|
||||||
|
* [BUG #1311](https://github.com/BurntSushi/ripgrep/issues/1311):
|
||||||
|
Fix multi-line bug where a search & replace for `\n` didn't work as expected.
|
||||||
|
* [BUG #1401](https://github.com/BurntSushi/ripgrep/issues/1401):
|
||||||
|
Fix buggy interaction between PCRE2 look-around and `-o/--only-matching`.
|
||||||
|
* [BUG #1412](https://github.com/BurntSushi/ripgrep/issues/1412):
|
||||||
|
Fix multi-line bug with searches using look-around past matching lines.
|
||||||
|
* [BUG #1577](https://github.com/BurntSushi/ripgrep/issues/1577):
|
||||||
|
Fish shell completions will continue to be auto-generated.
|
||||||
|
* [BUG #1642](https://github.com/BurntSushi/ripgrep/issues/1642):
|
||||||
|
Fixes a bug where using `-m` and `-A` printed more matches than the limit.
|
||||||
|
* [BUG #1703](https://github.com/BurntSushi/ripgrep/issues/1703):
|
||||||
|
Clarify the function of `-u/--unrestricted`.
|
||||||
|
* [BUG #1708](https://github.com/BurntSushi/ripgrep/issues/1708):
|
||||||
|
Clarify how `-S/--smart-case` works.
|
||||||
|
* [BUG #1730](https://github.com/BurntSushi/ripgrep/issues/1730):
|
||||||
|
Clarify that CLI invocation must always be valid, regardless of config file.
|
||||||
|
* [BUG #1741](https://github.com/BurntSushi/ripgrep/issues/1741):
|
||||||
|
Fix stdin detection when using PowerShell in UNIX environments.
|
||||||
|
* [BUG #1756](https://github.com/BurntSushi/ripgrep/pull/1756):
|
||||||
|
Fix bug where `foo/**` would match `foo`, but it shouldn't.
|
||||||
|
* [BUG #1765](https://github.com/BurntSushi/ripgrep/issues/1765):
|
||||||
|
Fix panic when `--crlf` is used in some cases.
|
||||||
|
* [BUG #1638](https://github.com/BurntSushi/ripgrep/issues/1638):
|
||||||
|
Correctly sniff UTF-8 and do transcoding, like we do for UTF-16.
|
||||||
|
* [BUG #1816](https://github.com/BurntSushi/ripgrep/issues/1816):
|
||||||
|
Add documentation for glob alternate syntax, e.g., `{a,b,..}`.
|
||||||
|
* [BUG #1847](https://github.com/BurntSushi/ripgrep/issues/1847):
|
||||||
|
Clarify how the `--hidden` flag works.
|
||||||
|
* [BUG #1866](https://github.com/BurntSushi/ripgrep/issues/1866#issuecomment-841635553):
|
||||||
|
Fix bug when computing column numbers in `--vimgrep` mode.
|
||||||
|
* [BUG #1868](https://github.com/BurntSushi/ripgrep/issues/1868):
|
||||||
|
Fix bug where `--passthru` and `-A/-B/-C` did not override each other.
|
||||||
|
* [BUG #1869](https://github.com/BurntSushi/ripgrep/pull/1869):
|
||||||
|
Clarify docs for `--files-with-matches` and `--files-without-match`.
|
||||||
|
* [BUG #1878](https://github.com/BurntSushi/ripgrep/issues/1878):
|
||||||
|
Fix bug where `\A` could produce unanchored matches in multiline search.
|
||||||
|
* [BUG 94e4b8e3](https://github.com/BurntSushi/ripgrep/commit/94e4b8e3):
|
||||||
|
Fix column numbers with `--vimgrep` is used with `-U/--multiline`.
|
||||||
|
|
||||||
|
|
||||||
|
12.1.1 (2020-05-29)
|
||||||
|
===================
|
||||||
|
ripgrep 12.1.1 is a patch release that fixes a couple small bugs. In
|
||||||
|
particular, the ripgrep 12.1.0 release did not tag new releases for all of its
|
||||||
|
in-tree dependencies. As a result, ripgrep built dependencies from crates.io
|
||||||
|
would produce a different build than compiling ripgrep from source on the
|
||||||
|
`12.1.0` tag. Namely, some crates like `grep-cli` had unreleased changes.
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* [BUG #1581](https://github.com/BurntSushi/ripgrep/issues/1581):
|
||||||
|
Corrects some egregious markup output in `--help`.
|
||||||
|
* [BUG #1591](https://github.com/BurntSushi/ripgrep/issues/1591):
|
||||||
|
Mention the special `$0` capture group in docs for the `-r/--replace` flag.
|
||||||
|
* [BUG #1602](https://github.com/BurntSushi/ripgrep/issues/1602):
|
||||||
|
Fix failing test resulting from out-of-sync dependencies.
|
||||||
|
|
||||||
|
|
||||||
|
12.1.0 (2020-05-09)
|
||||||
|
===================
|
||||||
|
ripgrep 12.1.0 is a small minor version release that mostly includes bug fixes
|
||||||
|
and documentation improvements. This release also contains some important
|
||||||
|
notices for downstream packagers.
|
||||||
|
|
||||||
|
**Notices for downstream ripgrep package maintainers:**
|
||||||
|
|
||||||
|
* Fish shell completions will be removed in the ripgrep 13 release.
|
||||||
|
See [#1577](https://github.com/BurntSushi/ripgrep/issues/1577)
|
||||||
|
for more details.
|
||||||
|
* ripgrep has switched from `a2x` to `asciidoctor` to generate the man page.
|
||||||
|
If `asciidoctor` is not present, then ripgrep will currently fall back to
|
||||||
|
`a2x`. Support for `a2x` will be dropped in the ripgrep 13 release.
|
||||||
|
See [#1544](https://github.com/BurntSushi/ripgrep/issues/1544)
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
Feature enhancements:
|
||||||
|
|
||||||
|
* [FEATURE #1547](https://github.com/BurntSushi/ripgrep/pull/1547):
|
||||||
|
Support decompressing `.Z` files via `uncompress`.
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* [BUG #1252](https://github.com/BurntSushi/ripgrep/issues/1252):
|
||||||
|
Add a section on the `--pre` flag to the GUIDE.
|
||||||
|
* [BUG #1339](https://github.com/BurntSushi/ripgrep/issues/1339):
|
||||||
|
Improve error message when a pattern with invalid UTF-8 is provided.
|
||||||
|
* [BUG #1524](https://github.com/BurntSushi/ripgrep/issues/1524):
|
||||||
|
Note how to escape a `$` when using `--replace`.
|
||||||
|
* [BUG #1537](https://github.com/BurntSushi/ripgrep/issues/1537):
|
||||||
|
Fix match bug caused by inner literal optimization.
|
||||||
|
* [BUG #1544](https://github.com/BurntSushi/ripgrep/issues/1544):
|
||||||
|
ripgrep now uses `asciidoctor` instead of `a2x` to generate its man page.
|
||||||
|
* [BUG #1550](https://github.com/BurntSushi/ripgrep/issues/1550):
|
||||||
|
Substantially reduce peak memory usage when searching wide directories.
|
||||||
|
* [BUG #1571](https://github.com/BurntSushi/ripgrep/issues/1571):
|
||||||
|
Add note about configuration files in `--type-{add,clear}` docs.
|
||||||
|
* [BUG #1573](https://github.com/BurntSushi/ripgrep/issues/1573):
|
||||||
|
Fix incorrect `--count-matches` output when using look-around.
|
||||||
|
|
||||||
|
|
||||||
|
12.0.1 (2020-03-29)
|
||||||
|
===================
|
||||||
|
ripgrep 12.0.1 is a small patch release that includes a minor bug fix relating
|
||||||
|
to superfluous error messages when searching git repositories with sub-modules.
|
||||||
|
This was a regression introduced in the 12.0.0 release.
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* [BUG #1520](https://github.com/BurntSushi/ripgrep/issues/1520):
|
||||||
|
Don't emit spurious error messages in git repositories with submodules.
|
||||||
|
|
||||||
|
|
||||||
|
12.0.0 (2020-03-15)
|
||||||
|
===================
|
||||||
|
ripgrep 12 is a new major version release of ripgrep that contains many bug
|
||||||
|
fixes, several important performance improvements and a few minor new features.
|
||||||
|
|
||||||
|
In a near future release, I am hoping to add an
|
||||||
|
[indexing feature](https://github.com/BurntSushi/ripgrep/issues/1497)
|
||||||
|
to ripgrep, which will dramatically speed up searching by building an index.
|
||||||
|
Feedback would very much be appreciated, especially on the user experience
|
||||||
|
which will be difficult to get right.
|
||||||
|
|
||||||
|
This release has no known breaking changes.
|
||||||
|
|
||||||
|
Deprecations:
|
||||||
|
|
||||||
|
* The `--no-pcre2-unicode` flag is deprecated. Instead, use the `--no-unicode`
|
||||||
|
flag, which applies to both the default regex engine and PCRE2. For now,
|
||||||
|
`--no-pcre2-unicode` and `--pcre2-unicode` are aliases to `--no-unicode`
|
||||||
|
and `--unicode`, respectively. The `--[no-]pcre2-unicode` flags may be
|
||||||
|
removed in a future release.
|
||||||
|
* The `--auto-hybrid-regex` flag is deprecated. Instead, use the new `--engine`
|
||||||
|
flag with the `auto` value.
|
||||||
|
|
||||||
|
Performance improvements:
|
||||||
|
|
||||||
|
* [PERF #1087](https://github.com/BurntSushi/ripgrep/pull/1087):
|
||||||
|
ripgrep is smarter when detected literals are whitespace.
|
||||||
|
* [PERF #1381](https://github.com/BurntSushi/ripgrep/pull/1381):
|
||||||
|
Directory traversal is sped up with speculative ignore-file existence checks.
|
||||||
|
* [PERF cd8ec38a](https://github.com/BurntSushi/ripgrep/commit/cd8ec38a):
|
||||||
|
Improve inner literal detection to cover more cases more effectively.
|
||||||
|
e.g., ` +Sherlock Holmes +` now has ` Sherlock Holmes ` extracted instead
|
||||||
|
of ` `.
|
||||||
|
* [PERF 6a0e0147](https://github.com/BurntSushi/ripgrep/commit/6a0e0147):
|
||||||
|
Improve literal detection when the `-w/--word-regexp` flag is used.
|
||||||
|
* [PERF ad97e9c9](https://github.com/BurntSushi/ripgrep/commit/ad97e9c9):
|
||||||
|
Improve overall performance of the `-w/--word-regexp` flag.
|
||||||
|
|
||||||
|
Feature enhancements:
|
||||||
|
|
||||||
|
* Added or improved file type filtering for erb, diff, Gradle, HAML, Org,
|
||||||
|
Postscript, Skim, Slim, Slime, RPM Spec files, Typoscript, xml.
|
||||||
|
* [FEATURE #1370](https://github.com/BurntSushi/ripgrep/pull/1370):
|
||||||
|
Add `--include-zero` flag that shows files searched without matches.
|
||||||
|
* [FEATURE #1390](https://github.com/BurntSushi/ripgrep/pull/1390):
|
||||||
|
Add `--no-context-separator` flag that always hides context separators.
|
||||||
|
* [FEATURE #1414](https://github.com/BurntSushi/ripgrep/pull/1414):
|
||||||
|
Add `--no-require-git` flag to allow ripgrep to respect gitignores anywhere.
|
||||||
|
* [FEATURE #1420](https://github.com/BurntSushi/ripgrep/pull/1420):
|
||||||
|
Add `--no-ignore-exclude` to disregard rules in `.git/info/exclude` files.
|
||||||
|
* [FEATURE #1466](https://github.com/BurntSushi/ripgrep/pull/1466):
|
||||||
|
Add `--no-ignore-files` flag to disable all `--ignore-file` flags.
|
||||||
|
* [FEATURE #1488](https://github.com/BurntSushi/ripgrep/pull/1488):
|
||||||
|
Add '--engine' flag for easier switching between regex engines.
|
||||||
|
* [FEATURE 75cbe88f](https://github.com/BurntSushi/ripgrep/commit/75cbe88f):
|
||||||
|
Add `--no-unicode` flag. This works on all supported regex engines.
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* [BUG #1291](https://github.com/BurntSushi/ripgrep/issues/1291):
|
||||||
|
ripgrep now works in non-existent directories.
|
||||||
|
* [BUG #1319](https://github.com/BurntSushi/ripgrep/issues/1319):
|
||||||
|
Fix match bug due to errant literal detection.
|
||||||
|
* [**BUG #1335**](https://github.com/BurntSushi/ripgrep/issues/1335):
|
||||||
|
Fixes a performance bug when searching plain text files with very long lines.
|
||||||
|
This was a serious performance regression in some cases.
|
||||||
|
* [BUG #1344](https://github.com/BurntSushi/ripgrep/issues/1344):
|
||||||
|
Document usage of `--type all`.
|
||||||
|
* [BUG #1389](https://github.com/BurntSushi/ripgrep/issues/1389):
|
||||||
|
Fixes a bug where ripgrep would panic when searching a symlinked directory.
|
||||||
|
* [BUG #1439](https://github.com/BurntSushi/ripgrep/issues/1439):
|
||||||
|
Improve documentation for ripgrep's automatic stdin detection.
|
||||||
|
* [BUG #1441](https://github.com/BurntSushi/ripgrep/issues/1441):
|
||||||
|
Remove CPU features from man page.
|
||||||
|
* [BUG #1442](https://github.com/BurntSushi/ripgrep/issues/1442),
|
||||||
|
[BUG #1478](https://github.com/BurntSushi/ripgrep/issues/1478):
|
||||||
|
Improve documentation of the `-g/--glob` flag.
|
||||||
|
* [BUG #1445](https://github.com/BurntSushi/ripgrep/issues/1445):
|
||||||
|
ripgrep now respects ignore rules from .git/info/exclude in worktrees.
|
||||||
|
* [BUG #1485](https://github.com/BurntSushi/ripgrep/issues/1485):
|
||||||
|
Fish shell completions from the release Debian package are now installed to
|
||||||
|
`/usr/share/fish/vendor_completions.d/rg.fish`.
|
||||||
|
|
||||||
|
|
||||||
|
11.0.2 (2019-08-01)
|
||||||
|
===================
|
||||||
|
ripgrep 11.0.2 is a new patch release that fixes a few bugs, including a
|
||||||
|
performance regression and a matching bug when using the `-F/--fixed-strings`
|
||||||
|
flag.
|
||||||
|
|
||||||
|
Feature enhancements:
|
||||||
|
|
||||||
|
* [FEATURE #1293](https://github.com/BurntSushi/ripgrep/issues/1293):
|
||||||
|
Added `--glob-case-insensitive` flag that makes `--glob` behave as `--iglob`.
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* [BUG #1246](https://github.com/BurntSushi/ripgrep/issues/1246):
|
||||||
|
Add translations to README, starting with an unofficial Chinese translation.
|
||||||
|
* [BUG #1259](https://github.com/BurntSushi/ripgrep/issues/1259):
|
||||||
|
Fix bug where the last byte of a `-f file` was stripped if it wasn't a `\n`.
|
||||||
|
* [BUG #1261](https://github.com/BurntSushi/ripgrep/issues/1261):
|
||||||
|
Document that no error is reported when searching for `\n` with `-P/--pcre2`.
|
||||||
|
* [BUG #1284](https://github.com/BurntSushi/ripgrep/issues/1284):
|
||||||
|
Mention `.ignore` and `.rgignore` more prominently in the README.
|
||||||
|
* [BUG #1292](https://github.com/BurntSushi/ripgrep/issues/1292):
|
||||||
|
Fix bug where `--with-filename` was sometimes enabled incorrectly.
|
||||||
|
* [BUG #1268](https://github.com/BurntSushi/ripgrep/issues/1268):
|
||||||
|
Fix major performance regression in GitHub `x86_64-linux` binary release.
|
||||||
|
* [BUG #1302](https://github.com/BurntSushi/ripgrep/issues/1302):
|
||||||
|
Show better error messages when a non-existent preprocessor command is given.
|
||||||
|
* [BUG #1334](https://github.com/BurntSushi/ripgrep/issues/1334):
|
||||||
|
Fix match regression with `-F` flag when patterns contain meta characters.
|
||||||
|
|
||||||
|
|
||||||
|
11.0.1 (2019-04-16)
|
||||||
|
===================
|
||||||
|
ripgrep 11.0.1 is a new patch release that fixes a search regression introduced
|
||||||
|
in the previous 11.0.0 release. In particular, ripgrep can enter an infinite
|
||||||
|
loop for some search patterns when searching invalid UTF-8.
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* [BUG #1247](https://github.com/BurntSushi/ripgrep/issues/1247):
|
||||||
|
Fix search bug that can cause ripgrep to enter an infinite loop.
|
||||||
|
|
||||||
|
|
||||||
|
11.0.0 (2019-04-15)
|
||||||
|
===================
|
||||||
ripgrep 11 is a new major version release of ripgrep that contains many bug
|
ripgrep 11 is a new major version release of ripgrep that contains many bug
|
||||||
fixes, some performance improvements and a few feature enhancements. Notably,
|
fixes, some performance improvements and a few feature enhancements. Notably,
|
||||||
ripgrep's user experience for binary file filtering has been improved. See the
|
ripgrep's user experience for binary file filtering has been improved. See the
|
||||||
@@ -32,9 +380,9 @@ This release increases the **minimum supported Rust version** from 1.28.0 to
|
|||||||
terminal. That is, `rg -uuu foo` should now be equivalent to `grep -r foo`.
|
terminal. That is, `rg -uuu foo` should now be equivalent to `grep -r foo`.
|
||||||
* The `avx-accel` feature of ripgrep has been removed since it is no longer
|
* The `avx-accel` feature of ripgrep has been removed since it is no longer
|
||||||
necessary. All uses of AVX in ripgrep are now enabled automatically via
|
necessary. All uses of AVX in ripgrep are now enabled automatically via
|
||||||
runtime CPU feature detection. The `simd-accel` feature does remain
|
runtime CPU feature detection. The `simd-accel` feature does remain available
|
||||||
available, however, it does increase compilation times substantially at the
|
(only for enabling SIMD for transcoding), however, it does increase
|
||||||
moment.
|
compilation times substantially at the moment.
|
||||||
|
|
||||||
Performance improvements:
|
Performance improvements:
|
||||||
|
|
||||||
@@ -368,7 +716,7 @@ Bug fixes:
|
|||||||
|
|
||||||
0.8.0 (2018-02-11)
|
0.8.0 (2018-02-11)
|
||||||
==================
|
==================
|
||||||
This is a new minor version releae of ripgrep that satisfies several popular
|
This is a new minor version release of ripgrep that satisfies several popular
|
||||||
feature requests (config files, search compressed files, true colors), fixes
|
feature requests (config files, search compressed files, true colors), fixes
|
||||||
many bugs and improves the quality of life for ripgrep maintainers. This
|
many bugs and improves the quality of life for ripgrep maintainers. This
|
||||||
release also includes greatly improved documentation in the form of a
|
release also includes greatly improved documentation in the form of a
|
||||||
@@ -1066,7 +1414,7 @@ Bug fixes:
|
|||||||
=====
|
=====
|
||||||
Feature enhancements:
|
Feature enhancements:
|
||||||
|
|
||||||
* Added or improved file type filtering for VB, R, F#, Swift, Nim, Javascript,
|
* Added or improved file type filtering for VB, R, F#, Swift, Nim, JavaScript,
|
||||||
TypeScript
|
TypeScript
|
||||||
* [FEATURE #20](https://github.com/BurntSushi/ripgrep/issues/20):
|
* [FEATURE #20](https://github.com/BurntSushi/ripgrep/issues/20):
|
||||||
Adds a --no-filename flag.
|
Adds a --no-filename flag.
|
||||||
|
|||||||
762
Cargo.lock
generated
762
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
59
Cargo.toml
59
Cargo.toml
@@ -1,16 +1,15 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ripgrep"
|
name = "ripgrep"
|
||||||
version = "0.10.0" #:version
|
version = "13.0.0" #:version
|
||||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||||
description = """
|
description = """
|
||||||
ripgrep is a line-oriented search tool that recursively searches your current
|
ripgrep is a line-oriented search tool that recursively searches the current
|
||||||
directory for a regex pattern while respecting your gitignore rules. ripgrep
|
directory for a regex pattern while respecting gitignore rules. ripgrep has
|
||||||
has first class support on Windows, macOS and Linux
|
first class support on Windows, macOS and Linux.
|
||||||
"""
|
"""
|
||||||
documentation = "https://github.com/BurntSushi/ripgrep"
|
documentation = "https://github.com/BurntSushi/ripgrep"
|
||||||
homepage = "https://github.com/BurntSushi/ripgrep"
|
homepage = "https://github.com/BurntSushi/ripgrep"
|
||||||
repository = "https://github.com/BurntSushi/ripgrep"
|
repository = "https://github.com/BurntSushi/ripgrep"
|
||||||
readme = "README.md"
|
|
||||||
keywords = ["regex", "grep", "egrep", "search", "pattern"]
|
keywords = ["regex", "grep", "egrep", "search", "pattern"]
|
||||||
categories = ["command-line-utilities", "text-processing"]
|
categories = ["command-line-utilities", "text-processing"]
|
||||||
license = "Unlicense OR MIT"
|
license = "Unlicense OR MIT"
|
||||||
@@ -18,14 +17,11 @@ exclude = ["HomebrewFormula"]
|
|||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
autotests = false
|
autotests = false
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
rust-version = "1.65"
|
||||||
[badges]
|
|
||||||
travis-ci = { repository = "BurntSushi/ripgrep" }
|
|
||||||
appveyor = { repository = "BurntSushi/ripgrep" }
|
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
bench = false
|
bench = false
|
||||||
path = "src/main.rs"
|
path = "crates/core/main.rs"
|
||||||
name = "rg"
|
name = "rg"
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
@@ -34,44 +30,47 @@ path = "tests/tests.rs"
|
|||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"globset",
|
"crates/globset",
|
||||||
"grep",
|
"crates/grep",
|
||||||
"grep-cli",
|
"crates/cli",
|
||||||
"grep-matcher",
|
"crates/matcher",
|
||||||
"grep-pcre2",
|
"crates/pcre2",
|
||||||
"grep-printer",
|
"crates/printer",
|
||||||
"grep-regex",
|
"crates/regex",
|
||||||
"grep-searcher",
|
"crates/searcher",
|
||||||
"ignore",
|
"crates/ignore",
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bstr = "0.1.2"
|
bstr = "1.1.0"
|
||||||
grep = { version = "0.2.3", path = "grep" }
|
grep = { version = "0.2.8", path = "crates/grep" }
|
||||||
ignore = { version = "0.4.7", path = "ignore" }
|
ignore = { version = "0.4.19", path = "crates/ignore" }
|
||||||
lazy_static = "1.1.0"
|
lazy_static = "1.1.0"
|
||||||
log = "0.4.5"
|
log = "0.4.5"
|
||||||
num_cpus = "1.8.0"
|
regex = "1.3.5"
|
||||||
regex = "1.0.5"
|
|
||||||
serde_json = "1.0.23"
|
serde_json = "1.0.23"
|
||||||
termcolor = "1.0.3"
|
termcolor = "1.1.0"
|
||||||
|
|
||||||
[dependencies.clap]
|
[dependencies.clap]
|
||||||
version = "2.32.0"
|
version = "2.33.0"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["suggestions"]
|
features = ["suggestions"]
|
||||||
|
|
||||||
|
[target.'cfg(all(target_env = "musl", target_pointer_width = "64"))'.dependencies.jemallocator]
|
||||||
|
version = "0.5.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
lazy_static = "1.1.0"
|
lazy_static = "1.1.0"
|
||||||
|
|
||||||
[build-dependencies.clap]
|
[build-dependencies.clap]
|
||||||
version = "2.32.0"
|
version = "2.33.0"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["suggestions"]
|
features = ["suggestions"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde = "1.0.77"
|
serde = "1.0.77"
|
||||||
serde_derive = "1.0.77"
|
serde_derive = "1.0.77"
|
||||||
|
walkdir = "2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
simd-accel = ["grep/simd-accel"]
|
simd-accel = ["grep/simd-accel"]
|
||||||
@@ -92,13 +91,13 @@ assets = [
|
|||||||
["README.md", "usr/share/doc/ripgrep/README", "644"],
|
["README.md", "usr/share/doc/ripgrep/README", "644"],
|
||||||
["FAQ.md", "usr/share/doc/ripgrep/FAQ", "644"],
|
["FAQ.md", "usr/share/doc/ripgrep/FAQ", "644"],
|
||||||
# The man page is automatically generated by ripgrep's build process, so
|
# The man page is automatically generated by ripgrep's build process, so
|
||||||
# this file isn't actually commited. Instead, to create a dpkg, either
|
# this file isn't actually committed. Instead, to create a dpkg, either
|
||||||
# create a deployment/deb directory and copy the man page to it, or use the
|
# create a deployment/deb directory and copy the man page to it, or use the
|
||||||
# 'ci/build_deb.sh' script.
|
# 'ci/build-deb' script.
|
||||||
["deployment/deb/rg.1", "usr/share/man/man1/rg.1", "644"],
|
["deployment/deb/rg.1", "usr/share/man/man1/rg.1", "644"],
|
||||||
# Similarly for shell completions.
|
# Similarly for shell completions.
|
||||||
["deployment/deb/rg.bash", "usr/share/bash-completion/completions/rg", "644"],
|
["deployment/deb/rg.bash", "usr/share/bash-completion/completions/rg", "644"],
|
||||||
["deployment/deb/rg.fish", "usr/share/fish/completions/rg.fish", "644"],
|
["deployment/deb/rg.fish", "usr/share/fish/vendor_completions.d/rg.fish", "644"],
|
||||||
["deployment/deb/_rg", "usr/share/zsh/vendor-completions/", "644"],
|
["deployment/deb/_rg", "usr/share/zsh/vendor-completions/", "644"],
|
||||||
]
|
]
|
||||||
extended-description = """\
|
extended-description = """\
|
||||||
|
|||||||
11
Cross.toml
Normal file
11
Cross.toml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[target.x86_64-unknown-linux-musl]
|
||||||
|
image = "burntsushi/cross:x86_64-unknown-linux-musl"
|
||||||
|
|
||||||
|
[target.i686-unknown-linux-gnu]
|
||||||
|
image = "burntsushi/cross:i686-unknown-linux-gnu"
|
||||||
|
|
||||||
|
[target.mips64-unknown-linux-gnuabi64]
|
||||||
|
image = "burntsushi/cross:mips64-unknown-linux-gnuabi64"
|
||||||
|
|
||||||
|
[target.arm-unknown-linux-gnueabihf]
|
||||||
|
image = "burntsushi/cross:arm-unknown-linux-gnueabihf"
|
||||||
73
FAQ.md
73
FAQ.md
@@ -5,14 +5,15 @@
|
|||||||
* [When is the next release?](#release)
|
* [When is the next release?](#release)
|
||||||
* [Does ripgrep have a man page?](#manpage)
|
* [Does ripgrep have a man page?](#manpage)
|
||||||
* [Does ripgrep have support for shell auto-completion?](#complete)
|
* [Does ripgrep have support for shell auto-completion?](#complete)
|
||||||
* [How do I use lookaround and/or backreferences?](#fancy)
|
|
||||||
* [How do I configure ripgrep's colors?](#colors)
|
|
||||||
* [How do I enable true colors on Windows?](#truecolors-windows)
|
|
||||||
* [How do I stop ripgrep from messing up colors when I kill it?](#stop-ripgrep)
|
|
||||||
* [How can I get results in a consistent order?](#order)
|
* [How can I get results in a consistent order?](#order)
|
||||||
* [How do I search files that aren't UTF-8?](#encoding)
|
* [How do I search files that aren't UTF-8?](#encoding)
|
||||||
* [How do I search compressed files?](#compressed)
|
* [How do I search compressed files?](#compressed)
|
||||||
* [How do I search over multiple lines?](#multiline)
|
* [How do I search over multiple lines?](#multiline)
|
||||||
|
* [How do I use lookaround and/or backreferences?](#fancy)
|
||||||
|
* [How do I configure ripgrep's colors?](#colors)
|
||||||
|
* [How do I enable true colors on Windows?](#truecolors-windows)
|
||||||
|
* [How do I stop ripgrep from messing up colors when I kill it?](#stop-ripgrep)
|
||||||
|
* [Why does using a leading `/` on Windows fail?](#because-cygwin)
|
||||||
* [How do I get around the regex size limit?](#size-limit)
|
* [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 `-f/--file` flag faster?](#dfa-size)
|
||||||
* [How do I make the output look like The Silver Searcher's output?](#silver-searcher-output)
|
* [How do I make the output look like The Silver Searcher's output?](#silver-searcher-output)
|
||||||
@@ -25,6 +26,7 @@
|
|||||||
* [How is ripgrep licensed?](#license)
|
* [How is ripgrep licensed?](#license)
|
||||||
* [Can ripgrep replace grep?](#posix4ever)
|
* [Can ripgrep replace grep?](#posix4ever)
|
||||||
* [What does the "rip" in ripgrep mean?](#intentcountsforsomething)
|
* [What does the "rip" in ripgrep mean?](#intentcountsforsomething)
|
||||||
|
* [How can I donate to ripgrep or its maintainers?](#donations)
|
||||||
|
|
||||||
|
|
||||||
<h3 name="config">
|
<h3 name="config">
|
||||||
@@ -50,18 +52,19 @@ ripgrep is a project whose contributors are volunteers. A release schedule
|
|||||||
adds undue stress to said volunteers. Therefore, releases are made on a best
|
adds undue stress to said volunteers. Therefore, releases are made on a best
|
||||||
effort basis and no dates **will ever be given**.
|
effort basis and no dates **will ever be given**.
|
||||||
|
|
||||||
One exception to this is high impact bugs. If a ripgrep release contains a
|
An exception to this _can be_ high impact bugs. If a ripgrep release contains
|
||||||
significant regression, then there will generally be a strong push to get a
|
a significant regression, then there will generally be a strong push to get a
|
||||||
patch release out with a fix.
|
patch release out with a fix. However, no promises are made.
|
||||||
|
|
||||||
|
|
||||||
<h3 name="manpage">
|
<h3 name="manpage">
|
||||||
Does ripgrep have a man page?
|
Does ripgrep have a man page?
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Yes! Whenever ripgrep is compiled on a system with `asciidoc` present, then a
|
Yes! Whenever ripgrep is compiled on a system with `asciidoctor` or `asciidoc`
|
||||||
man page is generated from ripgrep's argv parser. After compiling ripgrep, you
|
present, then a man page is generated from ripgrep's argv parser. After
|
||||||
can find the man page like so from the root of the repository:
|
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
|
$ find ./target -name rg.1 -print0 | xargs -0 ls -t | head -n1
|
||||||
@@ -137,7 +140,7 @@ How do I search compressed files?
|
|||||||
|
|
||||||
ripgrep's `-z/--search-zip` flag will cause it to search compressed files
|
ripgrep's `-z/--search-zip` flag will cause it to search compressed files
|
||||||
automatically. Currently, this supports gzip, bzip2, xz, lzma, lz4, Brotli and
|
automatically. Currently, this supports gzip, bzip2, xz, lzma, lz4, Brotli and
|
||||||
Zstd. Each of these requires requires the corresponding `gzip`, `bzip2`, `xz`,
|
Zstd. Each of these requires the corresponding `gzip`, `bzip2`, `xz`,
|
||||||
`lz4`, `brotli` and `zstd` binaries to be installed on your system. (That is,
|
`lz4`, `brotli` and `zstd` binaries to be installed on your system. (That is,
|
||||||
ripgrep does decompression by shelling out to another process.)
|
ripgrep does decompression by shelling out to another process.)
|
||||||
|
|
||||||
@@ -205,7 +208,7 @@ The `--color` flag accepts one of the following possible values: `never`,
|
|||||||
ripgrep to only enable colors when it is printing to a terminal. But if you
|
ripgrep to only enable colors when it is printing to a terminal. But if you
|
||||||
pipe ripgrep to a file or some other process, then it will suppress colors.
|
pipe ripgrep to a file or some other process, then it will suppress colors.
|
||||||
|
|
||||||
The --colors` flag is a bit more complicated. The general format is:
|
The `--colors` flag is a bit more complicated. The general format is:
|
||||||
|
|
||||||
```
|
```
|
||||||
--colors '{type}:{attribute}:{value}'
|
--colors '{type}:{attribute}:{value}'
|
||||||
@@ -313,6 +316,26 @@ available
|
|||||||
[here](https://github.com/BurntSushi/ripgrep/issues/281#issuecomment-269093893).
|
[here](https://github.com/BurntSushi/ripgrep/issues/281#issuecomment-269093893).
|
||||||
|
|
||||||
|
|
||||||
|
<h3 name="because-cygwin">
|
||||||
|
Why does using a leading `/` on Windows fail?
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
If you're using cygwin on Windows and try to search for a pattern beginning
|
||||||
|
with a `/`, then it's possible that cygwin is mangling that pattern without
|
||||||
|
your knowledge. For example, if you tried running `rg /foo` in a cygwin shell
|
||||||
|
on Windows, then cygwin might mistakenly perform path translation on `/foo`,
|
||||||
|
which would result in `rg C:/msys64/foo` being searched instead.
|
||||||
|
|
||||||
|
You can fix this in one of three ways:
|
||||||
|
|
||||||
|
1. Stop using cygwin.
|
||||||
|
2. Escape the leading slash with an additional slash. e.g., `rg //foo`.
|
||||||
|
3. Temporarily disable path translation by setting `MSYS_NO_PATHCONV=1`. e.g.,
|
||||||
|
`MSYS_NO_PATHCONV=1 rg /foo`.
|
||||||
|
|
||||||
|
For more details, see https://github.com/BurntSushi/ripgrep/issues/1277
|
||||||
|
|
||||||
|
|
||||||
<h3 name="size-limit">
|
<h3 name="size-limit">
|
||||||
How do I get around the regex size limit?
|
How do I get around the regex size limit?
|
||||||
</h3>
|
</h3>
|
||||||
@@ -822,7 +845,7 @@ rg foo --files-with-matches | xargs sed -i 's/foo/bar/g'
|
|||||||
will replace all instances of 'foo' with 'bar' in the files in which
|
will replace all instances of 'foo' with 'bar' in the files in which
|
||||||
ripgrep finds the foo pattern. The `-i` flag to sed indicates that you are
|
ripgrep finds the foo pattern. The `-i` flag to sed indicates that you are
|
||||||
editing files in place, and `s/foo/bar/g` says that you are performing a
|
editing files in place, and `s/foo/bar/g` says that you are performing a
|
||||||
**s**ubstitution of the pattren `foo` for `bar`, and that you are doing this
|
**s**ubstitution of the pattern `foo` for `bar`, and that you are doing this
|
||||||
substitution **g**lobally (all occurrences of the pattern in each file).
|
substitution **g**lobally (all occurrences of the pattern in each file).
|
||||||
|
|
||||||
Note: the above command assumes that you are using GNU sed. If you are using
|
Note: the above command assumes that you are using GNU sed. If you are using
|
||||||
@@ -869,7 +892,7 @@ The reason why ripgrep is dual licensed this way is two-fold:
|
|||||||
1. I, as ripgrep's author, would like to participate in a small bit of
|
1. I, as ripgrep's author, would like to participate in a small bit of
|
||||||
ideological activism by promoting the Unlicense's goal: to disclaim
|
ideological activism by promoting the Unlicense's goal: to disclaim
|
||||||
copyright monopoly interest.
|
copyright monopoly interest.
|
||||||
2. I, as ripgrep's author, would like as many people to use rigprep as
|
2. I, as ripgrep's author, would like as many people to use ripgrep as
|
||||||
possible. Since the Unlicense is not a proven or well known license, ripgrep
|
possible. Since the Unlicense is not a proven or well known license, ripgrep
|
||||||
is also offered under the MIT license, which is ubiquitous and accepted by
|
is also offered under the MIT license, which is ubiquitous and accepted by
|
||||||
almost everyone.
|
almost everyone.
|
||||||
@@ -934,8 +957,8 @@ Here are some cases where you might *not* want to use ripgrep. The same caveats
|
|||||||
for the previous section apply.
|
for the previous section apply.
|
||||||
|
|
||||||
* Are you writing portable shell scripts intended to work in a variety of
|
* Are you writing portable shell scripts intended to work in a variety of
|
||||||
environments? Great, probably not a good idea to use ripgrep! ripgrep is has
|
environments? Great, probably not a good idea to use ripgrep! ripgrep has
|
||||||
nowhere near the ubquity of grep, so if you do use ripgrep, you might need
|
nowhere near the ubiquity of grep, so if you do use ripgrep, you might need
|
||||||
to futz with the installation process more than you would with grep.
|
to futz with the installation process more than you would with grep.
|
||||||
* Do you care about POSIX compatibility? If so, then you can't use ripgrep
|
* Do you care about POSIX compatibility? If so, then you can't use ripgrep
|
||||||
because it never was, isn't and never will be POSIX compatible.
|
because it never was, isn't and never will be POSIX compatible.
|
||||||
@@ -981,3 +1004,21 @@ grep](#posix4ever),
|
|||||||
ripgrep is neither actually a "grep killer" nor was it ever intended to be. It
|
ripgrep is neither actually a "grep killer" nor was it ever intended to be. It
|
||||||
certainly does eat into some of its use cases, but that's nothing that other
|
certainly does eat into some of its use cases, but that's nothing that other
|
||||||
tools like ack or The Silver Searcher weren't already doing.
|
tools like ack or The Silver Searcher weren't already doing.
|
||||||
|
|
||||||
|
|
||||||
|
<h3 name="donations">
|
||||||
|
How can I donate to ripgrep or its maintainers?
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
As of now, you can't. While I believe the various efforts that are being
|
||||||
|
undertaken to help fund FOSS are extremely important, they aren't a good fit
|
||||||
|
for me. ripgrep is and I hope will remain a project of love that I develop in
|
||||||
|
my free time. As such, involving money---even in the form of donations given
|
||||||
|
without expectations---would severely change that dynamic for me personally.
|
||||||
|
|
||||||
|
Instead, I'd recommend donating to something else that is doing work that you
|
||||||
|
find meaningful. If you would like suggestions, then my favorites are:
|
||||||
|
|
||||||
|
* [The Internet Archive](https://archive.org/donate/)
|
||||||
|
* [Rails Girls](https://railsgirlssummerofcode.org/campaign/)
|
||||||
|
* [Wikipedia](https://wikimediafoundation.org/support/)
|
||||||
|
|||||||
252
GUIDE.md
252
GUIDE.md
@@ -19,6 +19,7 @@ translatable to any command line shell environment.
|
|||||||
* [Configuration file](#configuration-file)
|
* [Configuration file](#configuration-file)
|
||||||
* [File encoding](#file-encoding)
|
* [File encoding](#file-encoding)
|
||||||
* [Binary data](#binary-data)
|
* [Binary data](#binary-data)
|
||||||
|
* [Preprocessor](#preprocessor)
|
||||||
* [Common options](#common-options)
|
* [Common options](#common-options)
|
||||||
|
|
||||||
|
|
||||||
@@ -110,7 +111,7 @@ colors, you'll notice that `faster` will be highlighted instead of just the
|
|||||||
|
|
||||||
It is beyond the scope of this guide to provide a full tutorial on regular
|
It is beyond the scope of this guide to provide a full tutorial on regular
|
||||||
expressions, but ripgrep's specific syntax is documented here:
|
expressions, but ripgrep's specific syntax is documented here:
|
||||||
https://docs.rs/regex/0.2.5/regex/#syntax
|
https://docs.rs/regex/*/regex/#syntax
|
||||||
|
|
||||||
|
|
||||||
### Recursive search
|
### Recursive search
|
||||||
@@ -176,16 +177,21 @@ 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
|
search. By default, when you search a directory, ripgrep will ignore all of
|
||||||
the following:
|
the following:
|
||||||
|
|
||||||
1. Files and directories that match the rules in your `.gitignore` glob
|
1. Files and directories that match glob patterns in these three categories:
|
||||||
pattern.
|
1. gitignore globs (including global and repo-specific globs).
|
||||||
|
2. `.ignore` globs, which take precedence over all gitignore globs
|
||||||
|
when there's a conflict.
|
||||||
|
3. `.rgignore` globs, which take precedence over all `.ignore` globs
|
||||||
|
when there's a conflict.
|
||||||
2. Hidden files and directories.
|
2. Hidden files and directories.
|
||||||
3. Binary files. (ripgrep considers any file with a `NUL` byte to be binary.)
|
3. Binary files. (ripgrep considers any file with a `NUL` byte to be binary.)
|
||||||
4. Symbolic links aren't followed.
|
4. Symbolic links aren't followed.
|
||||||
|
|
||||||
All of these things can be toggled using various flags provided by ripgrep:
|
All of these things can be toggled using various flags provided by ripgrep:
|
||||||
|
|
||||||
1. You can disable `.gitignore` handling with the `--no-ignore` flag.
|
1. You can disable all ignore-related filtering with the `--no-ignore` flag.
|
||||||
2. Hidden files and directories can be searched with the `--hidden` flag.
|
2. Hidden files and directories can be searched with the `--hidden` (`-.` for
|
||||||
|
short) flag.
|
||||||
3. Binary files can be searched via the `--text` (`-a` for short) 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
|
Be careful with this flag! Binary files may emit control characters to your
|
||||||
terminal, which might cause strange behavior.
|
terminal, which might cause strange behavior.
|
||||||
@@ -376,7 +382,7 @@ make: *.mak, *.mk, GNUmakefile, Gnumakefile, Makefile, gnumakefile, makefile
|
|||||||
By default, ripgrep comes with a bunch of pre-defined types. Generally, these
|
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 correspond to well known public formats. But you can define your own
|
||||||
types as well. For example, perhaps you frequently search "web" files, which
|
types as well. For example, perhaps you frequently search "web" files, which
|
||||||
consist of Javascript, HTML and CSS:
|
consist of JavaScript, HTML and CSS:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ rg --type-add 'web:*.html' --type-add 'web:*.css' --type-add 'web:*.js' -tweb title
|
$ rg --type-add 'web:*.html' --type-add 'web:*.css' --type-add 'web:*.js' -tweb title
|
||||||
@@ -411,6 +417,21 @@ alias rg="rg --type-add 'web:*.{html,css,js}'"
|
|||||||
or add `--type-add=web:*.{html,css,js}` to your ripgrep configuration file.
|
or add `--type-add=web:*.{html,css,js}` to your ripgrep configuration file.
|
||||||
([Configuration files](#configuration-file) are covered in more detail later.)
|
([Configuration files](#configuration-file) are covered in more detail later.)
|
||||||
|
|
||||||
|
#### The special `all` file type
|
||||||
|
|
||||||
|
A special option supported by the `--type` flag is `all`. `--type all` looks
|
||||||
|
for a match in any of the supported file types listed by `--type-list`,
|
||||||
|
including those added on the command line using `--type-add`. It's equivalent
|
||||||
|
to the command `rg --type agda --type asciidoc --type asm ...`, where `...`
|
||||||
|
stands for a list of `--type` flags for the rest of the types in `--type-list`.
|
||||||
|
|
||||||
|
As an example, let's suppose you have a shell script in your current directory,
|
||||||
|
`my-shell-script`, which includes a shell library, `my-shell-library.bash`.
|
||||||
|
Both `rg --type sh` and `rg --type all` would only search for matches in
|
||||||
|
`my-shell-library.bash`, not `my-shell-script`, because the globs matched
|
||||||
|
by the `sh` file type don't include files without an extension. On the
|
||||||
|
other hand, `rg --type-not all` would search `my-shell-script` but not
|
||||||
|
`my-shell-library.bash`.
|
||||||
|
|
||||||
### Replacements
|
### Replacements
|
||||||
|
|
||||||
@@ -628,9 +649,9 @@ given, which is the default:
|
|||||||
they correspond to a UTF-16 BOM, then ripgrep will transcode the contents of
|
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
|
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
|
version of the file. (This incurs a performance penalty since transcoding
|
||||||
is slower than regex searching.) If the file contains invalid UTF-16, then
|
is needed in addition to regex searching.) If the file contains invalid
|
||||||
the Unicode replacement codepoint is substituted in place of invalid code
|
UTF-16, then the Unicode replacement codepoint is substituted in place of
|
||||||
units.
|
invalid code units.
|
||||||
* To handle other cases, ripgrep provides a `-E/--encoding` flag, which permits
|
* To handle other cases, ripgrep provides a `-E/--encoding` flag, which permits
|
||||||
you to specify an encoding from the
|
you to specify an encoding from the
|
||||||
[Encoding Standard](https://encoding.spec.whatwg.org/#concept-encoding-get).
|
[Encoding Standard](https://encoding.spec.whatwg.org/#concept-encoding-get).
|
||||||
@@ -716,8 +737,8 @@ binary files:
|
|||||||
**only applies to files searched by ripgrep as a result of recursive
|
**only applies to files searched by ripgrep as a result of recursive
|
||||||
directory traversal**, which is consistent with ripgrep's other automatic
|
directory traversal**, which is consistent with ripgrep's other automatic
|
||||||
filtering. For example, `rg foo .file` will search `.file` even though it
|
filtering. For example, `rg foo .file` will search `.file` even though it
|
||||||
is hidden. Similarly, `rg foo binary-file` search `binary-file` in "binary"
|
is hidden. Similarly, `rg foo binary-file` will search `binary-file` in
|
||||||
mode automatically.
|
"binary" mode automatically.
|
||||||
2. Binary mode is similar to the default mode, except it will not always
|
2. Binary mode is similar to the default mode, except it will not always
|
||||||
stop searching after it sees a `NUL` byte. Namely, in this mode, ripgrep
|
stop searching after it sees a `NUL` byte. Namely, in this mode, ripgrep
|
||||||
will continue searching a file that is known to be binary until the first
|
will continue searching a file that is known to be binary until the first
|
||||||
@@ -752,6 +773,212 @@ via the `--no-mmap` flag. (The cost will be a small performance regression when
|
|||||||
searching very large files on some platforms.)
|
searching very large files on some platforms.)
|
||||||
|
|
||||||
|
|
||||||
|
### Preprocessor
|
||||||
|
|
||||||
|
In ripgrep, a preprocessor is any type of command that can be run to transform
|
||||||
|
the input of every file before ripgrep searches it. This makes it possible to
|
||||||
|
search virtually any kind of content that can be automatically converted to
|
||||||
|
text without having to teach ripgrep how to read said content.
|
||||||
|
|
||||||
|
One common example is searching PDFs. PDFs are first and foremost meant to be
|
||||||
|
displayed to users. But PDFs often have text streams in them that can be useful
|
||||||
|
to search. In our case, we want to search Bruce Watson's excellent
|
||||||
|
dissertation,
|
||||||
|
[Taxonomies and Toolkits of Regular Language Algorithms](https://burntsushi.net/stuff/1995-watson.pdf).
|
||||||
|
After downloading it, let's try searching it:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ rg 'The Commentz-Walter algorithm' 1995-watson.pdf
|
||||||
|
$
|
||||||
|
```
|
||||||
|
|
||||||
|
Surely, a dissertation on regular language algorithms would mention
|
||||||
|
Commentz-Walter. Indeed it does, but our search isn't picking it up because
|
||||||
|
PDFs are a binary format, and the text shown in the PDF may not be encoded as
|
||||||
|
simple contiguous UTF-8. Namely, even passing the `-a/--text` flag to ripgrep
|
||||||
|
will not make our search work.
|
||||||
|
|
||||||
|
One way to fix this is to convert the PDF to plain text first. This won't work
|
||||||
|
well for all PDFs, but does great in a lot of cases. (Note that the tool we
|
||||||
|
use, `pdftotext`, is part of the [poppler](https://poppler.freedesktop.org)
|
||||||
|
PDF rendering library.)
|
||||||
|
|
||||||
|
```
|
||||||
|
$ pdftotext 1995-watson.pdf > 1995-watson.txt
|
||||||
|
$ rg 'The Commentz-Walter algorithm' 1995-watson.txt
|
||||||
|
316:The Commentz-Walter algorithms : : : : : : : : : : : : : : :
|
||||||
|
7165:4.4 The Commentz-Walter algorithms
|
||||||
|
10062:in input string S , we obtain the Boyer-Moore algorithm. The Commentz-Walter algorithm
|
||||||
|
17218:The Commentz-Walter algorithm (and its variants) displayed more interesting behaviour,
|
||||||
|
17249:Aho-Corasick algorithms are used extensively. The Commentz-Walter algorithms are used
|
||||||
|
17297: The Commentz-Walter algorithms (CW). In all versions of the CW algorithms, a common program skeleton is used with di erent shift functions. The CW algorithms are
|
||||||
|
```
|
||||||
|
|
||||||
|
But having to explicitly convert every file can be a pain, especially when you
|
||||||
|
have a directory full of PDF files. Instead, we can use ripgrep's preprocessor
|
||||||
|
feature to search the PDF. ripgrep's `--pre` flag works by taking a single
|
||||||
|
command name and then executing that command for every file that it searches.
|
||||||
|
ripgrep passes the file path as the first and only argument to the command and
|
||||||
|
also sends the contents of the file to stdin. So let's write a simple shell
|
||||||
|
script that wraps `pdftotext` in a way that conforms to this interface:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cat preprocess
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
exec pdftotext - -
|
||||||
|
```
|
||||||
|
|
||||||
|
With `preprocess` in the same directory as `1995-watson.pdf`, we can now use it
|
||||||
|
to search the PDF:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ rg --pre ./preprocess 'The Commentz-Walter algorithm' 1995-watson.pdf
|
||||||
|
316:The Commentz-Walter algorithms : : : : : : : : : : : : : : :
|
||||||
|
7165:4.4 The Commentz-Walter algorithms
|
||||||
|
10062:in input string S , we obtain the Boyer-Moore algorithm. The Commentz-Walter algorithm
|
||||||
|
17218:The Commentz-Walter algorithm (and its variants) displayed more interesting behaviour,
|
||||||
|
17249:Aho-Corasick algorithms are used extensively. The Commentz-Walter algorithms are used
|
||||||
|
17297: The Commentz-Walter algorithms (CW). In all versions of the CW algorithms, a common program skeleton is used with di erent shift functions. The CW algorithms are
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that `preprocess` must be resolvable to a command that ripgrep can read.
|
||||||
|
The simplest way to do this is to put your preprocessor command in a directory
|
||||||
|
that is in your `PATH` (or equivalent), or otherwise use an absolute path.
|
||||||
|
|
||||||
|
As a bonus, this turns out to be quite a bit faster than other specialized PDF
|
||||||
|
grepping tools:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ time rg --pre ./preprocess 'The Commentz-Walter algorithm' 1995-watson.pdf -c
|
||||||
|
6
|
||||||
|
|
||||||
|
real 0.697
|
||||||
|
user 0.684
|
||||||
|
sys 0.007
|
||||||
|
maxmem 16 MB
|
||||||
|
faults 0
|
||||||
|
|
||||||
|
$ time pdfgrep 'The Commentz-Walter algorithm' 1995-watson.pdf -c
|
||||||
|
6
|
||||||
|
|
||||||
|
real 1.336
|
||||||
|
user 1.310
|
||||||
|
sys 0.023
|
||||||
|
maxmem 16 MB
|
||||||
|
faults 0
|
||||||
|
```
|
||||||
|
|
||||||
|
If you wind up needing to search a lot of PDFs, then ripgrep's parallelism can
|
||||||
|
make the speed difference even greater.
|
||||||
|
|
||||||
|
#### A more robust preprocessor
|
||||||
|
|
||||||
|
One of the problems with the aforementioned preprocessor is that it will fail
|
||||||
|
if you try to search a file that isn't a PDF:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ echo foo > not-a-pdf
|
||||||
|
$ rg --pre ./preprocess 'The Commentz-Walter algorithm' not-a-pdf
|
||||||
|
not-a-pdf: preprocessor command failed: '"./preprocess" "not-a-pdf"':
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Syntax Warning: May not be a PDF file (continuing anyway)
|
||||||
|
Syntax Error: Couldn't find trailer dictionary
|
||||||
|
Syntax Error: Couldn't find trailer dictionary
|
||||||
|
Syntax Error: Couldn't read xref table
|
||||||
|
```
|
||||||
|
|
||||||
|
To fix this, we can make our preprocessor script a bit more robust by only
|
||||||
|
running `pdftotext` when we think the input is a non-empty PDF:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cat preprocessor
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
*.pdf)
|
||||||
|
# The -s flag ensures that the file is non-empty.
|
||||||
|
if [ -s "$1" ]; then
|
||||||
|
exec pdftotext - -
|
||||||
|
else
|
||||||
|
exec cat
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
exec cat
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
```
|
||||||
|
|
||||||
|
We can even extend our preprocessor to search other kinds of files. Sometimes
|
||||||
|
we don't always know the file type from the file name, so we can use the `file`
|
||||||
|
utility to "sniff" the type of the file based on its contents:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cat processor
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
*.pdf)
|
||||||
|
# The -s flag ensures that the file is non-empty.
|
||||||
|
if [ -s "$1" ]; then
|
||||||
|
exec pdftotext - -
|
||||||
|
else
|
||||||
|
exec cat
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
case $(file "$1") in
|
||||||
|
*Zstandard*)
|
||||||
|
exec pzstd -cdq
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
exec cat
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Reducing preprocessor overhead
|
||||||
|
|
||||||
|
There is one more problem with the above approach: it requires running a
|
||||||
|
preprocessor for every single file that ripgrep searches. If every file needs
|
||||||
|
a preprocessor, then this is OK. But if most don't, then this can substantially
|
||||||
|
slow down searches because of the overhead of launching new processors. You
|
||||||
|
can avoid this by telling ripgrep to only invoke the preprocessor when the file
|
||||||
|
path matches a glob. For example, consider the performance difference even when
|
||||||
|
searching a repository as small as ripgrep's:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ time rg --pre pre-rg 'fn is_empty' -c
|
||||||
|
crates/globset/src/lib.rs:1
|
||||||
|
crates/matcher/src/lib.rs:2
|
||||||
|
crates/ignore/src/overrides.rs:1
|
||||||
|
crates/ignore/src/gitignore.rs:1
|
||||||
|
crates/ignore/src/types.rs:1
|
||||||
|
|
||||||
|
real 0.138
|
||||||
|
user 0.485
|
||||||
|
sys 0.209
|
||||||
|
maxmem 7 MB
|
||||||
|
faults 0
|
||||||
|
|
||||||
|
$ time rg --pre pre-rg --pre-glob '*.pdf' 'fn is_empty' -c
|
||||||
|
crates/globset/src/lib.rs:1
|
||||||
|
crates/ignore/src/types.rs:1
|
||||||
|
crates/ignore/src/gitignore.rs:1
|
||||||
|
crates/ignore/src/overrides.rs:1
|
||||||
|
crates/matcher/src/lib.rs:2
|
||||||
|
|
||||||
|
real 0.008
|
||||||
|
user 0.010
|
||||||
|
sys 0.002
|
||||||
|
maxmem 7 MB
|
||||||
|
faults 0
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### Common options
|
### Common options
|
||||||
|
|
||||||
ripgrep has a lot of flags. Too many to keep in your head at once. This section
|
ripgrep has a lot of flags. Too many to keep in your head at once. This section
|
||||||
@@ -766,6 +993,8 @@ used options that will likely impact how you use ripgrep on a regular basis.
|
|||||||
* `-S/--smart-case`: This is similar to `--ignore-case`, but disables itself
|
* `-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
|
if the pattern contains any uppercase letters. Usually this flag is put into
|
||||||
alias or a config file.
|
alias or a config file.
|
||||||
|
* `-F/--fixed-strings`: Disable regular expression matching and treat the pattern
|
||||||
|
as a literal string.
|
||||||
* `-w/--word-regexp`: Require that all matches of the pattern be surrounded
|
* `-w/--word-regexp`: Require that all matches of the pattern be surrounded
|
||||||
by word boundaries. That is, given `pattern`, the `--word-regexp` flag will
|
by word boundaries. That is, given `pattern`, the `--word-regexp` flag will
|
||||||
cause ripgrep to behave as if `pattern` were actually `\b(?:pattern)\b`.
|
cause ripgrep to behave as if `pattern` were actually `\b(?:pattern)\b`.
|
||||||
@@ -773,6 +1002,7 @@ used options that will likely impact how you use ripgrep on a regular basis.
|
|||||||
* `--files`: Print the files that ripgrep *would* search, but don't actually
|
* `--files`: Print the files that ripgrep *would* search, but don't actually
|
||||||
search them.
|
search them.
|
||||||
* `-a/--text`: Search binary files as if they were plain text.
|
* `-a/--text`: Search binary files as if they were plain text.
|
||||||
|
* `-U/--multiline`: Permit matches to span multiple lines.
|
||||||
* `-z/--search-zip`: Search compressed files (gzip, bzip2, lzma, xz, lz4,
|
* `-z/--search-zip`: Search compressed files (gzip, bzip2, lzma, xz, lz4,
|
||||||
brotli, zstd). This is disabled by default.
|
brotli, zstd). This is disabled by default.
|
||||||
* `-C/--context`: Show the lines surrounding a match.
|
* `-C/--context`: Show the lines surrounding a match.
|
||||||
|
|||||||
225
README.md
225
README.md
@@ -1,19 +1,18 @@
|
|||||||
ripgrep (rg)
|
ripgrep (rg)
|
||||||
------------
|
------------
|
||||||
ripgrep is a line-oriented search tool that recursively searches your current
|
ripgrep is a line-oriented search tool that recursively searches the current
|
||||||
directory for a regex pattern. By default, ripgrep will respect your .gitignore
|
directory for a regex pattern. By default, ripgrep will respect gitignore rules
|
||||||
and automatically skip hidden files/directories and binary files. ripgrep
|
and automatically skip hidden files/directories and binary files. (To disable
|
||||||
has first class support on Windows, macOS and Linux, with binary downloads
|
all automatic filtering by default, use `rg -uuu`.) ripgrep has first class
|
||||||
available for [every release](https://github.com/BurntSushi/ripgrep/releases).
|
support on Windows, macOS and Linux, with binary downloads available for [every
|
||||||
ripgrep is similar to other popular search tools like The Silver Searcher, ack
|
release](https://github.com/BurntSushi/ripgrep/releases). ripgrep is similar to
|
||||||
and grep.
|
other popular search tools like The Silver Searcher, ack and grep.
|
||||||
|
|
||||||
[](https://travis-ci.org/BurntSushi/ripgrep)
|
[](https://github.com/BurntSushi/ripgrep/actions)
|
||||||
[](https://ci.appveyor.com/project/BurntSushi/ripgrep)
|
|
||||||
[](https://crates.io/crates/ripgrep)
|
[](https://crates.io/crates/ripgrep)
|
||||||
[](https://repology.org/project/ripgrep/badges)
|
[](https://repology.org/project/ripgrep/badges)
|
||||||
|
|
||||||
Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org).
|
Dual-licensed under MIT or the [UNLICENSE](https://unlicense.org).
|
||||||
|
|
||||||
|
|
||||||
### CHANGELOG
|
### CHANGELOG
|
||||||
@@ -29,60 +28,60 @@ Please see the [CHANGELOG](CHANGELOG.md) for a release history.
|
|||||||
* [Configuration files](GUIDE.md#configuration-file)
|
* [Configuration files](GUIDE.md#configuration-file)
|
||||||
* [Shell completions](FAQ.md#complete)
|
* [Shell completions](FAQ.md#complete)
|
||||||
* [Building](#building)
|
* [Building](#building)
|
||||||
|
* [Translations](#translations)
|
||||||
|
|
||||||
|
|
||||||
### Screenshot of search results
|
### Screenshot of search results
|
||||||
|
|
||||||
[](http://burntsushi.net/stuff/ripgrep1.png)
|
[](https://burntsushi.net/stuff/ripgrep1.png)
|
||||||
|
|
||||||
|
|
||||||
### Quick examples comparing tools
|
### Quick examples comparing tools
|
||||||
|
|
||||||
This example searches the entire Linux kernel source tree (after running
|
This example searches the entire
|
||||||
`make defconfig && make -j8`) for `[A-Z]+_SUSPEND`, where all matches must be
|
[Linux kernel source tree](https://github.com/BurntSushi/linux)
|
||||||
words. Timings were collected on a system with an Intel i7-6900K 3.2 GHz, and
|
(after running `make defconfig && make -j8`) for `[A-Z]+_SUSPEND`, where
|
||||||
ripgrep was compiled with SIMD enabled.
|
all matches must be words. Timings were collected on a system with an Intel
|
||||||
|
i7-6900K 3.2 GHz.
|
||||||
|
|
||||||
Please remember that a single benchmark is never enough! See my
|
Please remember that a single benchmark is never enough! See my
|
||||||
[blog post on ripgrep](http://blog.burntsushi.net/ripgrep/)
|
[blog post on ripgrep](https://blog.burntsushi.net/ripgrep/)
|
||||||
for a very detailed comparison with more benchmarks and analysis.
|
for a very detailed comparison with more benchmarks and analysis.
|
||||||
|
|
||||||
| Tool | Command | Line count | Time |
|
| Tool | Command | Line count | Time |
|
||||||
| ---- | ------- | ---------- | ---- |
|
| ---- | ------- | ---------- | ---- |
|
||||||
| ripgrep (Unicode) | `rg -n -w '[A-Z]+_SUSPEND'` | 450 | **0.106s** |
|
| ripgrep (Unicode) | `rg -n -w '[A-Z]+_SUSPEND'` | 452 | **0.136s** |
|
||||||
| [git grep](https://www.kernel.org/pub/software/scm/git/docs/git-grep.html) | `LC_ALL=C git grep -E -n -w '[A-Z]+_SUSPEND'` | 450 | 0.553s |
|
| [git grep](https://www.kernel.org/pub/software/scm/git/docs/git-grep.html) | `git grep -P -n -w '[A-Z]+_SUSPEND'` | 452 | 0.348s |
|
||||||
| [The Silver Searcher](https://github.com/ggreer/the_silver_searcher) | `ag -w '[A-Z]+_SUSPEND'` | 450 | 0.589s |
|
| [ugrep (Unicode)](https://github.com/Genivia/ugrep) | `ugrep -r --ignore-files --no-hidden -I -w '[A-Z]+_SUSPEND'` | 452 | 0.506s |
|
||||||
| [git grep (Unicode)](https://www.kernel.org/pub/software/scm/git/docs/git-grep.html) | `LC_ALL=en_US.UTF-8 git grep -E -n -w '[A-Z]+_SUSPEND'` | 450 | 2.266s |
|
| [The Silver Searcher](https://github.com/ggreer/the_silver_searcher) | `ag -w '[A-Z]+_SUSPEND'` | 452 | 0.654s |
|
||||||
| [sift](https://github.com/svent/sift) | `sift --git -n -w '[A-Z]+_SUSPEND'` | 450 | 3.505s |
|
| [git grep](https://www.kernel.org/pub/software/scm/git/docs/git-grep.html) | `LC_ALL=C git grep -E -n -w '[A-Z]+_SUSPEND'` | 452 | 1.150s |
|
||||||
| [ack](https://github.com/petdance/ack2) | `ack -w '[A-Z]+_SUSPEND'` | 1878 | 6.823s |
|
| [ack](https://github.com/beyondgrep/ack3) | `ack -w '[A-Z]+_SUSPEND'` | 452 | 4.054s |
|
||||||
| [The Platinum Searcher](https://github.com/monochromegane/the_platinum_searcher) | `pt -w -e '[A-Z]+_SUSPEND'` | 450 | 14.208s |
|
| [git grep (Unicode)](https://www.kernel.org/pub/software/scm/git/docs/git-grep.html) | `LC_ALL=en_US.UTF-8 git grep -E -n -w '[A-Z]+_SUSPEND'` | 452 | 4.205s |
|
||||||
|
|
||||||
(Yes, `ack` [has](https://github.com/petdance/ack2/issues/445) a
|
Here's another benchmark on the same corpus as above that disregards gitignore
|
||||||
[bug](https://github.com/petdance/ack2/issues/14).)
|
files and searches with a whitelist instead. The corpus is the same as in the
|
||||||
|
previous benchmark, and the flags passed to each command ensure that they are
|
||||||
Here's another benchmark that disregards gitignore files and searches with a
|
doing equivalent work:
|
||||||
whitelist instead. The corpus is the same as in the previous benchmark, and the
|
|
||||||
flags passed to each command ensure that they are doing equivalent work:
|
|
||||||
|
|
||||||
| Tool | Command | Line count | Time |
|
| Tool | Command | Line count | Time |
|
||||||
| ---- | ------- | ---------- | ---- |
|
| ---- | ------- | ---------- | ---- |
|
||||||
| ripgrep | `rg -L -u -tc -n -w '[A-Z]+_SUSPEND'` | 404 | **0.079s** |
|
| ripgrep | `rg -uuu -tc -n -w '[A-Z]+_SUSPEND'` | 388 | **0.096s** |
|
||||||
| [ucg](https://github.com/gvansickle/ucg) | `ucg --type=cc -w '[A-Z]+_SUSPEND'` | 390 | 0.163s |
|
| [ugrep](https://github.com/Genivia/ugrep) | `ugrep -r -n --include='*.c' --include='*.h' -w '[A-Z]+_SUSPEND'` | 388 | 0.493s |
|
||||||
| [GNU grep](https://www.gnu.org/software/grep/) | `egrep -R -n --include='*.c' --include='*.h' -w '[A-Z]+_SUSPEND'` | 404 | 0.611s |
|
| [GNU grep](https://www.gnu.org/software/grep/) | `egrep -r -n --include='*.c' --include='*.h' -w '[A-Z]+_SUSPEND'` | 388 | 0.806s |
|
||||||
|
|
||||||
(`ucg` [has slightly different behavior in the presence of symbolic links](https://github.com/gvansickle/ucg/issues/106).)
|
And finally, a straight-up comparison between ripgrep, ugrep and GNU grep on a
|
||||||
|
single large file cached in memory
|
||||||
And finally, a straight-up comparison between ripgrep and GNU grep on a single
|
(~13GB, [`OpenSubtitles.raw.en.gz`](http://opus.nlpl.eu/download.php?f=OpenSubtitles/v2018/mono/OpenSubtitles.raw.en.gz)):
|
||||||
large file (~9.3GB,
|
|
||||||
[`OpenSubtitles2016.raw.en.gz`](http://opus.lingfil.uu.se/OpenSubtitles2016/mono/OpenSubtitles2016.raw.en.gz)):
|
|
||||||
|
|
||||||
| Tool | Command | Line count | Time |
|
| Tool | Command | Line count | Time |
|
||||||
| ---- | ------- | ---------- | ---- |
|
| ---- | ------- | ---------- | ---- |
|
||||||
| ripgrep | `rg -w 'Sherlock [A-Z]\w+'` | 5268 | **2.108s** |
|
| ripgrep | `rg -w 'Sherlock [A-Z]\w+'` | 7882 | **2.769s** |
|
||||||
| [GNU grep](https://www.gnu.org/software/grep/) | `LC_ALL=C egrep -w 'Sherlock [A-Z]\w+'` | 5268 | 7.014s |
|
| [ugrep](https://github.com/Genivia/ugrep) | `ugrep -w 'Sherlock [A-Z]\w+'` | 7882 | 6.802s |
|
||||||
|
| [GNU grep](https://www.gnu.org/software/grep/) | `LC_ALL=en_US.UTF-8 egrep -w 'Sherlock [A-Z]\w+'` | 7882 | 9.027s |
|
||||||
|
|
||||||
In the above benchmark, passing the `-n` flag (for showing line numbers)
|
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.
|
increases the times to `3.423s` for ripgrep and `13.031s` for GNU grep. ugrep
|
||||||
|
times are unaffected by the presence or absence of `-n`.
|
||||||
|
|
||||||
|
|
||||||
### Why should I use ripgrep?
|
### Why should I use ripgrep?
|
||||||
@@ -91,16 +90,16 @@ increases the times to `2.640s` for ripgrep and `10.277s` for GNU grep.
|
|||||||
because it contains most of their features and is generally faster. (See
|
because it contains most of their features and is generally faster. (See
|
||||||
[the FAQ](FAQ.md#posix4ever) for more details on whether ripgrep can truly
|
[the FAQ](FAQ.md#posix4ever) for more details on whether ripgrep can truly
|
||||||
replace grep.)
|
replace grep.)
|
||||||
* Like other tools specialized to code search, ripgrep defaults to recursive
|
* Like other tools specialized to code search, ripgrep defaults to
|
||||||
directory search and won't search files ignored by your `.gitignore` files.
|
[recursive search](GUIDE.md#recursive-search) and does [automatic
|
||||||
It also ignores hidden and binary files by default. ripgrep also implements
|
filtering](GUIDE.md#automatic-filtering). Namely, ripgrep won't search files
|
||||||
full support for `.gitignore`, whereas there are many bugs related to that
|
ignored by your `.gitignore`/`.ignore`/`.rgignore` files, it won't search
|
||||||
functionality in other code search tools claiming to provide the same
|
hidden files and it won't search binary files. Automatic filtering can be
|
||||||
functionality.
|
disabled with `rg -uuu`.
|
||||||
* ripgrep can search specific types of files. For example, `rg -tpy foo`
|
* ripgrep can [search specific types of files](GUIDE.md#manual-filtering-file-types).
|
||||||
limits your search to Python files and `rg -Tjs foo` excludes Javascript
|
For example, `rg -tpy foo` limits your search to Python files and `rg -Tjs
|
||||||
files from your search. ripgrep can be taught about new file types with
|
foo` excludes JavaScript files from your search. ripgrep can be taught about
|
||||||
custom matching rules.
|
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
|
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
|
||||||
@@ -108,16 +107,23 @@ increases the times to `2.640s` for ripgrep and `10.277s` for GNU grep.
|
|||||||
* ripgrep has optional support for switching its regex engine to use PCRE2.
|
* ripgrep has optional support for switching its regex engine to use PCRE2.
|
||||||
Among other things, this makes it possible to use look-around and
|
Among other things, this makes it possible to use look-around and
|
||||||
backreferences in your patterns, which are not supported in ripgrep's default
|
backreferences in your patterns, which are not supported in ripgrep's default
|
||||||
regex engine. PCRE2 support is enabled with `-P`.
|
regex engine. PCRE2 support can be enabled with `-P/--pcre2` (use PCRE2
|
||||||
* ripgrep supports searching files in text encodings other than UTF-8, such
|
always) or `--auto-hybrid-regex` (use PCRE2 only if needed). An alternative
|
||||||
as UTF-16, latin-1, GBK, EUC-JP, Shift_JIS and more. (Some support for
|
syntax is provided via the `--engine (default|pcre2|auto-hybrid)` option.
|
||||||
automatically detecting UTF-16 is provided. Other text encodings must be
|
* ripgrep has [rudimentary support for replacements](GUIDE.md#replacements),
|
||||||
specifically specified with the `-E/--encoding` flag.)
|
which permit rewriting output based on what was matched.
|
||||||
* ripgrep supports searching files compressed in a common format (gzip, xz,
|
* ripgrep supports [searching files in text encodings](GUIDE.md#file-encoding)
|
||||||
lzma, bzip2 or lz4) with the `-z/--search-zip` flag.
|
other than UTF-8, such as UTF-16, latin-1, GBK, EUC-JP, Shift_JIS and more.
|
||||||
* ripgrep supports arbitrary input preprocessing filters which could be PDF
|
(Some support for automatically detecting UTF-16 is provided. Other text
|
||||||
text extraction, less supported decompression, decrypting, automatic encoding
|
encodings must be specifically specified with the `-E/--encoding` flag.)
|
||||||
detection and so on.
|
* ripgrep supports searching files compressed in a common format (brotli,
|
||||||
|
bzip2, gzip, lz4, lzma, xz, or zstandard) with the `-z/--search-zip` flag.
|
||||||
|
* ripgrep supports
|
||||||
|
[arbitrary input preprocessing filters](GUIDE.md#preprocessor)
|
||||||
|
which could be PDF text extraction, less supported decompression, decrypting,
|
||||||
|
automatic encoding detection and so on.
|
||||||
|
* ripgrep can be configured via a
|
||||||
|
[configuration file](GUIDE.md#configuration-file).
|
||||||
|
|
||||||
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.
|
bugs and Unicode support.
|
||||||
@@ -148,12 +154,12 @@ or more of the following:
|
|||||||
### Is it really faster than everything else?
|
### Is it really faster than everything else?
|
||||||
|
|
||||||
Generally, yes. A large number of benchmarks with detailed analysis for each is
|
Generally, yes. A large number of benchmarks with detailed analysis for each is
|
||||||
[available on my blog](http://blog.burntsushi.net/ripgrep/).
|
[available on my blog](https://blog.burntsushi.net/ripgrep/).
|
||||||
|
|
||||||
Summarizing, ripgrep is fast because:
|
Summarizing, ripgrep is fast because:
|
||||||
|
|
||||||
* It is built on top of
|
* It is built on top of
|
||||||
[Rust's regex engine](https://github.com/rust-lang-nursery/regex).
|
[Rust's regex engine](https://github.com/rust-lang/regex).
|
||||||
Rust's regex engine uses finite automata, SIMD and aggressive literal
|
Rust's regex engine uses finite automata, SIMD and aggressive literal
|
||||||
optimizations to make searching very fast. (PCRE2 support can be opted into
|
optimizations to make searching very fast. (PCRE2 support can be opted into
|
||||||
with the `-P/--pcre2` flag.)
|
with the `-P/--pcre2` flag.)
|
||||||
@@ -190,32 +196,17 @@ multiline search and opt-in fancy regex support via PCRE2.
|
|||||||
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
|
macOS and Linux.](https://github.com/BurntSushi/ripgrep/releases)** Linux and
|
||||||
platforms not explicitly mentioned below are advised to download one of these
|
Windows binaries are static executables. Users of platforms not explicitly
|
||||||
archives.
|
mentioned below are advised to download one of these archives.
|
||||||
|
|
||||||
Linux binaries are static executables. Windows binaries are available either as
|
If you're a **macOS Homebrew** or a **Linuxbrew** user, then you can install
|
||||||
built with MinGW (GNU) or with Microsoft Visual C++ (MSVC). When possible,
|
ripgrep from homebrew-core:
|
||||||
prefer MSVC over GNU, but you'll need to have the [Microsoft VC++ 2015
|
|
||||||
redistributable](https://www.microsoft.com/en-us/download/details.aspx?id=48145)
|
|
||||||
installed.
|
|
||||||
|
|
||||||
If you're a **macOS Homebrew** or a **Linuxbrew** user,
|
|
||||||
then you can install ripgrep either
|
|
||||||
from homebrew-core, (compiled with rust stable, no SIMD):
|
|
||||||
|
|
||||||
```
|
```
|
||||||
$ brew install ripgrep
|
$ brew install ripgrep
|
||||||
```
|
```
|
||||||
|
|
||||||
or you can install a binary compiled with rust nightly (including SIMD and all
|
|
||||||
optimizations) by utilizing a custom tap:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ brew tap burntsushi/ripgrep https://github.com/BurntSushi/ripgrep.git
|
|
||||||
$ brew install ripgrep-bin
|
|
||||||
```
|
|
||||||
|
|
||||||
If you're a **MacPorts** user, then you can install ripgrep from the
|
If you're a **MacPorts** user, then you can install ripgrep from the
|
||||||
[official ports](https://www.macports.org/ports.php?by=name&substr=ripgrep):
|
[official ports](https://www.macports.org/ports.php?by=name&substr=ripgrep):
|
||||||
|
|
||||||
@@ -231,7 +222,7 @@ $ choco install ripgrep
|
|||||||
```
|
```
|
||||||
|
|
||||||
If you're a **Windows Scoop** user, then you can install ripgrep from the
|
If you're a **Windows Scoop** user, then you can install ripgrep from the
|
||||||
[official bucket](https://github.com/lukesampson/scoop/blob/master/bucket/ripgrep.json):
|
[official bucket](https://github.com/ScoopInstaller/Main/blob/master/bucket/ripgrep.json):
|
||||||
|
|
||||||
```
|
```
|
||||||
$ scoop install ripgrep
|
$ scoop install ripgrep
|
||||||
@@ -257,23 +248,14 @@ repositories.
|
|||||||
$ sudo dnf install ripgrep
|
$ sudo dnf install ripgrep
|
||||||
```
|
```
|
||||||
|
|
||||||
If you're an **openSUSE Leap 15.0** user, you can install ripgrep from the
|
If you're an **openSUSE** user, ripgrep is included in **openSUSE Tumbleweed**
|
||||||
[utilities repo](https://build.opensuse.org/package/show/utilities/ripgrep):
|
and **openSUSE Leap** since 15.1.
|
||||||
|
|
||||||
```
|
|
||||||
$ sudo zypper ar https://download.opensuse.org/repositories/utilities/openSUSE_Leap_15.0/utilities.repo
|
|
||||||
$ sudo zypper install ripgrep
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
If you're an **openSUSE Tumbleweed** user, you can install ripgrep from the
|
|
||||||
[official repo](http://software.opensuse.org/package/ripgrep):
|
|
||||||
|
|
||||||
```
|
```
|
||||||
$ sudo zypper install ripgrep
|
$ sudo zypper install ripgrep
|
||||||
```
|
```
|
||||||
|
|
||||||
If you're a **RHEL/CentOS 7** user, you can install ripgrep from
|
If you're a **RHEL/CentOS 7/8** user, you can install ripgrep from
|
||||||
[copr](https://copr.fedorainfracloud.org/coprs/carlwgeorge/ripgrep/):
|
[copr](https://copr.fedorainfracloud.org/coprs/carlwgeorge/ripgrep/):
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -289,16 +271,23 @@ $ nix-env --install ripgrep
|
|||||||
$ # (Or using the attribute name, which is also ripgrep.)
|
$ # (Or using the attribute name, which is also ripgrep.)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If you're a **Guix** user, you can install ripgrep from the official
|
||||||
|
package collection:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ guix install ripgrep
|
||||||
|
```
|
||||||
|
|
||||||
If you're a **Debian** user (or a user of a Debian derivative like **Ubuntu**),
|
If you're a **Debian** user (or a user of a Debian derivative like **Ubuntu**),
|
||||||
then ripgrep can be installed using a binary `.deb` file provided in each
|
then ripgrep can be installed using a binary `.deb` file provided in each
|
||||||
[ripgrep release](https://github.com/BurntSushi/ripgrep/releases).
|
[ripgrep release](https://github.com/BurntSushi/ripgrep/releases).
|
||||||
|
|
||||||
```
|
```
|
||||||
$ curl -LO https://github.com/BurntSushi/ripgrep/releases/download/0.10.0/ripgrep_0.10.0_amd64.deb
|
$ curl -LO https://github.com/BurntSushi/ripgrep/releases/download/13.0.0/ripgrep_13.0.0_amd64.deb
|
||||||
$ sudo dpkg -i ripgrep_0.10.0_amd64.deb
|
$ sudo dpkg -i ripgrep_13.0.0_amd64.deb
|
||||||
```
|
```
|
||||||
|
|
||||||
If you run Debian Buster (currently Debian testing) or Debian sid, ripgrep is
|
If you run Debian Buster (currently Debian stable) or Debian sid, ripgrep is
|
||||||
[officially maintained by Debian](https://tracker.debian.org/pkg/rust-ripgrep).
|
[officially maintained by Debian](https://tracker.debian.org/pkg/rust-ripgrep).
|
||||||
```
|
```
|
||||||
$ sudo apt-get install ripgrep
|
$ sudo apt-get install ripgrep
|
||||||
@@ -325,19 +314,33 @@ If you're a **FreeBSD** user, then you can install ripgrep from the
|
|||||||
```
|
```
|
||||||
|
|
||||||
If you're an **OpenBSD** user, then you can install ripgrep from the
|
If you're an **OpenBSD** user, then you can install ripgrep from the
|
||||||
[official ports](http://openports.se/textproc/ripgrep):
|
[official ports](https://openports.se/textproc/ripgrep):
|
||||||
|
|
||||||
```
|
```
|
||||||
$ doas pkg_add ripgrep
|
$ doas pkg_add ripgrep
|
||||||
```
|
```
|
||||||
|
|
||||||
If you're a **NetBSD** user, then you can install ripgrep from
|
If you're a **NetBSD** user, then you can install ripgrep from
|
||||||
[pkgsrc](http://pkgsrc.se/textproc/ripgrep):
|
[pkgsrc](https://pkgsrc.se/textproc/ripgrep):
|
||||||
|
|
||||||
```
|
```
|
||||||
# pkgin install ripgrep
|
# pkgin install ripgrep
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If you're a **Haiku x86_64** user, then you can install ripgrep from the
|
||||||
|
[official ports](https://github.com/haikuports/haikuports/tree/master/sys-apps/ripgrep):
|
||||||
|
|
||||||
|
```
|
||||||
|
$ pkgman install ripgrep
|
||||||
|
```
|
||||||
|
|
||||||
|
If you're a **Haiku x86_gcc2** user, then you can install ripgrep from the
|
||||||
|
same port as Haiku x86_64 using the x86 secondary architecture build:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ pkgman install ripgrep_x86
|
||||||
|
```
|
||||||
|
|
||||||
If you're a **Rust programmer**, ripgrep can be installed with `cargo`.
|
If you're a **Rust programmer**, ripgrep can be installed with `cargo`.
|
||||||
|
|
||||||
* Note that the minimum supported version of Rust for ripgrep is **1.34.0**,
|
* Note that the minimum supported version of Rust for ripgrep is **1.34.0**,
|
||||||
@@ -350,15 +353,12 @@ If you're a **Rust programmer**, ripgrep can be installed with `cargo`.
|
|||||||
$ cargo install ripgrep
|
$ cargo install ripgrep
|
||||||
```
|
```
|
||||||
|
|
||||||
ripgrep isn't currently in any other package repositories.
|
|
||||||
[I'd like to change that](https://github.com/BurntSushi/ripgrep/issues/10).
|
|
||||||
|
|
||||||
|
|
||||||
### Building
|
### 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.
|
[Rust installation](https://www.rust-lang.org/) in order to compile it.
|
||||||
ripgrep compiles with Rust 1.34.0 (stable) or newer. In general, ripgrep tracks
|
ripgrep compiles with Rust 1.65.0 (stable) or newer. In general, ripgrep tracks
|
||||||
the latest stable release of the Rust compiler.
|
the latest stable release of the Rust compiler.
|
||||||
|
|
||||||
To build ripgrep:
|
To build ripgrep:
|
||||||
@@ -428,3 +428,20 @@ $ cargo test --all
|
|||||||
```
|
```
|
||||||
|
|
||||||
from the repository root.
|
from the repository root.
|
||||||
|
|
||||||
|
|
||||||
|
### Vulnerability reporting
|
||||||
|
|
||||||
|
For reporting a security vulnerability, please
|
||||||
|
[contact Andrew Gallant](https://blog.burntsushi.net/about/),
|
||||||
|
which has my email address and PGP public key if you wish to send an encrypted
|
||||||
|
message.
|
||||||
|
|
||||||
|
|
||||||
|
### Translations
|
||||||
|
|
||||||
|
The following is a list of known translations of ripgrep's documentation. These
|
||||||
|
are unofficially maintained and may not be up to date.
|
||||||
|
|
||||||
|
* [Chinese](https://github.com/chinanf-boy/ripgrep-zh#%E6%9B%B4%E6%96%B0-)
|
||||||
|
* [Spanish](https://github.com/UltiRequiem/traducciones/tree/master/ripgrep)
|
||||||
|
|||||||
56
RELEASE-CHECKLIST.md
Normal file
56
RELEASE-CHECKLIST.md
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
Release Checklist
|
||||||
|
-----------------
|
||||||
|
* Ensure local `master` is up to date with respect to `origin/master`.
|
||||||
|
* Run `cargo update` and review dependency updates. Commit updated
|
||||||
|
`Cargo.lock`.
|
||||||
|
* Run `cargo outdated` and review semver incompatible updates. Unless there is
|
||||||
|
a strong motivation otherwise, review and update every dependency. Also
|
||||||
|
run `--aggressive`, but don't update to crates that are still in beta.
|
||||||
|
* Review changes for every crate in `crates` since the last ripgrep release.
|
||||||
|
If the set of changes is non-empty, issue a new release for that crate. Check
|
||||||
|
crates in the following order. After updating a crate, ensure minimal
|
||||||
|
versions are updated as appropriate in dependents. If an update is required,
|
||||||
|
run `cargo-up --no-push crates/{CRATE}/Cargo.toml`.
|
||||||
|
* crates/globset
|
||||||
|
* crates/ignore
|
||||||
|
* crates/cli
|
||||||
|
* crates/matcher
|
||||||
|
* crates/regex
|
||||||
|
* crates/pcre2
|
||||||
|
* crates/searcher
|
||||||
|
* crates/printer
|
||||||
|
* crates/grep (bump minimal versions as necessary)
|
||||||
|
* crates/core (do **not** bump version, but update dependencies as needed)
|
||||||
|
* Update the CHANGELOG as appropriate.
|
||||||
|
* Edit the `Cargo.toml` to set the new ripgrep version. Run
|
||||||
|
`cargo update -p ripgrep` so that the `Cargo.lock` is updated. Commit the
|
||||||
|
changes and create a new signed tag. Alternatively, use
|
||||||
|
`cargo-up --no-push --no-release Cargo.toml {VERSION}` to automate this.
|
||||||
|
* Push changes to GitHub, NOT including the tag. (But do not publish new
|
||||||
|
version of ripgrep to crates.io yet.)
|
||||||
|
* Once CI for `master` finishes successfully, push the version tag. (Trying to
|
||||||
|
do this in one step seems to result in GitHub Actions not seeing the tag
|
||||||
|
push and thus not running the release workflow.)
|
||||||
|
* Wait for CI to finish creating the release. If the release build fails, then
|
||||||
|
delete the tag from GitHub, make fixes, re-tag, delete the release and push.
|
||||||
|
* Copy the relevant section of the CHANGELOG to the tagged release notes.
|
||||||
|
Include this blurb describing what ripgrep is:
|
||||||
|
> In case you haven't heard of it before, ripgrep is a line-oriented search
|
||||||
|
> tool that recursively searches the current directory for a regex pattern.
|
||||||
|
> By default, ripgrep will respect gitignore rules and automatically skip
|
||||||
|
> hidden files/directories and binary files.
|
||||||
|
* Run `ci/build-deb` locally and manually upload the deb package to the
|
||||||
|
release.
|
||||||
|
* Run `cargo publish`.
|
||||||
|
* Run `ci/sha256-releases {VERSION} >> pkg/brew/ripgrep-bin.rb`. Then edit
|
||||||
|
`pkg/brew/ripgrep-bin.rb` to update the version number and sha256 hashes.
|
||||||
|
Remove extraneous stuff added by `ci/sha256-releases`. Commit changes.
|
||||||
|
* Add TBD section to the top of the CHANGELOG:
|
||||||
|
```
|
||||||
|
TBD
|
||||||
|
===
|
||||||
|
Unreleased changes. Release notes have not yet been written.
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that
|
||||||
|
[`cargo-up` can be found in BurntSushi's dotfiles](https://github.com/BurntSushi/dotfiles/blob/master/bin/cargo-up).
|
||||||
81
appveyor.yml
81
appveyor.yml
@@ -1,81 +0,0 @@
|
|||||||
cache:
|
|
||||||
- c:\cargo\registry
|
|
||||||
- c:\cargo\git
|
|
||||||
|
|
||||||
init:
|
|
||||||
- mkdir c:\cargo
|
|
||||||
- mkdir c:\rustup
|
|
||||||
- SET PATH=c:\cargo\bin;%PATH%
|
|
||||||
|
|
||||||
clone_folder: c:\projects\ripgrep
|
|
||||||
|
|
||||||
environment:
|
|
||||||
CARGO_HOME: "c:\\cargo"
|
|
||||||
RUSTUP_HOME: "c:\\rustup"
|
|
||||||
CARGO_TARGET_DIR: "c:\\projects\\ripgrep\\target"
|
|
||||||
global:
|
|
||||||
PROJECT_NAME: ripgrep
|
|
||||||
RUST_BACKTRACE: full
|
|
||||||
matrix:
|
|
||||||
- TARGET: x86_64-pc-windows-gnu
|
|
||||||
CHANNEL: stable
|
|
||||||
BITS: 64
|
|
||||||
MSYS2: 1
|
|
||||||
- TARGET: x86_64-pc-windows-msvc
|
|
||||||
CHANNEL: stable
|
|
||||||
BITS: 64
|
|
||||||
- TARGET: i686-pc-windows-gnu
|
|
||||||
CHANNEL: stable
|
|
||||||
BITS: 32
|
|
||||||
MSYS2: 1
|
|
||||||
- TARGET: i686-pc-windows-msvc
|
|
||||||
CHANNEL: stable
|
|
||||||
BITS: 32
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
fast_finish: true
|
|
||||||
|
|
||||||
# Install Rust and Cargo
|
|
||||||
# (Based on from https://github.com/rust-lang/libc/blob/master/appveyor.yml)
|
|
||||||
install:
|
|
||||||
- curl -sSf -o rustup-init.exe https://win.rustup.rs/
|
|
||||||
- rustup-init.exe -y --default-host %TARGET%
|
|
||||||
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
|
|
||||||
- if defined MSYS2 set PATH=C:\msys64\mingw%BITS%\bin;%PATH%
|
|
||||||
- rustc -V
|
|
||||||
- cargo -V
|
|
||||||
|
|
||||||
# Hack to work around a harmless warning in Appveyor builds?
|
|
||||||
build: false
|
|
||||||
|
|
||||||
# Equivalent to Travis' `script` phase
|
|
||||||
test_script:
|
|
||||||
- cargo test --verbose --all --features pcre2
|
|
||||||
|
|
||||||
before_deploy:
|
|
||||||
# Generate artifacts for release
|
|
||||||
- cargo build --release --features pcre2
|
|
||||||
- mkdir staging
|
|
||||||
- copy target\release\rg.exe staging
|
|
||||||
- ps: copy target\release\build\ripgrep-*\out\_rg.ps1 staging
|
|
||||||
- cd staging
|
|
||||||
# release zipfile will look like 'ripgrep-1.2.3-x86_64-pc-windows-msvc'
|
|
||||||
- 7z a ../%PROJECT_NAME%-%APPVEYOR_REPO_TAG_NAME%-%TARGET%.zip *
|
|
||||||
- appveyor PushArtifact ../%PROJECT_NAME%-%APPVEYOR_REPO_TAG_NAME%-%TARGET%.zip
|
|
||||||
|
|
||||||
deploy:
|
|
||||||
description: 'Automatically deployed release'
|
|
||||||
# All the zipped artifacts will be deployed
|
|
||||||
artifact: /.*\.zip/
|
|
||||||
auth_token:
|
|
||||||
secure: vv4vBCEosGlyQjaEC1+kraP2P6O4CQSa+Tw50oHWFTGcmuXxaWS0/yEXbxsIRLpw
|
|
||||||
provider: GitHub
|
|
||||||
# deploy when a new tag is pushed and only on the stable channel
|
|
||||||
on:
|
|
||||||
CHANNEL: stable
|
|
||||||
appveyor_repo_tag: true
|
|
||||||
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- /^\d+\.\d+\.\d+$/
|
|
||||||
- master
|
|
||||||
@@ -23,16 +23,16 @@ import time
|
|||||||
# strategies used to increase the relevance of results returned.
|
# strategies used to increase the relevance of results returned.
|
||||||
|
|
||||||
SUBTITLES_DIR = 'subtitles'
|
SUBTITLES_DIR = 'subtitles'
|
||||||
SUBTITLES_EN_NAME = 'OpenSubtitles2016.raw.en'
|
SUBTITLES_EN_NAME = 'en.txt'
|
||||||
SUBTITLES_EN_NAME_SAMPLE = 'OpenSubtitles2016.raw.sample.en'
|
SUBTITLES_EN_NAME_SAMPLE = 'en.sample.txt'
|
||||||
SUBTITLES_EN_NAME_GZ = '%s.gz' % SUBTITLES_EN_NAME
|
SUBTITLES_EN_NAME_GZ = '%s.gz' % SUBTITLES_EN_NAME
|
||||||
SUBTITLES_EN_URL = 'http://opus.lingfil.uu.se/OpenSubtitles2016/mono/OpenSubtitles2016.raw.en.gz' # noqa
|
SUBTITLES_EN_URL = 'https://object.pouta.csc.fi/OPUS-OpenSubtitles/v2016/mono/en.txt.gz' # noqa
|
||||||
SUBTITLES_RU_NAME = 'OpenSubtitles2016.raw.ru'
|
SUBTITLES_RU_NAME = 'ru.txt'
|
||||||
SUBTITLES_RU_NAME_GZ = '%s.gz' % SUBTITLES_RU_NAME
|
SUBTITLES_RU_NAME_GZ = '%s.gz' % SUBTITLES_RU_NAME
|
||||||
SUBTITLES_RU_URL = 'http://opus.lingfil.uu.se/OpenSubtitles2016/mono/OpenSubtitles2016.raw.ru.gz' # noqa
|
SUBTITLES_RU_URL = 'https://object.pouta.csc.fi/OPUS-OpenSubtitles/v2016/mono/ru.txt.gz' # noqa
|
||||||
|
|
||||||
LINUX_DIR = 'linux'
|
LINUX_DIR = 'linux'
|
||||||
LINUX_CLONE = 'git://github.com/BurntSushi/linux'
|
LINUX_CLONE = 'https://github.com/BurntSushi/linux'
|
||||||
|
|
||||||
# Grep takes locale settings from the environment. There is a *substantial*
|
# Grep takes locale settings from the environment. There is a *substantial*
|
||||||
# performance impact for enabling Unicode, so we need to handle this explicitly
|
# performance impact for enabling Unicode, so we need to handle this explicitly
|
||||||
@@ -55,8 +55,10 @@ def bench_linux_literal_default(suite_dir):
|
|||||||
Benchmark the speed of a literal using *default* settings.
|
Benchmark the speed of a literal using *default* settings.
|
||||||
|
|
||||||
This is a purposefully unfair benchmark for use in performance
|
This is a purposefully unfair benchmark for use in performance
|
||||||
analysis, but it is pedagogically useful to demonstrate how
|
analysis, but it is pedagogically useful to demonstrate how default
|
||||||
default behaviors differ.
|
behaviors differ. For example, ugrep and grep don't do any smart
|
||||||
|
filtering by default, so they will invariably search more files
|
||||||
|
than ripgrep, ag or git grep.
|
||||||
'''
|
'''
|
||||||
require(suite_dir, 'linux')
|
require(suite_dir, 'linux')
|
||||||
cwd = path.join(suite_dir, LINUX_DIR)
|
cwd = path.join(suite_dir, LINUX_DIR)
|
||||||
@@ -69,16 +71,11 @@ def bench_linux_literal_default(suite_dir):
|
|||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
mkcmd('rg', ['rg', pat]),
|
mkcmd('rg', ['rg', pat]),
|
||||||
mkcmd('ag', ['ag', pat]),
|
mkcmd('ag', ['ag', pat]),
|
||||||
# ucg reports the exact same matches as ag and rg even though it
|
|
||||||
# doesn't read gitignore files. Instead, it has a file whitelist
|
|
||||||
# that happens to match up exactly with the gitignores for this search.
|
|
||||||
mkcmd('ucg', ['ucg', pat]),
|
|
||||||
# I guess setting LC_ALL=en_US.UTF-8 probably isn't necessarily the
|
# I guess setting LC_ALL=en_US.UTF-8 probably isn't necessarily the
|
||||||
# default, but I'd guess it to be on most desktop systems.
|
# default, but I'd guess it to be on most desktop systems.
|
||||||
mkcmd('pt', ['pt', pat]),
|
mkcmd('git grep', ['git', 'grep', pat], env=GREP_UNICODE),
|
||||||
# sift reports an extra line here for a binary file matched.
|
mkcmd('ugrep', ['ugrep', '-r', pat, './']),
|
||||||
mkcmd('sift', ['sift', pat]),
|
mkcmd('grep', ['grep', '-r', pat, './'], env=GREP_UNICODE),
|
||||||
mkcmd('git grep', ['git', 'grep', pat], env={'LC_ALL': 'en_US.UTF-8'}),
|
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@@ -100,16 +97,16 @@ def bench_linux_literal(suite_dir):
|
|||||||
return Command(*args, **kwargs)
|
return Command(*args, **kwargs)
|
||||||
|
|
||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
mkcmd('rg (ignore)', ['rg', '-n', pat]),
|
mkcmd('rg', ['rg', '-n', pat]),
|
||||||
mkcmd('rg (ignore) (mmap)', ['rg', '-n', '--mmap', pat]),
|
mkcmd('rg (mmap)', ['rg', '-n', '--mmap', pat]),
|
||||||
mkcmd('ag (ignore) (mmap)', ['ag', '-s', pat]),
|
mkcmd('ag (mmap)', ['ag', '-s', pat]),
|
||||||
mkcmd('pt (ignore)', ['pt', pat]),
|
mkcmd('git grep', [
|
||||||
mkcmd('sift (ignore)', SIFT + ['-n', '--git', pat]),
|
|
||||||
mkcmd('git grep (ignore)', [
|
|
||||||
'git', 'grep', '-I', '-n', pat,
|
'git', 'grep', '-I', '-n', pat,
|
||||||
], env={'LC_ALL': 'C'}),
|
], env={'LC_ALL': 'C'}),
|
||||||
mkcmd('rg (whitelist)', ['rg', '-n', '--no-ignore', '-tall', pat]),
|
mkcmd('ugrep', [
|
||||||
mkcmd('ucg (whitelist)', ['ucg', '--nosmart-case', pat]),
|
'ugrep', '-r', '--ignore-files', '--no-hidden', '-I',
|
||||||
|
'-n', pat, './',
|
||||||
|
])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@@ -129,31 +126,26 @@ def bench_linux_literal_casei(suite_dir):
|
|||||||
return Command(*args, **kwargs)
|
return Command(*args, **kwargs)
|
||||||
|
|
||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
mkcmd('rg (ignore)', ['rg', '-n', '-i', pat]),
|
mkcmd('rg', ['rg', '-n', '-i', pat]),
|
||||||
mkcmd('rg (ignore) (mmap)', ['rg', '-n', '-i', '--mmap', pat]),
|
mkcmd('rg (mmap)', ['rg', '-n', '-i', '--mmap', pat]),
|
||||||
mkcmd('ag (ignore) (mmap)', ['ag', '-i', pat]),
|
mkcmd('ag (mmap)', ['ag', '-i', pat]),
|
||||||
mkcmd('pt (ignore)', ['pt', '-i', pat]),
|
|
||||||
mkcmd('sift (ignore)', SIFT + ['-n', '-i', '--git', pat]),
|
|
||||||
# It'd technically be more appropriate to set LC_ALL=en_US.UTF-8 here,
|
# It'd technically be more appropriate to set LC_ALL=en_US.UTF-8 here,
|
||||||
# since that is certainly what ripgrep is doing, but this is for an
|
# since that is certainly what ripgrep is doing, but this is for an
|
||||||
# ASCII literal, so we should give `git grep` all the opportunity to
|
# ASCII literal, so we should give `git grep` all the opportunity to
|
||||||
# do its best.
|
# do its best.
|
||||||
mkcmd('git grep (ignore)', [
|
mkcmd('git grep', [
|
||||||
'git', 'grep', '-I', '-n', '-i', pat,
|
'git', 'grep', '-I', '-n', '-i', pat,
|
||||||
], env={'LC_ALL': 'C'}),
|
], env={'LC_ALL': 'C'}),
|
||||||
mkcmd('rg (whitelist)', [
|
mkcmd('ugrep', [
|
||||||
'rg', '-n', '-i', '--no-ignore', '-tall', pat,
|
'ugrep', '-r', '--ignore-files', '--no-hidden', '-I',
|
||||||
]),
|
'-n', '-i', pat, './',
|
||||||
mkcmd('ucg (whitelist)', ['ucg', '-i', pat]),
|
])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
def bench_linux_re_literal_suffix(suite_dir):
|
def bench_linux_re_literal_suffix(suite_dir):
|
||||||
'''
|
'''
|
||||||
Benchmark the speed of a literal inside a regex.
|
Benchmark the speed of a literal inside a regex.
|
||||||
|
|
||||||
This, for example, inhibits a prefix byte optimization used
|
|
||||||
inside of Go's regex engine (relevant for sift and pt).
|
|
||||||
'''
|
'''
|
||||||
require(suite_dir, 'linux')
|
require(suite_dir, 'linux')
|
||||||
cwd = path.join(suite_dir, LINUX_DIR)
|
cwd = path.join(suite_dir, LINUX_DIR)
|
||||||
@@ -164,26 +156,23 @@ def bench_linux_re_literal_suffix(suite_dir):
|
|||||||
return Command(*args, **kwargs)
|
return Command(*args, **kwargs)
|
||||||
|
|
||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
mkcmd('rg (ignore)', ['rg', '-n', pat]),
|
mkcmd('rg', ['rg', '-n', pat]),
|
||||||
mkcmd('ag (ignore)', ['ag', '-s', pat]),
|
mkcmd('ag', ['ag', '-s', pat]),
|
||||||
mkcmd('pt (ignore)', ['pt', '-e', pat]),
|
|
||||||
mkcmd('sift (ignore)', SIFT + ['-n', '--git', pat]),
|
|
||||||
mkcmd(
|
mkcmd(
|
||||||
'git grep (ignore)',
|
'git grep',
|
||||||
['git', 'grep', '-E', '-I', '-n', pat],
|
['git', 'grep', '-E', '-I', '-n', pat],
|
||||||
env={'LC_ALL': 'C'},
|
env={'LC_ALL': 'C'},
|
||||||
),
|
),
|
||||||
mkcmd('rg (whitelist)', ['rg', '-n', '--no-ignore', '-tall', pat]),
|
mkcmd('ugrep', [
|
||||||
mkcmd('ucg (whitelist)', ['ucg', '--nosmart-case', pat]),
|
'ugrep', '-r', '--ignore-files', '--no-hidden', '-I',
|
||||||
|
'-n', pat, './',
|
||||||
|
])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
def bench_linux_word(suite_dir):
|
def bench_linux_word(suite_dir):
|
||||||
'''
|
'''
|
||||||
Benchmark use of the -w ("match word") flag in each tool.
|
Benchmark use of the -w ("match word") flag in each tool.
|
||||||
|
|
||||||
sift has a lot of trouble with this because it forces it into Go's
|
|
||||||
regex engine by surrounding the pattern with \b assertions.
|
|
||||||
'''
|
'''
|
||||||
require(suite_dir, 'linux')
|
require(suite_dir, 'linux')
|
||||||
cwd = path.join(suite_dir, LINUX_DIR)
|
cwd = path.join(suite_dir, LINUX_DIR)
|
||||||
@@ -194,28 +183,23 @@ def bench_linux_word(suite_dir):
|
|||||||
return Command(*args, **kwargs)
|
return Command(*args, **kwargs)
|
||||||
|
|
||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
mkcmd('rg (ignore)', ['rg', '-n', '-w', pat]),
|
mkcmd('rg', ['rg', '-n', '-w', pat]),
|
||||||
mkcmd('ag (ignore)', ['ag', '-s', '-w', pat]),
|
mkcmd('ag', ['ag', '-s', '-w', pat]),
|
||||||
mkcmd('pt (ignore)', ['pt', '-w', pat]),
|
|
||||||
mkcmd('sift (ignore)', SIFT + ['-n', '-w', '--git', pat]),
|
|
||||||
mkcmd(
|
mkcmd(
|
||||||
'git grep (ignore)',
|
'git grep',
|
||||||
['git', 'grep', '-E', '-I', '-n', '-w', pat],
|
['git', 'grep', '-E', '-I', '-n', '-w', pat],
|
||||||
env={'LC_ALL': 'C'},
|
env={'LC_ALL': 'C'},
|
||||||
),
|
),
|
||||||
mkcmd('rg (whitelist)', [
|
mkcmd('ugrep', [
|
||||||
'rg', '-n', '-w', '--no-ignore', '-tall', pat,
|
'ugrep', '-r', '--ignore-files', '--no-hidden', '-I',
|
||||||
]),
|
'-n', '-w', pat, './',
|
||||||
mkcmd('ucg (whitelist)', ['ucg', '--nosmart-case', '-w', pat]),
|
])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
def bench_linux_unicode_greek(suite_dir):
|
def bench_linux_unicode_greek(suite_dir):
|
||||||
'''
|
'''
|
||||||
Benchmark matching of a Unicode category.
|
Benchmark matching of a Unicode category.
|
||||||
|
|
||||||
Only three tools (ripgrep, sift and pt) support this. We omit
|
|
||||||
pt because it is too slow.
|
|
||||||
'''
|
'''
|
||||||
require(suite_dir, 'linux')
|
require(suite_dir, 'linux')
|
||||||
cwd = path.join(suite_dir, LINUX_DIR)
|
cwd = path.join(suite_dir, LINUX_DIR)
|
||||||
@@ -227,8 +211,10 @@ def bench_linux_unicode_greek(suite_dir):
|
|||||||
|
|
||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
mkcmd('rg', ['rg', '-n', pat]),
|
mkcmd('rg', ['rg', '-n', pat]),
|
||||||
mkcmd('pt', ['pt', '-e', pat]),
|
mkcmd('ugrep', [
|
||||||
mkcmd('sift', SIFT + ['-n', '--git', pat]),
|
'ugrep', '-r', '--ignore-files', '--no-hidden', '-I',
|
||||||
|
'-n', pat, './',
|
||||||
|
])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@@ -248,18 +234,20 @@ def bench_linux_unicode_greek_casei(suite_dir):
|
|||||||
|
|
||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
mkcmd('rg', ['rg', '-n', '-i', pat]),
|
mkcmd('rg', ['rg', '-n', '-i', pat]),
|
||||||
mkcmd('pt', ['pt', '-i', '-e', pat]),
|
mkcmd('ugrep', [
|
||||||
mkcmd('sift', SIFT + ['-n', '-i', '--git', pat]),
|
'ugrep', '-r', '--ignore-files', '--no-hidden', '-I',
|
||||||
|
'-n', '-i', pat, './',
|
||||||
|
])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
def bench_linux_unicode_word(suite_dir):
|
def bench_linux_unicode_word(suite_dir):
|
||||||
'''
|
'''
|
||||||
Benchmark Unicode aware \w character class.
|
Benchmark Unicode aware \\w character class.
|
||||||
|
|
||||||
Only ripgrep and git-grep (with LC_ALL=en_US.UTF-8) actually get
|
Only ripgrep and git-grep (with LC_ALL=en_US.UTF-8) actually get
|
||||||
this right. Everything else uses the standard ASCII interpretation
|
this right. Everything else uses the standard ASCII interpretation
|
||||||
of \w.
|
of \\w.
|
||||||
'''
|
'''
|
||||||
require(suite_dir, 'linux')
|
require(suite_dir, 'linux')
|
||||||
cwd = path.join(suite_dir, LINUX_DIR)
|
cwd = path.join(suite_dir, LINUX_DIR)
|
||||||
@@ -270,26 +258,27 @@ def bench_linux_unicode_word(suite_dir):
|
|||||||
return Command(*args, **kwargs)
|
return Command(*args, **kwargs)
|
||||||
|
|
||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
mkcmd('rg (ignore)', ['rg', '-n', pat]),
|
mkcmd('rg', ['rg', '-n', pat]),
|
||||||
mkcmd('rg (ignore) (ASCII)', ['rg', '-n', '(?-u)' + pat]),
|
mkcmd('rg (ASCII)', ['rg', '-n', '(?-u)' + pat]),
|
||||||
mkcmd('ag (ignore) (ASCII)', ['ag', '-s', pat]),
|
mkcmd('ag (ASCII)', ['ag', '-s', pat]),
|
||||||
mkcmd('pt (ignore) (ASCII)', ['pt', '-e', pat]),
|
|
||||||
mkcmd('sift (ignore) (ASCII)', SIFT + ['-n', '--git', pat]),
|
|
||||||
mkcmd(
|
mkcmd(
|
||||||
'git grep (ignore)',
|
'git grep',
|
||||||
['git', 'grep', '-E', '-I', '-n', pat],
|
['git', 'grep', '-E', '-I', '-n', pat],
|
||||||
env={'LC_ALL': 'en_US.UTF-8'},
|
env={'LC_ALL': 'en_US.UTF-8'},
|
||||||
),
|
),
|
||||||
mkcmd(
|
mkcmd(
|
||||||
'git grep (ignore) (ASCII)',
|
'git grep (ASCII)',
|
||||||
['git', 'grep', '-E', '-I', '-n', pat],
|
['git', 'grep', '-E', '-I', '-n', pat],
|
||||||
env={'LC_ALL': 'C'},
|
env={'LC_ALL': 'C'},
|
||||||
),
|
),
|
||||||
mkcmd('rg (whitelist)', ['rg', '-n', '--no-ignore', '-tall', pat]),
|
mkcmd('ugrep', [
|
||||||
mkcmd('rg (whitelist) (ASCII)', [
|
'ugrep', '-r', '--ignore-files', '--no-hidden', '-I',
|
||||||
'rg', '-n', '--no-ignore', '-tall', '(?-u)' + pat,
|
'-n', pat, './',
|
||||||
|
]),
|
||||||
|
mkcmd('ugrep (ASCII)', [
|
||||||
|
'ugrep', '-r', '--ignore-files', '--no-hidden', '-I',
|
||||||
|
'-n', '-U', pat, './',
|
||||||
]),
|
]),
|
||||||
mkcmd('ucg (ASCII)', ['ucg', '--nosmart-case', pat]),
|
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@@ -311,26 +300,27 @@ def bench_linux_no_literal(suite_dir):
|
|||||||
return Command(*args, **kwargs)
|
return Command(*args, **kwargs)
|
||||||
|
|
||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
mkcmd('rg (ignore)', ['rg', '-n', pat]),
|
mkcmd('rg', ['rg', '-n', pat]),
|
||||||
mkcmd('rg (ignore) (ASCII)', ['rg', '-n', '(?-u)' + pat]),
|
mkcmd('rg (ASCII)', ['rg', '-n', '(?-u)' + pat]),
|
||||||
mkcmd('ag (ignore) (ASCII)', ['ag', '-s', pat]),
|
mkcmd('ag (ASCII)', ['ag', '-s', pat]),
|
||||||
mkcmd('pt (ignore) (ASCII)', ['pt', '-e', pat]),
|
|
||||||
mkcmd('sift (ignore) (ASCII)', SIFT + ['-n', '--git', pat]),
|
|
||||||
mkcmd(
|
mkcmd(
|
||||||
'git grep (ignore)',
|
'git grep',
|
||||||
['git', 'grep', '-E', '-I', '-n', pat],
|
['git', 'grep', '-E', '-I', '-n', pat],
|
||||||
env={'LC_ALL': 'en_US.UTF-8'},
|
env={'LC_ALL': 'en_US.UTF-8'},
|
||||||
),
|
),
|
||||||
mkcmd(
|
mkcmd(
|
||||||
'git grep (ignore) (ASCII)',
|
'git grep (ASCII)',
|
||||||
['git', 'grep', '-E', '-I', '-n', pat],
|
['git', 'grep', '-E', '-I', '-n', pat],
|
||||||
env={'LC_ALL': 'C'},
|
env={'LC_ALL': 'C'},
|
||||||
),
|
),
|
||||||
mkcmd('rg (whitelist)', ['rg', '-n', '--no-ignore', '-tall', pat]),
|
mkcmd('ugrep', [
|
||||||
mkcmd('rg (whitelist) (ASCII)', [
|
'ugrep', '-r', '--ignore-files', '--no-hidden', '-I',
|
||||||
'rg', '-n', '--no-ignore', '-tall', '(?-u)' + pat,
|
'-n', pat, './',
|
||||||
|
]),
|
||||||
|
mkcmd('ugrep (ASCII)', [
|
||||||
|
'ugrep', '-r', '--ignore-files', '--no-hidden', '-I',
|
||||||
|
'-n', '-U', pat, './',
|
||||||
]),
|
]),
|
||||||
mkcmd('ucg (whitelist) (ASCII)', ['ucg', '--nosmart-case', pat]),
|
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@@ -352,15 +342,17 @@ def bench_linux_alternates(suite_dir):
|
|||||||
return Command(*args, **kwargs)
|
return Command(*args, **kwargs)
|
||||||
|
|
||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
mkcmd('rg (ignore)', ['rg', '-n', pat]),
|
mkcmd('rg', ['rg', '-n', pat]),
|
||||||
mkcmd('ag (ignore)', ['ag', '-s', pat]),
|
mkcmd('ag', ['ag', '-s', pat]),
|
||||||
mkcmd(
|
mkcmd(
|
||||||
'git grep (ignore)',
|
'git grep',
|
||||||
['git', 'grep', '-E', '-I', '-n', pat],
|
['git', 'grep', '-E', '-I', '-n', pat],
|
||||||
env={'LC_ALL': 'C'},
|
env={'LC_ALL': 'C'},
|
||||||
),
|
),
|
||||||
mkcmd('rg (whitelist)', ['rg', '--no-ignore', '-n', pat]),
|
mkcmd('ugrep', [
|
||||||
mkcmd('ucg (whitelist)', ['ucg', '--nosmart-case', pat]),
|
'ugrep', '-r', '--ignore-files', '--no-hidden', '-I',
|
||||||
|
'-n', pat, './',
|
||||||
|
])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@@ -375,15 +367,17 @@ def bench_linux_alternates_casei(suite_dir):
|
|||||||
return Command(*args, **kwargs)
|
return Command(*args, **kwargs)
|
||||||
|
|
||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
mkcmd('rg (ignore)', ['rg', '-n', '-i', pat]),
|
mkcmd('rg', ['rg', '-n', '-i', pat]),
|
||||||
mkcmd('ag (ignore)', ['ag', '-i', pat]),
|
mkcmd('ag', ['ag', '-i', pat]),
|
||||||
mkcmd(
|
mkcmd(
|
||||||
'git grep (ignore)',
|
'git grep',
|
||||||
['git', 'grep', '-E', '-I', '-n', '-i', pat],
|
['git', 'grep', '-E', '-I', '-n', '-i', pat],
|
||||||
env={'LC_ALL': 'C'},
|
env={'LC_ALL': 'C'},
|
||||||
),
|
),
|
||||||
mkcmd('rg (whitelist)', ['rg', '--no-ignore', '-n', '-i', pat]),
|
mkcmd('ugrep', [
|
||||||
mkcmd('ucg (whitelist)', ['ucg', '-i', pat]),
|
'ugrep', '-r', '--ignore-files', '--no-hidden', '-I',
|
||||||
|
'-n', '-i', pat, './',
|
||||||
|
])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@@ -398,15 +392,11 @@ def bench_subtitles_en_literal(suite_dir):
|
|||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
Command('rg', ['rg', pat, en]),
|
Command('rg', ['rg', pat, en]),
|
||||||
Command('rg (no mmap)', ['rg', '--no-mmap', pat, en]),
|
Command('rg (no mmap)', ['rg', '--no-mmap', pat, en]),
|
||||||
Command('pt', ['pt', '-N', pat, en]),
|
Command('grep', ['grep', pat, en], env=GREP_ASCII),
|
||||||
Command('sift', ['sift', pat, en]),
|
|
||||||
Command('grep', ['grep', '-a', pat, en], env=GREP_ASCII),
|
|
||||||
Command('rg (lines)', ['rg', '-n', pat, en]),
|
Command('rg (lines)', ['rg', '-n', pat, en]),
|
||||||
Command('ag (lines)', ['ag', '-s', pat, en]),
|
Command('ag (lines)', ['ag', '-s', pat, en]),
|
||||||
Command('ucg (lines)', ['ucg', '--nosmart-case', pat, en]),
|
Command('grep (lines)', ['grep', '-n', pat, en], env=GREP_ASCII),
|
||||||
Command('pt (lines)', ['pt', pat, en]),
|
Command('ugrep (lines)', ['ugrep', '-n', pat, en])
|
||||||
Command('sift (lines)', ['sift', '-n', pat, en]),
|
|
||||||
Command('grep (lines)', ['grep', '-an', pat, en], env=GREP_ASCII),
|
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@@ -420,13 +410,11 @@ def bench_subtitles_en_literal_casei(suite_dir):
|
|||||||
|
|
||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
Command('rg', ['rg', '-i', pat, en]),
|
Command('rg', ['rg', '-i', pat, en]),
|
||||||
Command('grep', ['grep', '-ai', pat, en], env=GREP_UNICODE),
|
Command('grep', ['grep', '-i', pat, en], env=GREP_UNICODE),
|
||||||
Command('grep (ASCII)', [
|
Command('grep (ASCII)', ['grep', '-E', '-i', pat, en], env=GREP_ASCII),
|
||||||
'grep', '-E', '-ai', pat, en,
|
|
||||||
], env=GREP_ASCII),
|
|
||||||
Command('rg (lines)', ['rg', '-n', '-i', pat, en]),
|
Command('rg (lines)', ['rg', '-n', '-i', pat, en]),
|
||||||
Command('ag (lines) (ASCII)', ['ag', '-i', pat, en]),
|
Command('ag (lines) (ASCII)', ['ag', '-i', pat, en]),
|
||||||
Command('ucg (lines) (ASCII)', ['ucg', '-i', pat, en]),
|
Command('ugrep (lines)', ['ugrep', '-n', '-i', pat, en])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@@ -443,12 +431,10 @@ def bench_subtitles_en_literal_word(suite_dir):
|
|||||||
'rg', '-n', r'(?-u:\b)' + pat + r'(?-u:\b)', en,
|
'rg', '-n', r'(?-u:\b)' + pat + r'(?-u:\b)', en,
|
||||||
]),
|
]),
|
||||||
Command('ag (ASCII)', ['ag', '-sw', pat, en]),
|
Command('ag (ASCII)', ['ag', '-sw', pat, en]),
|
||||||
Command('ucg (ASCII)', ['ucg', '--nosmart-case', pat, en]),
|
Command('grep (ASCII)', ['grep', '-nw', pat, en], env=GREP_ASCII),
|
||||||
Command('grep (ASCII)', [
|
Command('ugrep (ASCII)', ['ugrep', '-nw', pat, en]),
|
||||||
'grep', '-anw', pat, en,
|
|
||||||
], env=GREP_ASCII),
|
|
||||||
Command('rg', ['rg', '-nw', pat, en]),
|
Command('rg', ['rg', '-nw', pat, en]),
|
||||||
Command('grep', ['grep', '-anw', pat, en], env=GREP_UNICODE),
|
Command('grep', ['grep', '-nw', pat, en], env=GREP_UNICODE),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@@ -469,14 +455,10 @@ def bench_subtitles_en_alternate(suite_dir):
|
|||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
Command('rg (lines)', ['rg', '-n', pat, en]),
|
Command('rg (lines)', ['rg', '-n', pat, en]),
|
||||||
Command('ag (lines)', ['ag', '-s', pat, en]),
|
Command('ag (lines)', ['ag', '-s', pat, en]),
|
||||||
Command('ucg (lines)', ['ucg', '--nosmart-case', pat, en]),
|
Command('grep (lines)', ['grep', '-E', '-n', pat, en], env=GREP_ASCII),
|
||||||
Command('grep (lines)', [
|
Command('ugrep (lines)', ['ugrep', '-n', pat, en]),
|
||||||
'grep', '-E', '-an', pat, en,
|
|
||||||
], env=GREP_ASCII),
|
|
||||||
Command('rg', ['rg', pat, en]),
|
Command('rg', ['rg', pat, en]),
|
||||||
Command('grep', [
|
Command('grep', ['grep', '-E', pat, en], env=GREP_ASCII),
|
||||||
'grep', '-E', '-a', pat, en,
|
|
||||||
], env=GREP_ASCII),
|
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@@ -496,12 +478,12 @@ def bench_subtitles_en_alternate_casei(suite_dir):
|
|||||||
|
|
||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
Command('ag (ASCII)', ['ag', '-s', '-i', pat, en]),
|
Command('ag (ASCII)', ['ag', '-s', '-i', pat, en]),
|
||||||
Command('ucg (ASCII)', ['ucg', '-i', pat, en]),
|
|
||||||
Command('grep (ASCII)', [
|
Command('grep (ASCII)', [
|
||||||
'grep', '-E', '-ani', pat, en,
|
'grep', '-E', '-ni', pat, en,
|
||||||
], env=GREP_ASCII),
|
], env=GREP_ASCII),
|
||||||
|
Command('ugrep (ASCII)', ['ugrep', '-n', '-i', pat, en]),
|
||||||
Command('rg', ['rg', '-n', '-i', pat, en]),
|
Command('rg', ['rg', '-n', '-i', pat, en]),
|
||||||
Command('grep', ['grep', '-E', '-ani', pat, en], env=GREP_UNICODE),
|
Command('grep', ['grep', '-E', '-ni', pat, en], env=GREP_UNICODE),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@@ -515,13 +497,12 @@ def bench_subtitles_en_surrounding_words(suite_dir):
|
|||||||
|
|
||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
Command('rg', ['rg', '-n', pat, en]),
|
Command('rg', ['rg', '-n', pat, en]),
|
||||||
Command('grep', ['grep', '-E', '-an', pat, en], env=GREP_UNICODE),
|
Command('grep', ['grep', '-E', '-n', pat, en], env=GREP_UNICODE),
|
||||||
|
Command('ugrep', ['ugrep', '-n', pat, en]),
|
||||||
Command('rg (ASCII)', ['rg', '-n', '(?-u)' + pat, en]),
|
Command('rg (ASCII)', ['rg', '-n', '(?-u)' + pat, en]),
|
||||||
Command('ag (ASCII)', ['ag', '-s', pat, en]),
|
Command('ag (ASCII)', ['ag', '-s', pat, en]),
|
||||||
Command('ucg (ASCII)', ['ucg', '--nosmart-case', pat, en]),
|
Command('grep (ASCII)', ['grep', '-E', '-n', pat, en], env=GREP_ASCII),
|
||||||
Command('grep (ASCII)', [
|
Command('ugrep (ASCII)', ['ugrep', '-n', '-U', pat, en])
|
||||||
'grep', '-E', '-an', pat, en,
|
|
||||||
], env=GREP_ASCII),
|
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@@ -540,12 +521,11 @@ def bench_subtitles_en_no_literal(suite_dir):
|
|||||||
|
|
||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
Command('rg', ['rg', '-n', pat, en]),
|
Command('rg', ['rg', '-n', pat, en]),
|
||||||
|
Command('ugrep', ['ugrep', '-n', pat, en]),
|
||||||
Command('rg (ASCII)', ['rg', '-n', '(?-u)' + pat, en]),
|
Command('rg (ASCII)', ['rg', '-n', '(?-u)' + pat, en]),
|
||||||
Command('ag (ASCII)', ['ag', '-s', pat, en]),
|
Command('ag (ASCII)', ['ag', '-s', pat, en]),
|
||||||
Command('ucg (ASCII)', ['ucg', '--nosmart-case', pat, en]),
|
Command('grep (ASCII)', ['grep', '-E', '-n', pat, en], env=GREP_ASCII),
|
||||||
Command('grep (ASCII)', [
|
Command('ugrep (ASCII)', ['ugrep', '-n', '-U', pat, en])
|
||||||
'grep', '-E', '-an', pat, en,
|
|
||||||
], env=GREP_ASCII),
|
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@@ -560,15 +540,15 @@ def bench_subtitles_ru_literal(suite_dir):
|
|||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
Command('rg', ['rg', pat, ru]),
|
Command('rg', ['rg', pat, ru]),
|
||||||
Command('rg (no mmap)', ['rg', '--no-mmap', pat, ru]),
|
Command('rg (no mmap)', ['rg', '--no-mmap', pat, ru]),
|
||||||
Command('pt', ['pt', '-N', pat, ru]),
|
Command('grep', ['grep', pat, ru], env=GREP_ASCII),
|
||||||
Command('sift', ['sift', pat, ru]),
|
|
||||||
Command('grep', ['grep', '-a', pat, ru], env=GREP_ASCII),
|
|
||||||
Command('rg (lines)', ['rg', '-n', pat, ru]),
|
Command('rg (lines)', ['rg', '-n', pat, ru]),
|
||||||
Command('ag (lines)', ['ag', '-s', pat, ru]),
|
Command('ag (lines)', ['ag', '-s', pat, ru]),
|
||||||
Command('ucg (lines)', ['ucg', '--nosmart-case', pat, ru]),
|
Command('grep (lines)', ['grep', '-n', pat, ru], env=GREP_ASCII),
|
||||||
Command('pt (lines)', ['pt', pat, ru]),
|
# ugrep incorrectly identifies this corpus as binary, but it is
|
||||||
Command('sift (lines)', ['sift', '-n', pat, ru]),
|
# entirely valid UTF-8. So we tell ugrep to always treat the corpus
|
||||||
Command('grep (lines)', ['grep', '-an', pat, ru], env=GREP_ASCII),
|
# as text even though this technically gives it an edge over other
|
||||||
|
# tools. (It no longer needs to check for binary data.)
|
||||||
|
Command('ugrep (lines)', ['ugrep', '-a', '-n', pat, ru])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@@ -582,13 +562,12 @@ def bench_subtitles_ru_literal_casei(suite_dir):
|
|||||||
|
|
||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
Command('rg', ['rg', '-i', pat, ru]),
|
Command('rg', ['rg', '-i', pat, ru]),
|
||||||
Command('grep', ['grep', '-ai', pat, ru], env=GREP_UNICODE),
|
Command('grep', ['grep', '-i', pat, ru], env=GREP_UNICODE),
|
||||||
Command('grep (ASCII)', [
|
Command('grep (ASCII)', ['grep', '-E', '-i', pat, ru], env=GREP_ASCII),
|
||||||
'grep', '-E', '-ai', pat, ru,
|
|
||||||
], env=GREP_ASCII),
|
|
||||||
Command('rg (lines)', ['rg', '-n', '-i', pat, ru]),
|
Command('rg (lines)', ['rg', '-n', '-i', pat, ru]),
|
||||||
Command('ag (lines) (ASCII)', ['ag', '-i', pat, ru]),
|
Command('ag (lines) (ASCII)', ['ag', '-i', pat, ru]),
|
||||||
Command('ucg (lines) (ASCII)', ['ucg', '-i', pat, ru]),
|
# See bench_subtitles_ru_literal for why we use '-a' here.
|
||||||
|
Command('ugrep (lines) (ASCII)', ['ugrep', '-a', '-n', '-i', pat, ru])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@@ -602,15 +581,20 @@ def bench_subtitles_ru_literal_word(suite_dir):
|
|||||||
|
|
||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
Command('rg (ASCII)', [
|
Command('rg (ASCII)', [
|
||||||
'rg', '-n', r'(?-u:\b)' + pat + r'(?-u:\b)', ru,
|
# You might think we'd use \b here for word boundaries, but both
|
||||||
|
# GNU grep and ripgrep implement -w with the formulation below.
|
||||||
|
# Since we can't use Unicode in a pattern and disable Unicode word
|
||||||
|
# boundaries, we just hand-jam this ourselves.
|
||||||
|
'rg', '-n', r'(?-u:^|\W)' + pat + r'(?-u:$|\W)', ru,
|
||||||
]),
|
]),
|
||||||
Command('ag (ASCII)', ['ag', '-sw', pat, ru]),
|
Command('ag (ASCII)', ['ag', '-sw', pat, ru]),
|
||||||
Command('ucg (ASCII)', ['ucg', '--nosmart-case', pat, ru]),
|
|
||||||
Command('grep (ASCII)', [
|
Command('grep (ASCII)', [
|
||||||
'grep', '-anw', pat, ru,
|
'grep', '-nw', pat, ru,
|
||||||
], env=GREP_ASCII),
|
], env=GREP_ASCII),
|
||||||
|
# See bench_subtitles_ru_literal for why we use '-a' here.
|
||||||
|
Command('ugrep (ASCII)', ['ugrep', '-anw', pat, ru]),
|
||||||
Command('rg', ['rg', '-nw', pat, ru]),
|
Command('rg', ['rg', '-nw', pat, ru]),
|
||||||
Command('grep', ['grep', '-anw', pat, ru], env=GREP_UNICODE),
|
Command('grep', ['grep', '-nw', pat, ru], env=GREP_UNICODE),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@@ -631,14 +615,11 @@ def bench_subtitles_ru_alternate(suite_dir):
|
|||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
Command('rg (lines)', ['rg', '-n', pat, ru]),
|
Command('rg (lines)', ['rg', '-n', pat, ru]),
|
||||||
Command('ag (lines)', ['ag', '-s', pat, ru]),
|
Command('ag (lines)', ['ag', '-s', pat, ru]),
|
||||||
Command('ucg (lines)', ['ucg', '--nosmart-case', pat, ru]),
|
Command('grep (lines)', ['grep', '-E', '-n', pat, ru], env=GREP_ASCII),
|
||||||
Command('grep (lines)', [
|
# See bench_subtitles_ru_literal for why we use '-a' here.
|
||||||
'grep', '-E', '-an', pat, ru,
|
Command('ugrep (lines)', ['ugrep', '-an', pat, ru]),
|
||||||
], env=GREP_ASCII),
|
|
||||||
Command('rg', ['rg', pat, ru]),
|
Command('rg', ['rg', pat, ru]),
|
||||||
Command('grep', [
|
Command('grep', ['grep', '-E', pat, ru], env=GREP_ASCII),
|
||||||
'grep', '-E', '-a', pat, ru,
|
|
||||||
], env=GREP_ASCII),
|
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@@ -658,12 +639,13 @@ def bench_subtitles_ru_alternate_casei(suite_dir):
|
|||||||
|
|
||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
Command('ag (ASCII)', ['ag', '-s', '-i', pat, ru]),
|
Command('ag (ASCII)', ['ag', '-s', '-i', pat, ru]),
|
||||||
Command('ucg (ASCII)', ['ucg', '-i', pat, ru]),
|
|
||||||
Command('grep (ASCII)', [
|
Command('grep (ASCII)', [
|
||||||
'grep', '-E', '-ani', pat, ru,
|
'grep', '-E', '-ni', pat, ru,
|
||||||
], env=GREP_ASCII),
|
], env=GREP_ASCII),
|
||||||
|
# See bench_subtitles_ru_literal for why we use '-a' here.
|
||||||
|
Command('ugrep (ASCII)', ['ugrep', '-ani', pat, ru]),
|
||||||
Command('rg', ['rg', '-n', '-i', pat, ru]),
|
Command('rg', ['rg', '-n', '-i', pat, ru]),
|
||||||
Command('grep', ['grep', '-E', '-ani', pat, ru], env=GREP_UNICODE),
|
Command('grep', ['grep', '-E', '-ni', pat, ru], env=GREP_UNICODE),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@@ -677,12 +659,12 @@ def bench_subtitles_ru_surrounding_words(suite_dir):
|
|||||||
|
|
||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
Command('rg', ['rg', '-n', pat, ru]),
|
Command('rg', ['rg', '-n', pat, ru]),
|
||||||
Command('grep', ['grep', '-E', '-an', pat, ru], env=GREP_UNICODE),
|
Command('grep', ['grep', '-E', '-n', pat, ru], env=GREP_UNICODE),
|
||||||
|
Command('ugrep', ['ugrep', '-an', pat, ru]),
|
||||||
Command('ag (ASCII)', ['ag', '-s', pat, ru]),
|
Command('ag (ASCII)', ['ag', '-s', pat, ru]),
|
||||||
Command('ucg (ASCII)', ['ucg', '--nosmart-case', pat, ru]),
|
Command('grep (ASCII)', ['grep', '-E', '-n', pat, ru], env=GREP_ASCII),
|
||||||
Command('grep (ASCII)', [
|
# See bench_subtitles_ru_literal for why we use '-a' here.
|
||||||
'grep', '-E', '-an', pat, ru,
|
Command('ugrep (ASCII)', ['ugrep', '-a', '-n', '-U', pat, ru]),
|
||||||
], env=GREP_ASCII),
|
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@@ -701,12 +683,13 @@ def bench_subtitles_ru_no_literal(suite_dir):
|
|||||||
|
|
||||||
return Benchmark(pattern=pat, commands=[
|
return Benchmark(pattern=pat, commands=[
|
||||||
Command('rg', ['rg', '-n', pat, ru]),
|
Command('rg', ['rg', '-n', pat, ru]),
|
||||||
|
# See bench_subtitles_ru_literal for why we use '-a' here.
|
||||||
|
Command('ugrep', ['ugrep', '-an', pat, ru]),
|
||||||
Command('rg (ASCII)', ['rg', '-n', '(?-u)' + pat, ru]),
|
Command('rg (ASCII)', ['rg', '-n', '(?-u)' + pat, ru]),
|
||||||
Command('ag (ASCII)', ['ag', '-s', pat, ru]),
|
Command('ag (ASCII)', ['ag', '-s', pat, ru]),
|
||||||
Command('ucg (ASCII)', ['ucg', '--nosmart-case', pat, ru]),
|
Command('grep (ASCII)', ['grep', '-E', '-n', pat, ru], env=GREP_ASCII),
|
||||||
Command('grep (ASCII)', [
|
# See bench_subtitles_ru_literal for why we use '-a' here.
|
||||||
'grep', '-E', '-an', pat, ru,
|
Command('ugrep (ASCII)', ['ugrep', '-anU', pat, ru])
|
||||||
], env=GREP_ASCII),
|
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@@ -756,7 +739,7 @@ class Benchmark(object):
|
|||||||
def __init__(self, name=None, pattern=None, commands=None,
|
def __init__(self, name=None, pattern=None, commands=None,
|
||||||
warmup_count=1, count=3, line_count=True,
|
warmup_count=1, count=3, line_count=True,
|
||||||
allow_missing_commands=False,
|
allow_missing_commands=False,
|
||||||
disabled_cmds=None):
|
disabled_cmds=None, order=0):
|
||||||
'''
|
'''
|
||||||
Create a single benchmark.
|
Create a single benchmark.
|
||||||
|
|
||||||
@@ -792,6 +775,8 @@ class Benchmark(object):
|
|||||||
will simply skip it.
|
will simply skip it.
|
||||||
:param list(str) disabled_cmds:
|
:param list(str) disabled_cmds:
|
||||||
A list of commands to skip.
|
A list of commands to skip.
|
||||||
|
:param int order:
|
||||||
|
An integer indicating the sequence number of this benchmark.
|
||||||
'''
|
'''
|
||||||
self.name = name
|
self.name = name
|
||||||
self.pattern = pattern
|
self.pattern = pattern
|
||||||
@@ -801,6 +786,7 @@ class Benchmark(object):
|
|||||||
self.line_count = line_count
|
self.line_count = line_count
|
||||||
self.allow_missing_commands = allow_missing_commands
|
self.allow_missing_commands = allow_missing_commands
|
||||||
self.disabled_cmds = set(disabled_cmds or [])
|
self.disabled_cmds = set(disabled_cmds or [])
|
||||||
|
self.order = order
|
||||||
|
|
||||||
def raise_if_missing(self):
|
def raise_if_missing(self):
|
||||||
'''
|
'''
|
||||||
@@ -894,7 +880,7 @@ class Result(object):
|
|||||||
'''
|
'''
|
||||||
Create a new set of results, initially empty.
|
Create a new set of results, initially empty.
|
||||||
|
|
||||||
:param Benchmarl benchmark:
|
:param Benchmark benchmark:
|
||||||
The benchmark that produced these results.
|
The benchmark that produced these results.
|
||||||
'''
|
'''
|
||||||
self.benchmark = benchmark
|
self.benchmark = benchmark
|
||||||
@@ -1088,7 +1074,7 @@ def download_subtitles_en(suite_dir):
|
|||||||
# benchmarks finish in a reasonable time.
|
# benchmarks finish in a reasonable time.
|
||||||
with open(path.join(subtitle_dir, en_path_sample), 'wb+') as f:
|
with open(path.join(subtitle_dir, en_path_sample), 'wb+') as f:
|
||||||
run_cmd(
|
run_cmd(
|
||||||
['head', '-n', '32722372', en_path],
|
['head', '-n', '55000000', en_path],
|
||||||
cwd=subtitle_dir, stdout=f)
|
cwd=subtitle_dir, stdout=f)
|
||||||
|
|
||||||
|
|
||||||
@@ -1163,19 +1149,22 @@ def collect_benchmarks(suite_dir, filter_pat=None,
|
|||||||
requires corpora that are missing, then a log message is
|
requires corpora that are missing, then a log message is
|
||||||
emitted to stderr and it is not yielded.
|
emitted to stderr and it is not yielded.
|
||||||
'''
|
'''
|
||||||
for fun in sorted(globals()):
|
benchmarks = []
|
||||||
if not fun.startswith('bench_'):
|
for global_name in globals():
|
||||||
|
if not global_name.startswith('bench_'):
|
||||||
continue
|
continue
|
||||||
name = re.sub('^bench_', '', fun)
|
name = re.sub('^bench_', '', global_name)
|
||||||
if filter_pat is not None and not re.search(filter_pat, name):
|
if filter_pat is not None and not re.search(filter_pat, name):
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
benchmark = globals()[fun](suite_dir)
|
fun = globals()[global_name]
|
||||||
|
benchmark = fun(suite_dir)
|
||||||
benchmark.name = name
|
benchmark.name = name
|
||||||
benchmark.warmup_count = warmup_iter
|
benchmark.warmup_count = warmup_iter
|
||||||
benchmark.count = bench_iter
|
benchmark.count = bench_iter
|
||||||
benchmark.allow_missing_commands = allow_missing_commands
|
benchmark.allow_missing_commands = allow_missing_commands
|
||||||
benchmark.disabled_cmds = disabled_cmds
|
benchmark.disabled_cmds = disabled_cmds
|
||||||
|
benchmark.order = fun.__code__.co_firstlineno
|
||||||
benchmark.raise_if_missing()
|
benchmark.raise_if_missing()
|
||||||
except MissingDependencies as e:
|
except MissingDependencies as e:
|
||||||
eprint(
|
eprint(
|
||||||
@@ -1190,7 +1179,8 @@ def collect_benchmarks(suite_dir, filter_pat=None,
|
|||||||
'(run with --allow-missing to run incomplete benchmarks)'
|
'(run with --allow-missing to run incomplete benchmarks)'
|
||||||
eprint(fmt % (', '.join(e.missing_names), name))
|
eprint(fmt % (', '.join(e.missing_names), name))
|
||||||
continue
|
continue
|
||||||
yield benchmark
|
benchmarks.append(benchmark)
|
||||||
|
return sorted(benchmarks, key=lambda b: b.order)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
37
benchsuite/runs/2020-10-14-archlinux-frink/README.md
Normal file
37
benchsuite/runs/2020-10-14-archlinux-frink/README.md
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
This directory contains updated benchmarks as of 2020-10-14. They were captured
|
||||||
|
via the benchsuite script at `benchsuite/benchsuite` from the root of this
|
||||||
|
repository. The command that was run:
|
||||||
|
|
||||||
|
$ ./benchsuite \
|
||||||
|
--dir /tmp/benchsuite \
|
||||||
|
--raw runs/2020-10-14-archlinux-frink/raw.csv \
|
||||||
|
--warmup-iter 1 \
|
||||||
|
--bench-iter 5
|
||||||
|
|
||||||
|
The versions of each tool are as follows:
|
||||||
|
|
||||||
|
$ rg --version
|
||||||
|
ripgrep 12.1.1 (rev def993bad1)
|
||||||
|
-SIMD -AVX (compiled)
|
||||||
|
+SIMD +AVX (runtime)
|
||||||
|
|
||||||
|
$ grep -V
|
||||||
|
grep (GNU grep) 3.4
|
||||||
|
|
||||||
|
$ ag -V
|
||||||
|
ag version 2.2.0
|
||||||
|
|
||||||
|
Features:
|
||||||
|
+jit +lzma +zlib
|
||||||
|
|
||||||
|
$ git --version
|
||||||
|
git version 2.28.0
|
||||||
|
|
||||||
|
$ ugrep --version
|
||||||
|
ugrep 3.0.2 x86_64-pc-linux-gnu +avx2 +pcre2_jit +zlib +bzip2 +lzma +lz4
|
||||||
|
License BSD-3-Clause: <https://opensource.org/licenses/BSD-3-Clause>
|
||||||
|
Written by Robert van Engelen and others: <https://github.com/Genivia/ugrep>
|
||||||
|
|
||||||
|
The version of ripgrep used was compiled from source on commit def993bad1:
|
||||||
|
|
||||||
|
$ cargo build --release --features 'pcre2'
|
||||||
671
benchsuite/runs/2020-10-14-archlinux-frink/raw.csv
Normal file
671
benchsuite/runs/2020-10-14-archlinux-frink/raw.csv
Normal file
@@ -0,0 +1,671 @@
|
|||||||
|
benchmark,warmup_iter,iter,name,command,duration,lines,env
|
||||||
|
linux_literal_default,1,5,rg,rg PM_RESUME,0.12675833702087402,19,
|
||||||
|
linux_literal_default,1,5,rg,rg PM_RESUME,0.1196434497833252,19,
|
||||||
|
linux_literal_default,1,5,rg,rg PM_RESUME,0.12096214294433594,19,
|
||||||
|
linux_literal_default,1,5,rg,rg PM_RESUME,0.1257617473602295,19,
|
||||||
|
linux_literal_default,1,5,rg,rg PM_RESUME,0.12903356552124023,19,
|
||||||
|
linux_literal_default,1,5,ag,ag PM_RESUME,0.8575565814971924,19,
|
||||||
|
linux_literal_default,1,5,ag,ag PM_RESUME,0.9113664627075195,19,
|
||||||
|
linux_literal_default,1,5,ag,ag PM_RESUME,0.944256067276001,19,
|
||||||
|
linux_literal_default,1,5,ag,ag PM_RESUME,0.5309450626373291,19,
|
||||||
|
linux_literal_default,1,5,ag,ag PM_RESUME,0.6105470657348633,19,
|
||||||
|
linux_literal_default,1,5,git grep,git grep PM_RESUME,0.49039149284362793,19,LC_ALL=en_US.UTF-8
|
||||||
|
linux_literal_default,1,5,git grep,git grep PM_RESUME,0.48095154762268066,19,LC_ALL=en_US.UTF-8
|
||||||
|
linux_literal_default,1,5,git grep,git grep PM_RESUME,0.48927950859069824,19,LC_ALL=en_US.UTF-8
|
||||||
|
linux_literal_default,1,5,git grep,git grep PM_RESUME,0.47182321548461914,19,LC_ALL=en_US.UTF-8
|
||||||
|
linux_literal_default,1,5,git grep,git grep PM_RESUME,0.46923041343688965,19,LC_ALL=en_US.UTF-8
|
||||||
|
linux_literal_default,1,5,ugrep,ugrep -r PM_RESUME ./,0.13612771034240723,19,
|
||||||
|
linux_literal_default,1,5,ugrep,ugrep -r PM_RESUME ./,0.13677191734313965,19,
|
||||||
|
linux_literal_default,1,5,ugrep,ugrep -r PM_RESUME ./,0.13688087463378906,19,
|
||||||
|
linux_literal_default,1,5,ugrep,ugrep -r PM_RESUME ./,0.13218474388122559,19,
|
||||||
|
linux_literal_default,1,5,ugrep,ugrep -r PM_RESUME ./,0.13851046562194824,19,
|
||||||
|
linux_literal_default,1,5,grep,grep -r PM_RESUME ./,1.1436240673065186,19,LC_ALL=en_US.UTF-8
|
||||||
|
linux_literal_default,1,5,grep,grep -r PM_RESUME ./,1.1436970233917236,19,LC_ALL=en_US.UTF-8
|
||||||
|
linux_literal_default,1,5,grep,grep -r PM_RESUME ./,1.1542651653289795,19,LC_ALL=en_US.UTF-8
|
||||||
|
linux_literal_default,1,5,grep,grep -r PM_RESUME ./,1.14790940284729,19,LC_ALL=en_US.UTF-8
|
||||||
|
linux_literal_default,1,5,grep,grep -r PM_RESUME ./,1.1441664695739746,19,LC_ALL=en_US.UTF-8
|
||||||
|
linux_literal,1,5,rg,rg -n PM_RESUME,0.134232759475708,19,
|
||||||
|
linux_literal,1,5,rg,rg -n PM_RESUME,0.12477993965148926,19,
|
||||||
|
linux_literal,1,5,rg,rg -n PM_RESUME,0.11790871620178223,19,
|
||||||
|
linux_literal,1,5,rg,rg -n PM_RESUME,0.13471150398254395,19,
|
||||||
|
linux_literal,1,5,rg,rg -n PM_RESUME,0.13730239868164062,19,
|
||||||
|
linux_literal,1,5,rg (mmap),rg -n --mmap PM_RESUME,1.2953157424926758,19,
|
||||||
|
linux_literal,1,5,rg (mmap),rg -n --mmap PM_RESUME,1.3263885974884033,19,
|
||||||
|
linux_literal,1,5,rg (mmap),rg -n --mmap PM_RESUME,1.320932388305664,19,
|
||||||
|
linux_literal,1,5,rg (mmap),rg -n --mmap PM_RESUME,1.3446438312530518,19,
|
||||||
|
linux_literal,1,5,rg (mmap),rg -n --mmap PM_RESUME,1.3919141292572021,19,
|
||||||
|
linux_literal,1,5,ag (mmap),ag -s PM_RESUME,0.7901346683502197,19,
|
||||||
|
linux_literal,1,5,ag (mmap),ag -s PM_RESUME,0.9647164344787598,19,
|
||||||
|
linux_literal,1,5,ag (mmap),ag -s PM_RESUME,0.8800022602081299,19,
|
||||||
|
linux_literal,1,5,ag (mmap),ag -s PM_RESUME,0.9307558536529541,19,
|
||||||
|
linux_literal,1,5,ag (mmap),ag -s PM_RESUME,0.8346366882324219,19,
|
||||||
|
linux_literal,1,5,git grep,git grep -I -n PM_RESUME,0.4694955348968506,19,LC_ALL=C
|
||||||
|
linux_literal,1,5,git grep,git grep -I -n PM_RESUME,0.4620368480682373,19,LC_ALL=C
|
||||||
|
linux_literal,1,5,git grep,git grep -I -n PM_RESUME,0.4673285484313965,19,LC_ALL=C
|
||||||
|
linux_literal,1,5,git grep,git grep -I -n PM_RESUME,0.4570960998535156,19,LC_ALL=C
|
||||||
|
linux_literal,1,5,git grep,git grep -I -n PM_RESUME,0.4648761749267578,19,LC_ALL=C
|
||||||
|
linux_literal,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n PM_RESUME ./,0.3233473300933838,19,
|
||||||
|
linux_literal,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n PM_RESUME ./,0.3199331760406494,19,
|
||||||
|
linux_literal,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n PM_RESUME ./,0.29825615882873535,19,
|
||||||
|
linux_literal,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n PM_RESUME ./,0.3003232479095459,19,
|
||||||
|
linux_literal,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n PM_RESUME ./,0.30283141136169434,19,
|
||||||
|
linux_literal_casei,1,5,rg,rg -n -i PM_RESUME,0.1349015235900879,456,
|
||||||
|
linux_literal_casei,1,5,rg,rg -n -i PM_RESUME,0.1277780532836914,456,
|
||||||
|
linux_literal_casei,1,5,rg,rg -n -i PM_RESUME,0.1251516342163086,456,
|
||||||
|
linux_literal_casei,1,5,rg,rg -n -i PM_RESUME,0.12959671020507812,456,
|
||||||
|
linux_literal_casei,1,5,rg,rg -n -i PM_RESUME,0.1374528408050537,456,
|
||||||
|
linux_literal_casei,1,5,rg (mmap),rg -n -i --mmap PM_RESUME,1.3468265533447266,456,
|
||||||
|
linux_literal_casei,1,5,rg (mmap),rg -n -i --mmap PM_RESUME,1.3552894592285156,456,
|
||||||
|
linux_literal_casei,1,5,rg (mmap),rg -n -i --mmap PM_RESUME,1.3028552532196045,456,
|
||||||
|
linux_literal_casei,1,5,rg (mmap),rg -n -i --mmap PM_RESUME,1.336735725402832,456,
|
||||||
|
linux_literal_casei,1,5,rg (mmap),rg -n -i --mmap PM_RESUME,1.338634729385376,456,
|
||||||
|
linux_literal_casei,1,5,ag (mmap),ag -i PM_RESUME,0.5562450885772705,456,
|
||||||
|
linux_literal_casei,1,5,ag (mmap),ag -i PM_RESUME,0.7324790954589844,456,
|
||||||
|
linux_literal_casei,1,5,ag (mmap),ag -i PM_RESUME,0.8382794857025146,456,
|
||||||
|
linux_literal_casei,1,5,ag (mmap),ag -i PM_RESUME,0.5817627906799316,456,
|
||||||
|
linux_literal_casei,1,5,ag (mmap),ag -i PM_RESUME,0.5771033763885498,456,
|
||||||
|
linux_literal_casei,1,5,git grep,git grep -I -n -i PM_RESUME,0.48885059356689453,456,LC_ALL=C
|
||||||
|
linux_literal_casei,1,5,git grep,git grep -I -n -i PM_RESUME,0.4838893413543701,456,LC_ALL=C
|
||||||
|
linux_literal_casei,1,5,git grep,git grep -I -n -i PM_RESUME,0.48733997344970703,456,LC_ALL=C
|
||||||
|
linux_literal_casei,1,5,git grep,git grep -I -n -i PM_RESUME,0.4765594005584717,456,LC_ALL=C
|
||||||
|
linux_literal_casei,1,5,git grep,git grep -I -n -i PM_RESUME,0.47402334213256836,456,LC_ALL=C
|
||||||
|
linux_literal_casei,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i PM_RESUME ./,0.3075406551361084,456,
|
||||||
|
linux_literal_casei,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i PM_RESUME ./,0.2922379970550537,456,
|
||||||
|
linux_literal_casei,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i PM_RESUME ./,0.2901036739349365,456,
|
||||||
|
linux_literal_casei,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i PM_RESUME ./,0.2723674774169922,456,
|
||||||
|
linux_literal_casei,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i PM_RESUME ./,0.2762429714202881,456,
|
||||||
|
linux_re_literal_suffix,1,5,rg,rg -n [A-Z]+_RESUME,0.12853646278381348,1944,
|
||||||
|
linux_re_literal_suffix,1,5,rg,rg -n [A-Z]+_RESUME,0.1190040111541748,1944,
|
||||||
|
linux_re_literal_suffix,1,5,rg,rg -n [A-Z]+_RESUME,0.14054393768310547,1944,
|
||||||
|
linux_re_literal_suffix,1,5,rg,rg -n [A-Z]+_RESUME,0.12263894081115723,1944,
|
||||||
|
linux_re_literal_suffix,1,5,rg,rg -n [A-Z]+_RESUME,0.12101268768310547,1944,
|
||||||
|
linux_re_literal_suffix,1,5,ag,ag -s [A-Z]+_RESUME,0.9220716953277588,1944,
|
||||||
|
linux_re_literal_suffix,1,5,ag,ag -s [A-Z]+_RESUME,1.009810209274292,1944,
|
||||||
|
linux_re_literal_suffix,1,5,ag,ag -s [A-Z]+_RESUME,0.9654982089996338,1944,
|
||||||
|
linux_re_literal_suffix,1,5,ag,ag -s [A-Z]+_RESUME,1.2758586406707764,1944,
|
||||||
|
linux_re_literal_suffix,1,5,ag,ag -s [A-Z]+_RESUME,1.0480666160583496,1944,
|
||||||
|
linux_re_literal_suffix,1,5,git grep,git grep -E -I -n [A-Z]+_RESUME,1.1811027526855469,1944,LC_ALL=C
|
||||||
|
linux_re_literal_suffix,1,5,git grep,git grep -E -I -n [A-Z]+_RESUME,1.1824719905853271,1944,LC_ALL=C
|
||||||
|
linux_re_literal_suffix,1,5,git grep,git grep -E -I -n [A-Z]+_RESUME,1.2052066326141357,1944,LC_ALL=C
|
||||||
|
linux_re_literal_suffix,1,5,git grep,git grep -E -I -n [A-Z]+_RESUME,1.224193811416626,1944,LC_ALL=C
|
||||||
|
linux_re_literal_suffix,1,5,git grep,git grep -E -I -n [A-Z]+_RESUME,1.2896029949188232,1944,LC_ALL=C
|
||||||
|
linux_re_literal_suffix,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n [A-Z]+_RESUME ./,0.5580098628997803,1944,
|
||||||
|
linux_re_literal_suffix,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n [A-Z]+_RESUME ./,0.5409820079803467,1944,
|
||||||
|
linux_re_literal_suffix,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n [A-Z]+_RESUME ./,0.5436761379241943,1944,
|
||||||
|
linux_re_literal_suffix,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n [A-Z]+_RESUME ./,0.5317332744598389,1944,
|
||||||
|
linux_re_literal_suffix,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n [A-Z]+_RESUME ./,0.5662341117858887,1944,
|
||||||
|
linux_word,1,5,rg,rg -n -w PM_RESUME,0.13112211227416992,6,
|
||||||
|
linux_word,1,5,rg,rg -n -w PM_RESUME,0.13633346557617188,6,
|
||||||
|
linux_word,1,5,rg,rg -n -w PM_RESUME,0.1308743953704834,6,
|
||||||
|
linux_word,1,5,rg,rg -n -w PM_RESUME,0.13691973686218262,6,
|
||||||
|
linux_word,1,5,rg,rg -n -w PM_RESUME,0.1369326114654541,6,
|
||||||
|
linux_word,1,5,ag,ag -s -w PM_RESUME,0.5965347290039062,6,
|
||||||
|
linux_word,1,5,ag,ag -s -w PM_RESUME,0.8891518115997314,6,
|
||||||
|
linux_word,1,5,ag,ag -s -w PM_RESUME,0.5207972526550293,6,
|
||||||
|
linux_word,1,5,ag,ag -s -w PM_RESUME,0.5551142692565918,6,
|
||||||
|
linux_word,1,5,ag,ag -s -w PM_RESUME,0.5308854579925537,6,
|
||||||
|
linux_word,1,5,git grep,git grep -E -I -n -w PM_RESUME,0.45984363555908203,6,LC_ALL=C
|
||||||
|
linux_word,1,5,git grep,git grep -E -I -n -w PM_RESUME,0.47351694107055664,6,LC_ALL=C
|
||||||
|
linux_word,1,5,git grep,git grep -E -I -n -w PM_RESUME,0.5011758804321289,6,LC_ALL=C
|
||||||
|
linux_word,1,5,git grep,git grep -E -I -n -w PM_RESUME,0.45740509033203125,6,LC_ALL=C
|
||||||
|
linux_word,1,5,git grep,git grep -E -I -n -w PM_RESUME,0.46122002601623535,6,LC_ALL=C
|
||||||
|
linux_word,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n -w PM_RESUME ./,0.3174629211425781,6,
|
||||||
|
linux_word,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n -w PM_RESUME ./,0.32368993759155273,6,
|
||||||
|
linux_word,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n -w PM_RESUME ./,0.3131399154663086,6,
|
||||||
|
linux_word,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n -w PM_RESUME ./,0.2834908962249756,6,
|
||||||
|
linux_word,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n -w PM_RESUME ./,0.2899782657623291,6,
|
||||||
|
linux_unicode_greek,1,5,rg,rg -n \p{Greek},0.2624638080596924,105,
|
||||||
|
linux_unicode_greek,1,5,rg,rg -n \p{Greek},0.26248669624328613,105,
|
||||||
|
linux_unicode_greek,1,5,rg,rg -n \p{Greek},0.26514244079589844,105,
|
||||||
|
linux_unicode_greek,1,5,rg,rg -n \p{Greek},0.26303768157958984,105,
|
||||||
|
linux_unicode_greek,1,5,rg,rg -n \p{Greek},0.2612752914428711,105,
|
||||||
|
linux_unicode_greek,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n \p{Greek} ./,0.2842683792114258,105,
|
||||||
|
linux_unicode_greek,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n \p{Greek} ./,0.2718374729156494,105,
|
||||||
|
linux_unicode_greek,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n \p{Greek} ./,0.26900339126586914,105,
|
||||||
|
linux_unicode_greek,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n \p{Greek} ./,0.267728328704834,105,
|
||||||
|
linux_unicode_greek,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n \p{Greek} ./,0.27019381523132324,105,
|
||||||
|
linux_unicode_greek_casei,1,5,rg,rg -n -i \p{Greek},0.24460315704345703,225,
|
||||||
|
linux_unicode_greek_casei,1,5,rg,rg -n -i \p{Greek},0.2752077579498291,225,
|
||||||
|
linux_unicode_greek_casei,1,5,rg,rg -n -i \p{Greek},0.25118350982666016,225,
|
||||||
|
linux_unicode_greek_casei,1,5,rg,rg -n -i \p{Greek},0.2610158920288086,225,
|
||||||
|
linux_unicode_greek_casei,1,5,rg,rg -n -i \p{Greek},0.24675774574279785,225,
|
||||||
|
linux_unicode_greek_casei,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i \p{Greek} ./,0.26882410049438477,105,
|
||||||
|
linux_unicode_greek_casei,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i \p{Greek} ./,0.2770118713378906,105,
|
||||||
|
linux_unicode_greek_casei,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i \p{Greek} ./,0.2694118022918701,105,
|
||||||
|
linux_unicode_greek_casei,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i \p{Greek} ./,0.2690916061401367,105,
|
||||||
|
linux_unicode_greek_casei,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i \p{Greek} ./,0.2686276435852051,105,
|
||||||
|
linux_unicode_word,1,5,rg,rg -n \wAh,0.13727664947509766,229,
|
||||||
|
linux_unicode_word,1,5,rg,rg -n \wAh,0.1450798511505127,229,
|
||||||
|
linux_unicode_word,1,5,rg,rg -n \wAh,0.13819336891174316,229,
|
||||||
|
linux_unicode_word,1,5,rg,rg -n \wAh,0.1422877311706543,229,
|
||||||
|
linux_unicode_word,1,5,rg,rg -n \wAh,0.13657712936401367,229,
|
||||||
|
linux_unicode_word,1,5,rg (ASCII),rg -n (?-u)\wAh,0.1487271785736084,216,
|
||||||
|
linux_unicode_word,1,5,rg (ASCII),rg -n (?-u)\wAh,0.1459641456604004,216,
|
||||||
|
linux_unicode_word,1,5,rg (ASCII),rg -n (?-u)\wAh,0.13515281677246094,216,
|
||||||
|
linux_unicode_word,1,5,rg (ASCII),rg -n (?-u)\wAh,0.12724566459655762,216,
|
||||||
|
linux_unicode_word,1,5,rg (ASCII),rg -n (?-u)\wAh,0.13360023498535156,216,
|
||||||
|
linux_unicode_word,1,5,ag (ASCII),ag -s \wAh,1.2160453796386719,216,
|
||||||
|
linux_unicode_word,1,5,ag (ASCII),ag -s \wAh,1.230163335800171,216,
|
||||||
|
linux_unicode_word,1,5,ag (ASCII),ag -s \wAh,1.2649273872375488,216,
|
||||||
|
linux_unicode_word,1,5,ag (ASCII),ag -s \wAh,1.224984884262085,216,
|
||||||
|
linux_unicode_word,1,5,ag (ASCII),ag -s \wAh,1.4559555053710938,216,
|
||||||
|
linux_unicode_word,1,5,git grep,git grep -E -I -n \wAh,8.233768224716187,229,LC_ALL=en_US.UTF-8
|
||||||
|
linux_unicode_word,1,5,git grep,git grep -E -I -n \wAh,8.191053867340088,229,LC_ALL=en_US.UTF-8
|
||||||
|
linux_unicode_word,1,5,git grep,git grep -E -I -n \wAh,8.175920724868774,229,LC_ALL=en_US.UTF-8
|
||||||
|
linux_unicode_word,1,5,git grep,git grep -E -I -n \wAh,8.167959451675415,229,LC_ALL=en_US.UTF-8
|
||||||
|
linux_unicode_word,1,5,git grep,git grep -E -I -n \wAh,8.1710205078125,229,LC_ALL=en_US.UTF-8
|
||||||
|
linux_unicode_word,1,5,git grep (ASCII),git grep -E -I -n \wAh,2.3747494220733643,216,LC_ALL=C
|
||||||
|
linux_unicode_word,1,5,git grep (ASCII),git grep -E -I -n \wAh,2.3170926570892334,216,LC_ALL=C
|
||||||
|
linux_unicode_word,1,5,git grep (ASCII),git grep -E -I -n \wAh,2.3430888652801514,216,LC_ALL=C
|
||||||
|
linux_unicode_word,1,5,git grep (ASCII),git grep -E -I -n \wAh,2.3219168186187744,216,LC_ALL=C
|
||||||
|
linux_unicode_word,1,5,git grep (ASCII),git grep -E -I -n \wAh,2.3155832290649414,216,LC_ALL=C
|
||||||
|
linux_unicode_word,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n \wAh ./,0.2722008228302002,229,
|
||||||
|
linux_unicode_word,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n \wAh ./,0.27547430992126465,229,
|
||||||
|
linux_unicode_word,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n \wAh ./,0.2771613597869873,229,
|
||||||
|
linux_unicode_word,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n \wAh ./,0.27692317962646484,229,
|
||||||
|
linux_unicode_word,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n \wAh ./,0.27749085426330566,229,
|
||||||
|
linux_unicode_word,1,5,ugrep (ASCII),ugrep -r --ignore-files --no-hidden -I -n -U \wAh ./,0.2744929790496826,216,
|
||||||
|
linux_unicode_word,1,5,ugrep (ASCII),ugrep -r --ignore-files --no-hidden -I -n -U \wAh ./,0.2725999355316162,216,
|
||||||
|
linux_unicode_word,1,5,ugrep (ASCII),ugrep -r --ignore-files --no-hidden -I -n -U \wAh ./,0.27443718910217285,216,
|
||||||
|
linux_unicode_word,1,5,ugrep (ASCII),ugrep -r --ignore-files --no-hidden -I -n -U \wAh ./,0.2668039798736572,216,
|
||||||
|
linux_unicode_word,1,5,ugrep (ASCII),ugrep -r --ignore-files --no-hidden -I -n -U \wAh ./,0.27918338775634766,216,
|
||||||
|
linux_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.38802123069763184,611,
|
||||||
|
linux_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.40351152420043945,611,
|
||||||
|
linux_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.40592288970947266,611,
|
||||||
|
linux_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.40622901916503906,611,
|
||||||
|
linux_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.40683722496032715,611,
|
||||||
|
linux_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2553420066833496,610,
|
||||||
|
linux_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2511327266693115,610,
|
||||||
|
linux_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2530384063720703,610,
|
||||||
|
linux_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2420644760131836,610,
|
||||||
|
linux_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2691671848297119,610,
|
||||||
|
linux_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.9446702003479004,971,
|
||||||
|
linux_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.9380638599395752,971,
|
||||||
|
linux_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.9273786544799805,971,
|
||||||
|
linux_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.9271430969238281,971,
|
||||||
|
linux_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.9307007789611816,971,
|
||||||
|
linux_no_literal,1,5,git grep,git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},14.531656265258789,611,LC_ALL=en_US.UTF-8
|
||||||
|
linux_no_literal,1,5,git grep,git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},14.570266008377075,611,LC_ALL=en_US.UTF-8
|
||||||
|
linux_no_literal,1,5,git grep,git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},14.51328158378601,611,LC_ALL=en_US.UTF-8
|
||||||
|
linux_no_literal,1,5,git grep,git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},14.644389629364014,611,LC_ALL=en_US.UTF-8
|
||||||
|
linux_no_literal,1,5,git grep,git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},14.694648027420044,611,LC_ALL=en_US.UTF-8
|
||||||
|
linux_no_literal,1,5,git grep (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},3.164829730987549,610,LC_ALL=C
|
||||||
|
linux_no_literal,1,5,git grep (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},3.2377045154571533,610,LC_ALL=C
|
||||||
|
linux_no_literal,1,5,git grep (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},3.1798932552337646,610,LC_ALL=C
|
||||||
|
linux_no_literal,1,5,git grep (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},3.142343044281006,610,LC_ALL=C
|
||||||
|
linux_no_literal,1,5,git grep (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},3.185952663421631,610,LC_ALL=C
|
||||||
|
linux_no_literal,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} ./,6.241358041763306,973,
|
||||||
|
linux_no_literal,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} ./,6.213250637054443,973,
|
||||||
|
linux_no_literal,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} ./,6.242088079452515,973,
|
||||||
|
linux_no_literal,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} ./,6.126717567443848,973,
|
||||||
|
linux_no_literal,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} ./,6.15744948387146,973,
|
||||||
|
linux_no_literal,1,5,ugrep (ASCII),ugrep -r --ignore-files --no-hidden -I -n -U \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} ./,0.3647449016571045,972,
|
||||||
|
linux_no_literal,1,5,ugrep (ASCII),ugrep -r --ignore-files --no-hidden -I -n -U \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} ./,0.36277341842651367,972,
|
||||||
|
linux_no_literal,1,5,ugrep (ASCII),ugrep -r --ignore-files --no-hidden -I -n -U \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} ./,0.3670034408569336,972,
|
||||||
|
linux_no_literal,1,5,ugrep (ASCII),ugrep -r --ignore-files --no-hidden -I -n -U \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} ./,0.3563535213470459,972,
|
||||||
|
linux_no_literal,1,5,ugrep (ASCII),ugrep -r --ignore-files --no-hidden -I -n -U \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} ./,0.36490702629089355,972,
|
||||||
|
linux_alternates,1,5,rg,rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.14299488067626953,112,
|
||||||
|
linux_alternates,1,5,rg,rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.15548348426818848,112,
|
||||||
|
linux_alternates,1,5,rg,rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.14477276802062988,112,
|
||||||
|
linux_alternates,1,5,rg,rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.12926578521728516,112,
|
||||||
|
linux_alternates,1,5,rg,rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.13896560668945312,112,
|
||||||
|
linux_alternates,1,5,ag,ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.9893472194671631,112,
|
||||||
|
linux_alternates,1,5,ag,ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.016686201095581,112,
|
||||||
|
linux_alternates,1,5,ag,ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.9755496978759766,112,
|
||||||
|
linux_alternates,1,5,ag,ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.9718713760375977,112,
|
||||||
|
linux_alternates,1,5,ag,ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.0030465126037598,112,
|
||||||
|
linux_alternates,1,5,git grep,git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5737886428833008,112,LC_ALL=C
|
||||||
|
linux_alternates,1,5,git grep,git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.562185525894165,112,LC_ALL=C
|
||||||
|
linux_alternates,1,5,git grep,git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5762710571289062,112,LC_ALL=C
|
||||||
|
linux_alternates,1,5,git grep,git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5561251640319824,112,LC_ALL=C
|
||||||
|
linux_alternates,1,5,git grep,git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5849525928497314,112,LC_ALL=C
|
||||||
|
linux_alternates,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT ./,0.3186032772064209,112,
|
||||||
|
linux_alternates,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT ./,0.2896738052368164,112,
|
||||||
|
linux_alternates,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT ./,0.28582000732421875,112,
|
||||||
|
linux_alternates,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT ./,0.2837677001953125,112,
|
||||||
|
linux_alternates,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT ./,0.27143406867980957,112,
|
||||||
|
linux_alternates_casei,1,5,rg,rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.21955585479736328,203,
|
||||||
|
linux_alternates_casei,1,5,rg,rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.22631502151489258,203,
|
||||||
|
linux_alternates_casei,1,5,rg,rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.23458337783813477,203,
|
||||||
|
linux_alternates_casei,1,5,rg,rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.21781086921691895,203,
|
||||||
|
linux_alternates_casei,1,5,rg,rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.231217622756958,203,
|
||||||
|
linux_alternates_casei,1,5,ag,ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.7170076370239258,203,
|
||||||
|
linux_alternates_casei,1,5,ag,ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.7032256126403809,203,
|
||||||
|
linux_alternates_casei,1,5,ag,ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.6868026256561279,203,
|
||||||
|
linux_alternates_casei,1,5,ag,ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.6965539455413818,203,
|
||||||
|
linux_alternates_casei,1,5,ag,ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.6966633796691895,203,
|
||||||
|
linux_alternates_casei,1,5,git grep,git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.9774580001831055,203,LC_ALL=C
|
||||||
|
linux_alternates_casei,1,5,git grep,git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.9654648303985596,203,LC_ALL=C
|
||||||
|
linux_alternates_casei,1,5,git grep,git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.967714786529541,203,LC_ALL=C
|
||||||
|
linux_alternates_casei,1,5,git grep,git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.9789888858795166,203,LC_ALL=C
|
||||||
|
linux_alternates_casei,1,5,git grep,git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.9938976764678955,203,LC_ALL=C
|
||||||
|
linux_alternates_casei,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT ./,0.2825000286102295,203,
|
||||||
|
linux_alternates_casei,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT ./,0.27024054527282715,203,
|
||||||
|
linux_alternates_casei,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT ./,0.27353668212890625,203,
|
||||||
|
linux_alternates_casei,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT ./,0.27333736419677734,203,
|
||||||
|
linux_alternates_casei,1,5,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT ./,0.2730555534362793,203,
|
||||||
|
subtitles_en_literal,1,5,rg,rg Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.2259538173675537,830,
|
||||||
|
subtitles_en_literal,1,5,rg,rg Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.22034168243408203,830,
|
||||||
|
subtitles_en_literal,1,5,rg,rg Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.22986674308776855,830,
|
||||||
|
subtitles_en_literal,1,5,rg,rg Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.22815775871276855,830,
|
||||||
|
subtitles_en_literal,1,5,rg,rg Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.2238922119140625,830,
|
||||||
|
subtitles_en_literal,1,5,rg (no mmap),rg --no-mmap Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.36427783966064453,830,
|
||||||
|
subtitles_en_literal,1,5,rg (no mmap),rg --no-mmap Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.37499117851257324,830,
|
||||||
|
subtitles_en_literal,1,5,rg (no mmap),rg --no-mmap Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.36223769187927246,830,
|
||||||
|
subtitles_en_literal,1,5,rg (no mmap),rg --no-mmap Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.3646128177642822,830,
|
||||||
|
subtitles_en_literal,1,5,rg (no mmap),rg --no-mmap Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.36281347274780273,830,
|
||||||
|
subtitles_en_literal,1,5,grep,grep Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.8064453601837158,830,LC_ALL=C
|
||||||
|
subtitles_en_literal,1,5,grep,grep Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.8001935482025146,830,LC_ALL=C
|
||||||
|
subtitles_en_literal,1,5,grep,grep Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.8018591403961182,830,LC_ALL=C
|
||||||
|
subtitles_en_literal,1,5,grep,grep Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.7978458404541016,830,LC_ALL=C
|
||||||
|
subtitles_en_literal,1,5,grep,grep Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.7912843227386475,830,LC_ALL=C
|
||||||
|
subtitles_en_literal,1,5,rg (lines),rg -n Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.31099891662597656,830,
|
||||||
|
subtitles_en_literal,1,5,rg (lines),rg -n Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.3145768642425537,830,
|
||||||
|
subtitles_en_literal,1,5,rg (lines),rg -n Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.30507469177246094,830,
|
||||||
|
subtitles_en_literal,1,5,rg (lines),rg -n Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.3450126647949219,830,
|
||||||
|
subtitles_en_literal,1,5,rg (lines),rg -n Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.31091880798339844,830,
|
||||||
|
subtitles_en_literal,1,5,ag (lines),ag -s Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,2.5518174171447754,830,
|
||||||
|
subtitles_en_literal,1,5,ag (lines),ag -s Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,2.551568031311035,830,
|
||||||
|
subtitles_en_literal,1,5,ag (lines),ag -s Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,2.5306365489959717,830,
|
||||||
|
subtitles_en_literal,1,5,ag (lines),ag -s Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,2.537529468536377,830,
|
||||||
|
subtitles_en_literal,1,5,ag (lines),ag -s Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,2.5627124309539795,830,
|
||||||
|
subtitles_en_literal,1,5,grep (lines),grep -n Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,1.2934913635253906,830,LC_ALL=C
|
||||||
|
subtitles_en_literal,1,5,grep (lines),grep -n Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,1.2990975379943848,830,LC_ALL=C
|
||||||
|
subtitles_en_literal,1,5,grep (lines),grep -n Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,1.2942156791687012,830,LC_ALL=C
|
||||||
|
subtitles_en_literal,1,5,grep (lines),grep -n Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,1.2887969017028809,830,LC_ALL=C
|
||||||
|
subtitles_en_literal,1,5,grep (lines),grep -n Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,1.2922444343566895,830,LC_ALL=C
|
||||||
|
subtitles_en_literal,1,5,ugrep (lines),ugrep -n Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.3939177989959717,830,
|
||||||
|
subtitles_en_literal,1,5,ugrep (lines),ugrep -n Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.3916018009185791,830,
|
||||||
|
subtitles_en_literal,1,5,ugrep (lines),ugrep -n Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.40460968017578125,830,
|
||||||
|
subtitles_en_literal,1,5,ugrep (lines),ugrep -n Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.41738367080688477,830,
|
||||||
|
subtitles_en_literal,1,5,ugrep (lines),ugrep -n Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.41339826583862305,830,
|
||||||
|
subtitles_en_literal_casei,1,5,rg,rg -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.37847900390625,871,
|
||||||
|
subtitles_en_literal_casei,1,5,rg,rg -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.3692331314086914,871,
|
||||||
|
subtitles_en_literal_casei,1,5,rg,rg -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.40493106842041016,871,
|
||||||
|
subtitles_en_literal_casei,1,5,rg,rg -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.4074361324310303,871,
|
||||||
|
subtitles_en_literal_casei,1,5,rg,rg -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.4297189712524414,871,
|
||||||
|
subtitles_en_literal_casei,1,5,grep,grep -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,3.63842511177063,871,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_literal_casei,1,5,grep,grep -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,3.6366350650787354,871,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_literal_casei,1,5,grep,grep -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,3.6044440269470215,871,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_literal_casei,1,5,grep,grep -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,3.6123127937316895,871,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_literal_casei,1,5,grep,grep -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,3.6119742393493652,871,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_literal_casei,1,5,grep (ASCII),grep -E -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.917151689529419,871,LC_ALL=C
|
||||||
|
subtitles_en_literal_casei,1,5,grep (ASCII),grep -E -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.9379458427429199,871,LC_ALL=C
|
||||||
|
subtitles_en_literal_casei,1,5,grep (ASCII),grep -E -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.9703550338745117,871,LC_ALL=C
|
||||||
|
subtitles_en_literal_casei,1,5,grep (ASCII),grep -E -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.9309988021850586,871,LC_ALL=C
|
||||||
|
subtitles_en_literal_casei,1,5,grep (ASCII),grep -E -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.9328129291534424,871,LC_ALL=C
|
||||||
|
subtitles_en_literal_casei,1,5,rg (lines),rg -n -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.5196061134338379,871,
|
||||||
|
subtitles_en_literal_casei,1,5,rg (lines),rg -n -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.5225450992584229,871,
|
||||||
|
subtitles_en_literal_casei,1,5,rg (lines),rg -n -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.4856400489807129,871,
|
||||||
|
subtitles_en_literal_casei,1,5,rg (lines),rg -n -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.5204241275787354,871,
|
||||||
|
subtitles_en_literal_casei,1,5,rg (lines),rg -n -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.5224106311798096,871,
|
||||||
|
subtitles_en_literal_casei,1,5,ag (lines) (ASCII),ag -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,2.5935003757476807,871,
|
||||||
|
subtitles_en_literal_casei,1,5,ag (lines) (ASCII),ag -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,2.640918016433716,871,
|
||||||
|
subtitles_en_literal_casei,1,5,ag (lines) (ASCII),ag -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,2.602182626724243,871,
|
||||||
|
subtitles_en_literal_casei,1,5,ag (lines) (ASCII),ag -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,2.575654983520508,871,
|
||||||
|
subtitles_en_literal_casei,1,5,ag (lines) (ASCII),ag -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,2.5606820583343506,871,
|
||||||
|
subtitles_en_literal_casei,1,5,ugrep (lines),ugrep -n -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,1.0980546474456787,871,
|
||||||
|
subtitles_en_literal_casei,1,5,ugrep (lines),ugrep -n -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,1.095038652420044,871,
|
||||||
|
subtitles_en_literal_casei,1,5,ugrep (lines),ugrep -n -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,1.0974702835083008,871,
|
||||||
|
subtitles_en_literal_casei,1,5,ugrep (lines),ugrep -n -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,1.113879919052124,871,
|
||||||
|
subtitles_en_literal_casei,1,5,ugrep (lines),ugrep -n -i Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,1.1096961498260498,871,
|
||||||
|
subtitles_en_literal_word,1,5,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /tmp/benchsuite/subtitles/en.sample.txt,0.3175060749053955,830,
|
||||||
|
subtitles_en_literal_word,1,5,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /tmp/benchsuite/subtitles/en.sample.txt,0.321685791015625,830,
|
||||||
|
subtitles_en_literal_word,1,5,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /tmp/benchsuite/subtitles/en.sample.txt,0.30799293518066406,830,
|
||||||
|
subtitles_en_literal_word,1,5,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /tmp/benchsuite/subtitles/en.sample.txt,0.31140613555908203,830,
|
||||||
|
subtitles_en_literal_word,1,5,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /tmp/benchsuite/subtitles/en.sample.txt,0.32439208030700684,830,
|
||||||
|
subtitles_en_literal_word,1,5,ag (ASCII),ag -sw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,2.5530965328216553,830,
|
||||||
|
subtitles_en_literal_word,1,5,ag (ASCII),ag -sw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,2.5833561420440674,830,
|
||||||
|
subtitles_en_literal_word,1,5,ag (ASCII),ag -sw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,2.5765762329101562,830,
|
||||||
|
subtitles_en_literal_word,1,5,ag (ASCII),ag -sw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,2.610975742340088,830,
|
||||||
|
subtitles_en_literal_word,1,5,ag (ASCII),ag -sw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,2.5965471267700195,830,
|
||||||
|
subtitles_en_literal_word,1,5,grep (ASCII),grep -nw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,1.3212966918945312,830,LC_ALL=C
|
||||||
|
subtitles_en_literal_word,1,5,grep (ASCII),grep -nw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,1.311401128768921,830,LC_ALL=C
|
||||||
|
subtitles_en_literal_word,1,5,grep (ASCII),grep -nw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,1.298889398574829,830,LC_ALL=C
|
||||||
|
subtitles_en_literal_word,1,5,grep (ASCII),grep -nw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,1.316542148590088,830,LC_ALL=C
|
||||||
|
subtitles_en_literal_word,1,5,grep (ASCII),grep -nw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,1.3483500480651855,830,LC_ALL=C
|
||||||
|
subtitles_en_literal_word,1,5,ugrep (ASCII),ugrep -nw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.4127326011657715,830,
|
||||||
|
subtitles_en_literal_word,1,5,ugrep (ASCII),ugrep -nw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.4138009548187256,830,
|
||||||
|
subtitles_en_literal_word,1,5,ugrep (ASCII),ugrep -nw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.4203319549560547,830,
|
||||||
|
subtitles_en_literal_word,1,5,ugrep (ASCII),ugrep -nw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.4127979278564453,830,
|
||||||
|
subtitles_en_literal_word,1,5,ugrep (ASCII),ugrep -nw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.41126537322998047,830,
|
||||||
|
subtitles_en_literal_word,1,5,rg,rg -nw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.3251321315765381,830,
|
||||||
|
subtitles_en_literal_word,1,5,rg,rg -nw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.31773900985717773,830,
|
||||||
|
subtitles_en_literal_word,1,5,rg,rg -nw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.32987523078918457,830,
|
||||||
|
subtitles_en_literal_word,1,5,rg,rg -nw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.32228970527648926,830,
|
||||||
|
subtitles_en_literal_word,1,5,rg,rg -nw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,0.3207516670227051,830,
|
||||||
|
subtitles_en_literal_word,1,5,grep,grep -nw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,1.2946159839630127,830,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_literal_word,1,5,grep,grep -nw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,1.333972454071045,830,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_literal_word,1,5,grep,grep -nw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,1.3002500534057617,830,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_literal_word,1,5,grep,grep -nw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,1.347550630569458,830,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_literal_word,1,5,grep,grep -nw Sherlock Holmes /tmp/benchsuite/subtitles/en.sample.txt,1.306572675704956,830,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_alternate,1,5,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,0.4178187847137451,1094,
|
||||||
|
subtitles_en_alternate,1,5,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,0.44626832008361816,1094,
|
||||||
|
subtitles_en_alternate,1,5,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,0.44959425926208496,1094,
|
||||||
|
subtitles_en_alternate,1,5,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,0.38634324073791504,1094,
|
||||||
|
subtitles_en_alternate,1,5,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,0.4460463523864746,1094,
|
||||||
|
subtitles_en_alternate,1,5,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,3.6045682430267334,1094,
|
||||||
|
subtitles_en_alternate,1,5,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,3.6191344261169434,1094,
|
||||||
|
subtitles_en_alternate,1,5,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,3.579859972000122,1094,
|
||||||
|
subtitles_en_alternate,1,5,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,3.6637580394744873,1094,
|
||||||
|
subtitles_en_alternate,1,5,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,3.5728182792663574,1094,
|
||||||
|
subtitles_en_alternate,1,5,grep (lines),grep -E -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,3.323948621749878,1094,LC_ALL=C
|
||||||
|
subtitles_en_alternate,1,5,grep (lines),grep -E -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,3.3338429927825928,1094,LC_ALL=C
|
||||||
|
subtitles_en_alternate,1,5,grep (lines),grep -E -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,3.34714937210083,1094,LC_ALL=C
|
||||||
|
subtitles_en_alternate,1,5,grep (lines),grep -E -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,3.314117908477783,1094,LC_ALL=C
|
||||||
|
subtitles_en_alternate,1,5,grep (lines),grep -E -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,3.303710699081421,1094,LC_ALL=C
|
||||||
|
subtitles_en_alternate,1,5,ugrep (lines),ugrep -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,1.147033452987671,1094,
|
||||||
|
subtitles_en_alternate,1,5,ugrep (lines),ugrep -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,1.2054970264434814,1094,
|
||||||
|
subtitles_en_alternate,1,5,ugrep (lines),ugrep -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,1.0998892784118652,1094,
|
||||||
|
subtitles_en_alternate,1,5,ugrep (lines),ugrep -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,1.101989984512329,1094,
|
||||||
|
subtitles_en_alternate,1,5,ugrep (lines),ugrep -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,1.110612154006958,1094,
|
||||||
|
subtitles_en_alternate,1,5,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,0.29009222984313965,1094,
|
||||||
|
subtitles_en_alternate,1,5,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,0.29300451278686523,1094,
|
||||||
|
subtitles_en_alternate,1,5,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,0.3199915885925293,1094,
|
||||||
|
subtitles_en_alternate,1,5,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,0.3187263011932373,1094,
|
||||||
|
subtitles_en_alternate,1,5,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,0.30321288108825684,1094,
|
||||||
|
subtitles_en_alternate,1,5,grep,grep -E Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,2.813009738922119,1094,LC_ALL=C
|
||||||
|
subtitles_en_alternate,1,5,grep,grep -E Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,2.80930757522583,1094,LC_ALL=C
|
||||||
|
subtitles_en_alternate,1,5,grep,grep -E Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,2.814509153366089,1094,LC_ALL=C
|
||||||
|
subtitles_en_alternate,1,5,grep,grep -E Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,2.8390560150146484,1094,LC_ALL=C
|
||||||
|
subtitles_en_alternate,1,5,grep,grep -E Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,2.830871105194092,1094,LC_ALL=C
|
||||||
|
subtitles_en_alternate_casei,1,5,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,6.166510343551636,1136,
|
||||||
|
subtitles_en_alternate_casei,1,5,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,6.192304849624634,1136,
|
||||||
|
subtitles_en_alternate_casei,1,5,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,6.185140132904053,1136,
|
||||||
|
subtitles_en_alternate_casei,1,5,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,6.20132040977478,1136,
|
||||||
|
subtitles_en_alternate_casei,1,5,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,6.159040451049805,1136,
|
||||||
|
subtitles_en_alternate_casei,1,5,grep (ASCII),grep -E -ni Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,5.523138999938965,1136,LC_ALL=C
|
||||||
|
subtitles_en_alternate_casei,1,5,grep (ASCII),grep -E -ni Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,5.512346267700195,1136,LC_ALL=C
|
||||||
|
subtitles_en_alternate_casei,1,5,grep (ASCII),grep -E -ni Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,5.562563896179199,1136,LC_ALL=C
|
||||||
|
subtitles_en_alternate_casei,1,5,grep (ASCII),grep -E -ni Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,5.533160448074341,1136,LC_ALL=C
|
||||||
|
subtitles_en_alternate_casei,1,5,grep (ASCII),grep -E -ni Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,5.504830837249756,1136,LC_ALL=C
|
||||||
|
subtitles_en_alternate_casei,1,5,ugrep (ASCII),ugrep -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,1.1120033264160156,1136,
|
||||||
|
subtitles_en_alternate_casei,1,5,ugrep (ASCII),ugrep -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,1.1150739192962646,1136,
|
||||||
|
subtitles_en_alternate_casei,1,5,ugrep (ASCII),ugrep -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,1.1018304824829102,1136,
|
||||||
|
subtitles_en_alternate_casei,1,5,ugrep (ASCII),ugrep -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,1.1106996536254883,1136,
|
||||||
|
subtitles_en_alternate_casei,1,5,ugrep (ASCII),ugrep -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,1.0994808673858643,1136,
|
||||||
|
subtitles_en_alternate_casei,1,5,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,0.8494291305541992,1136,
|
||||||
|
subtitles_en_alternate_casei,1,5,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,0.7878148555755615,1136,
|
||||||
|
subtitles_en_alternate_casei,1,5,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,0.8290884494781494,1136,
|
||||||
|
subtitles_en_alternate_casei,1,5,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,0.7409803867340088,1136,
|
||||||
|
subtitles_en_alternate_casei,1,5,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,0.7880558967590332,1136,
|
||||||
|
subtitles_en_alternate_casei,1,5,grep,grep -E -ni Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,5.5523765087127686,1136,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_alternate_casei,1,5,grep,grep -E -ni Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,5.527086019515991,1136,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_alternate_casei,1,5,grep,grep -E -ni Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,5.740911483764648,1136,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_alternate_casei,1,5,grep,grep -E -ni Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,5.520638465881348,1136,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_alternate_casei,1,5,grep,grep -E -ni Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/en.sample.txt,5.52523398399353,1136,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_surrounding_words,1,5,rg,rg -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,0.3353078365325928,483,
|
||||||
|
subtitles_en_surrounding_words,1,5,rg,rg -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,0.3248591423034668,483,
|
||||||
|
subtitles_en_surrounding_words,1,5,rg,rg -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,0.33918261528015137,483,
|
||||||
|
subtitles_en_surrounding_words,1,5,rg,rg -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,0.33177971839904785,483,
|
||||||
|
subtitles_en_surrounding_words,1,5,rg,rg -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,0.34472131729125977,483,
|
||||||
|
subtitles_en_surrounding_words,1,5,grep,grep -E -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,1.7516274452209473,483,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_surrounding_words,1,5,grep,grep -E -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,1.7489221096038818,483,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_surrounding_words,1,5,grep,grep -E -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,1.7574889659881592,483,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_surrounding_words,1,5,grep,grep -E -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,1.813244342803955,483,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_surrounding_words,1,5,grep,grep -E -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,1.750051498413086,483,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_surrounding_words,1,5,ugrep,ugrep -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,70.12419986724854,489,
|
||||||
|
subtitles_en_surrounding_words,1,5,ugrep,ugrep -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,70.26925611495972,489,
|
||||||
|
subtitles_en_surrounding_words,1,5,ugrep,ugrep -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,70.56865787506104,489,
|
||||||
|
subtitles_en_surrounding_words,1,5,ugrep,ugrep -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,70.12933135032654,489,
|
||||||
|
subtitles_en_surrounding_words,1,5,ugrep,ugrep -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,70.07925295829773,489,
|
||||||
|
subtitles_en_surrounding_words,1,5,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,0.3309454917907715,483,
|
||||||
|
subtitles_en_surrounding_words,1,5,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,0.33062124252319336,483,
|
||||||
|
subtitles_en_surrounding_words,1,5,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,0.3292708396911621,483,
|
||||||
|
subtitles_en_surrounding_words,1,5,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,0.3300509452819824,483,
|
||||||
|
subtitles_en_surrounding_words,1,5,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,0.3252389430999756,483,
|
||||||
|
subtitles_en_surrounding_words,1,5,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,7.372813701629639,489,
|
||||||
|
subtitles_en_surrounding_words,1,5,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,7.338848114013672,489,
|
||||||
|
subtitles_en_surrounding_words,1,5,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,7.739792108535767,489,
|
||||||
|
subtitles_en_surrounding_words,1,5,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,7.302056074142456,489,
|
||||||
|
subtitles_en_surrounding_words,1,5,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,7.334207057952881,489,
|
||||||
|
subtitles_en_surrounding_words,1,5,grep (ASCII),grep -E -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,1.7617950439453125,483,LC_ALL=C
|
||||||
|
subtitles_en_surrounding_words,1,5,grep (ASCII),grep -E -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,1.7765378952026367,483,LC_ALL=C
|
||||||
|
subtitles_en_surrounding_words,1,5,grep (ASCII),grep -E -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,1.7456245422363281,483,LC_ALL=C
|
||||||
|
subtitles_en_surrounding_words,1,5,grep (ASCII),grep -E -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,1.748713731765747,483,LC_ALL=C
|
||||||
|
subtitles_en_surrounding_words,1,5,grep (ASCII),grep -E -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,1.7846882343292236,483,LC_ALL=C
|
||||||
|
subtitles_en_surrounding_words,1,5,ugrep (ASCII),ugrep -n -U \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,31.14370322227478,489,
|
||||||
|
subtitles_en_surrounding_words,1,5,ugrep (ASCII),ugrep -n -U \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,31.543628454208374,489,
|
||||||
|
subtitles_en_surrounding_words,1,5,ugrep (ASCII),ugrep -n -U \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,31.133421182632446,489,
|
||||||
|
subtitles_en_surrounding_words,1,5,ugrep (ASCII),ugrep -n -U \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,31.149214506149292,489,
|
||||||
|
subtitles_en_surrounding_words,1,5,ugrep (ASCII),ugrep -n -U \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/en.sample.txt,31.180144548416138,489,
|
||||||
|
subtitles_en_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,2.9173591136932373,22,
|
||||||
|
subtitles_en_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,2.867539644241333,22,
|
||||||
|
subtitles_en_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,2.9047088623046875,22,
|
||||||
|
subtitles_en_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,2.9265778064727783,22,
|
||||||
|
subtitles_en_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,2.874317169189453,22,
|
||||||
|
subtitles_en_no_literal,1,5,ugrep,ugrep -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,24.619744777679443,309,
|
||||||
|
subtitles_en_no_literal,1,5,ugrep,ugrep -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,24.622087240219116,309,
|
||||||
|
subtitles_en_no_literal,1,5,ugrep,ugrep -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,24.770710468292236,309,
|
||||||
|
subtitles_en_no_literal,1,5,ugrep,ugrep -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,24.60181713104248,309,
|
||||||
|
subtitles_en_no_literal,1,5,ugrep,ugrep -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,24.678969383239746,309,
|
||||||
|
subtitles_en_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,2.676262140274048,22,
|
||||||
|
subtitles_en_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,2.673837184906006,22,
|
||||||
|
subtitles_en_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,2.667243003845215,22,
|
||||||
|
subtitles_en_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,2.667970657348633,22,
|
||||||
|
subtitles_en_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,2.6588196754455566,22,
|
||||||
|
subtitles_en_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,10.786212682723999,302,
|
||||||
|
subtitles_en_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,10.744041204452515,302,
|
||||||
|
subtitles_en_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,10.74718165397644,302,
|
||||||
|
subtitles_en_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,10.768681287765503,302,
|
||||||
|
subtitles_en_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,10.772834777832031,302,
|
||||||
|
subtitles_en_no_literal,1,5,grep (ASCII),grep -E -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,6.287469148635864,22,LC_ALL=C
|
||||||
|
subtitles_en_no_literal,1,5,grep (ASCII),grep -E -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,6.243509769439697,22,LC_ALL=C
|
||||||
|
subtitles_en_no_literal,1,5,grep (ASCII),grep -E -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,6.242478370666504,22,LC_ALL=C
|
||||||
|
subtitles_en_no_literal,1,5,grep (ASCII),grep -E -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,6.2600791454315186,22,LC_ALL=C
|
||||||
|
subtitles_en_no_literal,1,5,grep (ASCII),grep -E -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,6.2560741901397705,22,LC_ALL=C
|
||||||
|
subtitles_en_no_literal,1,5,ugrep (ASCII),ugrep -n -U \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,4.670856237411499,302,
|
||||||
|
subtitles_en_no_literal,1,5,ugrep (ASCII),ugrep -n -U \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,4.703561544418335,302,
|
||||||
|
subtitles_en_no_literal,1,5,ugrep (ASCII),ugrep -n -U \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,4.675989627838135,302,
|
||||||
|
subtitles_en_no_literal,1,5,ugrep (ASCII),ugrep -n -U \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,4.6688103675842285,302,
|
||||||
|
subtitles_en_no_literal,1,5,ugrep (ASCII),ugrep -n -U \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/en.sample.txt,4.715432167053223,302,
|
||||||
|
subtitles_ru_literal,1,5,rg,rg Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.20440673828125,583,
|
||||||
|
subtitles_ru_literal,1,5,rg,rg Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.20561552047729492,583,
|
||||||
|
subtitles_ru_literal,1,5,rg,rg Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.2381761074066162,583,
|
||||||
|
subtitles_ru_literal,1,5,rg,rg Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.23102140426635742,583,
|
||||||
|
subtitles_ru_literal,1,5,rg,rg Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.19649791717529297,583,
|
||||||
|
subtitles_ru_literal,1,5,rg (no mmap),rg --no-mmap Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.3158297538757324,583,
|
||||||
|
subtitles_ru_literal,1,5,rg (no mmap),rg --no-mmap Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.3136112689971924,583,
|
||||||
|
subtitles_ru_literal,1,5,rg (no mmap),rg --no-mmap Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.32402992248535156,583,
|
||||||
|
subtitles_ru_literal,1,5,rg (no mmap),rg --no-mmap Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.3248250484466553,583,
|
||||||
|
subtitles_ru_literal,1,5,rg (no mmap),rg --no-mmap Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.3201103210449219,583,
|
||||||
|
subtitles_ru_literal,1,5,grep,grep Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.7790360450744629,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal,1,5,grep,grep Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.7977695465087891,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal,1,5,grep,grep Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.7397308349609375,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal,1,5,grep,grep Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.7123947143554688,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal,1,5,grep,grep Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.711977481842041,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal,1,5,rg (lines),rg -n Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.27593088150024414,583,
|
||||||
|
subtitles_ru_literal,1,5,rg (lines),rg -n Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.2842848300933838,583,
|
||||||
|
subtitles_ru_literal,1,5,rg (lines),rg -n Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.28340864181518555,583,
|
||||||
|
subtitles_ru_literal,1,5,rg (lines),rg -n Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.28469133377075195,583,
|
||||||
|
subtitles_ru_literal,1,5,rg (lines),rg -n Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.27951884269714355,583,
|
||||||
|
subtitles_ru_literal,1,5,ag (lines),ag -s Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,2.7401182651519775,583,
|
||||||
|
subtitles_ru_literal,1,5,ag (lines),ag -s Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,2.658051013946533,583,
|
||||||
|
subtitles_ru_literal,1,5,ag (lines),ag -s Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,2.666799306869507,583,
|
||||||
|
subtitles_ru_literal,1,5,ag (lines),ag -s Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,2.7145025730133057,583,
|
||||||
|
subtitles_ru_literal,1,5,ag (lines),ag -s Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,2.7412168979644775,583,
|
||||||
|
subtitles_ru_literal,1,5,grep (lines),grep -n Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.0886235237121582,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal,1,5,grep (lines),grep -n Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.0896506309509277,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal,1,5,grep (lines),grep -n Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.1100494861602783,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal,1,5,grep (lines),grep -n Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.088308334350586,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal,1,5,grep (lines),grep -n Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.0891127586364746,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal,1,5,ugrep (lines),ugrep -n Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.8426175117492676,583,
|
||||||
|
subtitles_ru_literal,1,5,ugrep (lines),ugrep -n Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.85064697265625,583,
|
||||||
|
subtitles_ru_literal,1,5,ugrep (lines),ugrep -n Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.8356082439422607,583,
|
||||||
|
subtitles_ru_literal,1,5,ugrep (lines),ugrep -n Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.8405826091766357,583,
|
||||||
|
subtitles_ru_literal,1,5,ugrep (lines),ugrep -n Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.83730149269104,583,
|
||||||
|
subtitles_ru_literal_casei,1,5,rg,rg -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.48739099502563477,604,
|
||||||
|
subtitles_ru_literal_casei,1,5,rg,rg -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.4823324680328369,604,
|
||||||
|
subtitles_ru_literal_casei,1,5,rg,rg -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.4832422733306885,604,
|
||||||
|
subtitles_ru_literal_casei,1,5,rg,rg -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.4812777042388916,604,
|
||||||
|
subtitles_ru_literal_casei,1,5,rg,rg -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.4854264259338379,604,
|
||||||
|
subtitles_ru_literal_casei,1,5,grep,grep -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,6.694453477859497,604,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_literal_casei,1,5,grep,grep -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,6.759232044219971,604,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_literal_casei,1,5,grep,grep -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,6.686243534088135,604,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_literal_casei,1,5,grep,grep -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,6.7029454708099365,604,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_literal_casei,1,5,grep,grep -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,6.699738264083862,604,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_literal_casei,1,5,grep (ASCII),grep -E -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.7290260791778564,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal_casei,1,5,grep (ASCII),grep -E -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.7400493621826172,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal_casei,1,5,grep (ASCII),grep -E -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.7299001216888428,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal_casei,1,5,grep (ASCII),grep -E -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.7308380603790283,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal_casei,1,5,grep (ASCII),grep -E -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.7283904552459717,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal_casei,1,5,rg (lines),rg -n -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.5711629390716553,604,
|
||||||
|
subtitles_ru_literal_casei,1,5,rg (lines),rg -n -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.574974536895752,604,
|
||||||
|
subtitles_ru_literal_casei,1,5,rg (lines),rg -n -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.5820963382720947,604,
|
||||||
|
subtitles_ru_literal_casei,1,5,rg (lines),rg -n -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.5438523292541504,604,
|
||||||
|
subtitles_ru_literal_casei,1,5,rg (lines),rg -n -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.5054161548614502,604,
|
||||||
|
subtitles_ru_literal_casei,1,5,ag (lines) (ASCII),ag -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.6135058403015137,,
|
||||||
|
subtitles_ru_literal_casei,1,5,ag (lines) (ASCII),ag -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.6051545143127441,,
|
||||||
|
subtitles_ru_literal_casei,1,5,ag (lines) (ASCII),ag -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.6032793521881104,,
|
||||||
|
subtitles_ru_literal_casei,1,5,ag (lines) (ASCII),ag -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.6097028255462646,,
|
||||||
|
subtitles_ru_literal_casei,1,5,ag (lines) (ASCII),ag -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.6850666999816895,,
|
||||||
|
subtitles_ru_literal_casei,1,5,ugrep (lines) (ASCII),ugrep -n -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.833592176437378,583,
|
||||||
|
subtitles_ru_literal_casei,1,5,ugrep (lines) (ASCII),ugrep -n -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.8357219696044922,583,
|
||||||
|
subtitles_ru_literal_casei,1,5,ugrep (lines) (ASCII),ugrep -n -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.8394358158111572,583,
|
||||||
|
subtitles_ru_literal_casei,1,5,ugrep (lines) (ASCII),ugrep -n -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.8334264755249023,583,
|
||||||
|
subtitles_ru_literal_casei,1,5,ugrep (lines) (ASCII),ugrep -n -i Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.8304622173309326,583,
|
||||||
|
subtitles_ru_literal_word,1,5,rg (ASCII),rg -n (?-u:^|\W)Шерлок Холмс(?-u:$|\W) /tmp/benchsuite/subtitles/ru.txt,0.2904787063598633,583,
|
||||||
|
subtitles_ru_literal_word,1,5,rg (ASCII),rg -n (?-u:^|\W)Шерлок Холмс(?-u:$|\W) /tmp/benchsuite/subtitles/ru.txt,0.2831101417541504,583,
|
||||||
|
subtitles_ru_literal_word,1,5,rg (ASCII),rg -n (?-u:^|\W)Шерлок Холмс(?-u:$|\W) /tmp/benchsuite/subtitles/ru.txt,0.2786984443664551,583,
|
||||||
|
subtitles_ru_literal_word,1,5,rg (ASCII),rg -n (?-u:^|\W)Шерлок Холмс(?-u:$|\W) /tmp/benchsuite/subtitles/ru.txt,0.28719663619995117,583,
|
||||||
|
subtitles_ru_literal_word,1,5,rg (ASCII),rg -n (?-u:^|\W)Шерлок Холмс(?-u:$|\W) /tmp/benchsuite/subtitles/ru.txt,0.27600622177124023,583,
|
||||||
|
subtitles_ru_literal_word,1,5,ag (ASCII),ag -sw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.6810102462768555,,
|
||||||
|
subtitles_ru_literal_word,1,5,ag (ASCII),ag -sw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.6855161190032959,,
|
||||||
|
subtitles_ru_literal_word,1,5,ag (ASCII),ag -sw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.6827929019927979,,
|
||||||
|
subtitles_ru_literal_word,1,5,ag (ASCII),ag -sw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.6587810516357422,,
|
||||||
|
subtitles_ru_literal_word,1,5,ag (ASCII),ag -sw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.6551673412322998,,
|
||||||
|
subtitles_ru_literal_word,1,5,grep (ASCII),grep -nw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.0948495864868164,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal_word,1,5,grep (ASCII),grep -nw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.097151756286621,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal_word,1,5,grep (ASCII),grep -nw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.1051688194274902,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal_word,1,5,grep (ASCII),grep -nw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.1151607036590576,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal_word,1,5,grep (ASCII),grep -nw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.1100919246673584,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal_word,1,5,ugrep (ASCII),ugrep -nw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.84104585647583,,
|
||||||
|
subtitles_ru_literal_word,1,5,ugrep (ASCII),ugrep -nw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.9092209339141846,,
|
||||||
|
subtitles_ru_literal_word,1,5,ugrep (ASCII),ugrep -nw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.836583137512207,,
|
||||||
|
subtitles_ru_literal_word,1,5,ugrep (ASCII),ugrep -nw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.8941335678100586,,
|
||||||
|
subtitles_ru_literal_word,1,5,ugrep (ASCII),ugrep -nw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.8811957836151123,,
|
||||||
|
subtitles_ru_literal_word,1,5,rg,rg -nw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.2956504821777344,579,
|
||||||
|
subtitles_ru_literal_word,1,5,rg,rg -nw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.29023194313049316,579,
|
||||||
|
subtitles_ru_literal_word,1,5,rg,rg -nw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.3374972343444824,579,
|
||||||
|
subtitles_ru_literal_word,1,5,rg,rg -nw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.29686713218688965,579,
|
||||||
|
subtitles_ru_literal_word,1,5,rg,rg -nw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,0.29778003692626953,579,
|
||||||
|
subtitles_ru_literal_word,1,5,grep,grep -nw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.1042869091033936,579,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_literal_word,1,5,grep,grep -nw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.1068925857543945,579,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_literal_word,1,5,grep,grep -nw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.0973529815673828,579,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_literal_word,1,5,grep,grep -nw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.0917479991912842,579,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_literal_word,1,5,grep,grep -nw Шерлок Холмс /tmp/benchsuite/subtitles/ru.txt,1.0987188816070557,579,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_alternate,1,5,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,0.8945937156677246,691,
|
||||||
|
subtitles_ru_alternate,1,5,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,0.8919808864593506,691,
|
||||||
|
subtitles_ru_alternate,1,5,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,0.9041986465454102,691,
|
||||||
|
subtitles_ru_alternate,1,5,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,0.8838107585906982,691,
|
||||||
|
subtitles_ru_alternate,1,5,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,0.903540849685669,691,
|
||||||
|
subtitles_ru_alternate,1,5,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,3.715298652648926,691,
|
||||||
|
subtitles_ru_alternate,1,5,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,3.676830530166626,691,
|
||||||
|
subtitles_ru_alternate,1,5,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,3.721431016921997,691,
|
||||||
|
subtitles_ru_alternate,1,5,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,3.6990325450897217,691,
|
||||||
|
subtitles_ru_alternate,1,5,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,3.764216184616089,691,
|
||||||
|
subtitles_ru_alternate,1,5,grep (lines),grep -E -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,8.519805669784546,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate,1,5,grep (lines),grep -E -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,8.40212869644165,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate,1,5,grep (lines),grep -E -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,8.381818294525146,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate,1,5,grep (lines),grep -E -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,8.386401176452637,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate,1,5,grep (lines),grep -E -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,8.425997257232666,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate,1,5,ugrep (lines),ugrep -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,13.259684801101685,691,
|
||||||
|
subtitles_ru_alternate,1,5,ugrep (lines),ugrep -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,13.236181735992432,691,
|
||||||
|
subtitles_ru_alternate,1,5,ugrep (lines),ugrep -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,13.340983629226685,691,
|
||||||
|
subtitles_ru_alternate,1,5,ugrep (lines),ugrep -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,13.21895980834961,691,
|
||||||
|
subtitles_ru_alternate,1,5,ugrep (lines),ugrep -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,13.194425106048584,691,
|
||||||
|
subtitles_ru_alternate,1,5,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,0.8262777328491211,691,
|
||||||
|
subtitles_ru_alternate,1,5,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,0.8343832492828369,691,
|
||||||
|
subtitles_ru_alternate,1,5,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,0.8675012588500977,691,
|
||||||
|
subtitles_ru_alternate,1,5,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,0.8584244251251221,691,
|
||||||
|
subtitles_ru_alternate,1,5,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,0.8777158260345459,691,
|
||||||
|
subtitles_ru_alternate,1,5,grep,grep -E Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,8.25586986541748,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate,1,5,grep,grep -E Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,8.007173538208008,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate,1,5,grep,grep -E Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,8.068726301193237,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate,1,5,grep,grep -E Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,8.010542631149292,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate,1,5,grep,grep -E Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,8.021028280258179,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate_casei,1,5,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,3.7179486751556396,691,
|
||||||
|
subtitles_ru_alternate_casei,1,5,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,3.682896375656128,691,
|
||||||
|
subtitles_ru_alternate_casei,1,5,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,3.699859142303467,691,
|
||||||
|
subtitles_ru_alternate_casei,1,5,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,3.662733316421509,691,
|
||||||
|
subtitles_ru_alternate_casei,1,5,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,3.661060094833374,691,
|
||||||
|
subtitles_ru_alternate_casei,1,5,grep (ASCII),grep -E -ni Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,8.434819221496582,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate_casei,1,5,grep (ASCII),grep -E -ni Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,8.436205625534058,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate_casei,1,5,grep (ASCII),grep -E -ni Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,8.388120412826538,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate_casei,1,5,grep (ASCII),grep -E -ni Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,8.407799243927002,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate_casei,1,5,grep (ASCII),grep -E -ni Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,8.44464373588562,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate_casei,1,5,ugrep (ASCII),ugrep -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,13.216991662979126,691,
|
||||||
|
subtitles_ru_alternate_casei,1,5,ugrep (ASCII),ugrep -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,13.470320701599121,691,
|
||||||
|
subtitles_ru_alternate_casei,1,5,ugrep (ASCII),ugrep -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,13.21274471282959,691,
|
||||||
|
subtitles_ru_alternate_casei,1,5,ugrep (ASCII),ugrep -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,13.38324522972107,691,
|
||||||
|
subtitles_ru_alternate_casei,1,5,ugrep (ASCII),ugrep -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,13.3148832321167,691,
|
||||||
|
subtitles_ru_alternate_casei,1,5,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,6.205031156539917,735,
|
||||||
|
subtitles_ru_alternate_casei,1,5,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,6.1502509117126465,735,
|
||||||
|
subtitles_ru_alternate_casei,1,5,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,6.150696516036987,735,
|
||||||
|
subtitles_ru_alternate_casei,1,5,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,6.150148630142212,735,
|
||||||
|
subtitles_ru_alternate_casei,1,5,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,6.153124809265137,735,
|
||||||
|
subtitles_ru_alternate_casei,1,5,grep,grep -E -ni Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,7.477111339569092,735,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_alternate_casei,1,5,grep,grep -E -ni Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,7.483617782592773,735,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_alternate_casei,1,5,grep,grep -E -ni Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,7.502292156219482,735,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_alternate_casei,1,5,grep,grep -E -ni Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,7.528963327407837,735,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_alternate_casei,1,5,grep,grep -E -ni Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/ru.txt,7.482379198074341,735,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_surrounding_words,1,5,rg,rg -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,0.3461883068084717,278,
|
||||||
|
subtitles_ru_surrounding_words,1,5,rg,rg -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,0.30211687088012695,278,
|
||||||
|
subtitles_ru_surrounding_words,1,5,rg,rg -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,0.30521416664123535,278,
|
||||||
|
subtitles_ru_surrounding_words,1,5,rg,rg -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,0.2969543933868408,278,
|
||||||
|
subtitles_ru_surrounding_words,1,5,rg,rg -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,0.3003671169281006,278,
|
||||||
|
subtitles_ru_surrounding_words,1,5,grep,grep -E -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,1.4209251403808594,278,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_surrounding_words,1,5,grep,grep -E -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,1.4190807342529297,278,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_surrounding_words,1,5,grep,grep -E -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,1.4178283214569092,278,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_surrounding_words,1,5,grep,grep -E -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,1.4173235893249512,278,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_surrounding_words,1,5,grep,grep -E -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,1.4221296310424805,278,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_surrounding_words,1,5,ugrep,ugrep -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,70.6701226234436,326,
|
||||||
|
subtitles_ru_surrounding_words,1,5,ugrep,ugrep -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,71.15788650512695,326,
|
||||||
|
subtitles_ru_surrounding_words,1,5,ugrep,ugrep -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,71.07276272773743,326,
|
||||||
|
subtitles_ru_surrounding_words,1,5,ugrep,ugrep -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,70.5626060962677,326,
|
||||||
|
subtitles_ru_surrounding_words,1,5,ugrep,ugrep -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,70.54449439048767,326,
|
||||||
|
subtitles_ru_surrounding_words,1,5,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,1.868441104888916,,
|
||||||
|
subtitles_ru_surrounding_words,1,5,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,1.886382818222046,,
|
||||||
|
subtitles_ru_surrounding_words,1,5,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,1.8685986995697021,,
|
||||||
|
subtitles_ru_surrounding_words,1,5,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,1.8727426528930664,,
|
||||||
|
subtitles_ru_surrounding_words,1,5,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,1.8667800426483154,,
|
||||||
|
subtitles_ru_surrounding_words,1,5,grep (ASCII),grep -E -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,1.3818490505218506,,LC_ALL=C
|
||||||
|
subtitles_ru_surrounding_words,1,5,grep (ASCII),grep -E -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,1.3709721565246582,,LC_ALL=C
|
||||||
|
subtitles_ru_surrounding_words,1,5,grep (ASCII),grep -E -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,1.3819043636322021,,LC_ALL=C
|
||||||
|
subtitles_ru_surrounding_words,1,5,grep (ASCII),grep -E -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,1.460402488708496,,LC_ALL=C
|
||||||
|
subtitles_ru_surrounding_words,1,5,grep (ASCII),grep -E -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,1.4097135066986084,,LC_ALL=C
|
||||||
|
subtitles_ru_surrounding_words,1,5,ugrep (ASCII),ugrep -n -U \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,1.286102294921875,,
|
||||||
|
subtitles_ru_surrounding_words,1,5,ugrep (ASCII),ugrep -n -U \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,1.2712647914886475,,
|
||||||
|
subtitles_ru_surrounding_words,1,5,ugrep (ASCII),ugrep -n -U \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,1.2950100898742676,,
|
||||||
|
subtitles_ru_surrounding_words,1,5,ugrep (ASCII),ugrep -n -U \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,1.264500617980957,,
|
||||||
|
subtitles_ru_surrounding_words,1,5,ugrep (ASCII),ugrep -n -U \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/ru.txt,1.2877566814422607,,
|
||||||
|
subtitles_ru_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,3.1152236461639404,41,
|
||||||
|
subtitles_ru_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,3.1311423778533936,41,
|
||||||
|
subtitles_ru_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,3.0800061225891113,41,
|
||||||
|
subtitles_ru_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,3.070636510848999,41,
|
||||||
|
subtitles_ru_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,3.0940587520599365,41,
|
||||||
|
subtitles_ru_no_literal,1,5,ugrep,ugrep -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,50.85447072982788,86,
|
||||||
|
subtitles_ru_no_literal,1,5,ugrep,ugrep -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,50.832582235336304,86,
|
||||||
|
subtitles_ru_no_literal,1,5,ugrep,ugrep -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,50.8755087852478,86,
|
||||||
|
subtitles_ru_no_literal,1,5,ugrep,ugrep -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,50.79056358337402,86,
|
||||||
|
subtitles_ru_no_literal,1,5,ugrep,ugrep -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,50.84795618057251,86,
|
||||||
|
subtitles_ru_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,2.716826915740967,,
|
||||||
|
subtitles_ru_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,2.7381114959716797,,
|
||||||
|
subtitles_ru_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,2.7545180320739746,,
|
||||||
|
subtitles_ru_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,2.7215416431427,,
|
||||||
|
subtitles_ru_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,2.707784414291382,,
|
||||||
|
subtitles_ru_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,1.9250116348266602,,
|
||||||
|
subtitles_ru_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,1.8956947326660156,,
|
||||||
|
subtitles_ru_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,1.8904175758361816,,
|
||||||
|
subtitles_ru_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,1.8968868255615234,,
|
||||||
|
subtitles_ru_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,1.900888204574585,,
|
||||||
|
subtitles_ru_no_literal,1,5,grep (ASCII),grep -E -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,1.755054235458374,,LC_ALL=C
|
||||||
|
subtitles_ru_no_literal,1,5,grep (ASCII),grep -E -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,1.7681376934051514,,LC_ALL=C
|
||||||
|
subtitles_ru_no_literal,1,5,grep (ASCII),grep -E -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,1.7654614448547363,,LC_ALL=C
|
||||||
|
subtitles_ru_no_literal,1,5,grep (ASCII),grep -E -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,1.75648832321167,,LC_ALL=C
|
||||||
|
subtitles_ru_no_literal,1,5,grep (ASCII),grep -E -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,1.7456772327423096,,LC_ALL=C
|
||||||
|
subtitles_ru_no_literal,1,5,ugrep (ASCII),ugrep -n -U \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,1.2170698642730713,,
|
||||||
|
subtitles_ru_no_literal,1,5,ugrep (ASCII),ugrep -n -U \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,1.1907124519348145,,
|
||||||
|
subtitles_ru_no_literal,1,5,ugrep (ASCII),ugrep -n -U \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,1.1722266674041748,,
|
||||||
|
subtitles_ru_no_literal,1,5,ugrep (ASCII),ugrep -n -U \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,1.191617727279663,,
|
||||||
|
subtitles_ru_no_literal,1,5,ugrep (ASCII),ugrep -n -U \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/ru.txt,1.1909863948822021,,
|
||||||
|
208
benchsuite/runs/2020-10-14-archlinux-frink/summary
Normal file
208
benchsuite/runs/2020-10-14-archlinux-frink/summary
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
linux_literal_default (pattern: PM_RESUME)
|
||||||
|
------------------------------------------
|
||||||
|
rg* 0.124 +/- 0.004 (lines: 19)*
|
||||||
|
ag 0.771 +/- 0.187 (lines: 19)
|
||||||
|
git grep 0.480 +/- 0.010 (lines: 19)
|
||||||
|
ugrep 0.136 +/- 0.002 (lines: 19)
|
||||||
|
grep 1.147 +/- 0.005 (lines: 19)
|
||||||
|
|
||||||
|
linux_literal (pattern: PM_RESUME)
|
||||||
|
----------------------------------
|
||||||
|
rg* 0.130 +/- 0.008 (lines: 19)*
|
||||||
|
rg (mmap) 1.336 +/- 0.036 (lines: 19)
|
||||||
|
ag (mmap) 0.880 +/- 0.071 (lines: 19)
|
||||||
|
git grep 0.464 +/- 0.005 (lines: 19)
|
||||||
|
ugrep 0.309 +/- 0.012 (lines: 19)
|
||||||
|
|
||||||
|
linux_literal_casei (pattern: PM_RESUME)
|
||||||
|
----------------------------------------
|
||||||
|
rg* 0.131 +/- 0.005 (lines: 456)*
|
||||||
|
rg (mmap) 1.336 +/- 0.020 (lines: 456)
|
||||||
|
ag (mmap) 0.657 +/- 0.123 (lines: 456)
|
||||||
|
git grep 0.482 +/- 0.007 (lines: 456)
|
||||||
|
ugrep 0.288 +/- 0.014 (lines: 456)
|
||||||
|
|
||||||
|
linux_re_literal_suffix (pattern: [A-Z]+_RESUME)
|
||||||
|
------------------------------------------------
|
||||||
|
rg* 0.126 +/- 0.009 (lines: 1944)*
|
||||||
|
ag 1.044 +/- 0.138 (lines: 1944)
|
||||||
|
git grep 1.217 +/- 0.045 (lines: 1944)
|
||||||
|
ugrep 0.548 +/- 0.014 (lines: 1944)
|
||||||
|
|
||||||
|
linux_word (pattern: PM_RESUME)
|
||||||
|
-------------------------------
|
||||||
|
rg* 0.134 +/- 0.003 (lines: 6)*
|
||||||
|
ag 0.618 +/- 0.154 (lines: 6)
|
||||||
|
git grep 0.471 +/- 0.018 (lines: 6)
|
||||||
|
ugrep 0.306 +/- 0.018 (lines: 6)
|
||||||
|
|
||||||
|
linux_unicode_greek (pattern: \p{Greek})
|
||||||
|
----------------------------------------
|
||||||
|
rg* 0.263 +/- 0.001 (lines: 105)*
|
||||||
|
ugrep 0.273 +/- 0.007 (lines: 105)
|
||||||
|
|
||||||
|
linux_unicode_greek_casei (pattern: \p{Greek})
|
||||||
|
----------------------------------------------
|
||||||
|
rg* 0.256 +/- 0.013 (lines: 225)*
|
||||||
|
ugrep 0.271 +/- 0.004 (lines: 105)
|
||||||
|
|
||||||
|
linux_unicode_word (pattern: \wAh)
|
||||||
|
----------------------------------
|
||||||
|
rg 0.140 +/- 0.004 (lines: 229)
|
||||||
|
rg (ASCII)* 0.138 +/- 0.009 (lines: 216)*
|
||||||
|
ag (ASCII) 1.278 +/- 0.101 (lines: 216)
|
||||||
|
git grep 8.188 +/- 0.027 (lines: 229)
|
||||||
|
git grep (ASCII) 2.334 +/- 0.025 (lines: 216)
|
||||||
|
ugrep 0.276 +/- 0.002 (lines: 229)
|
||||||
|
ugrep (ASCII) 0.274 +/- 0.004 (lines: 216)
|
||||||
|
|
||||||
|
linux_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5})
|
||||||
|
-----------------------------------------------------------------
|
||||||
|
rg 0.402 +/- 0.008 (lines: 611)
|
||||||
|
rg (ASCII)* 0.254 +/- 0.010 (lines: 610)*
|
||||||
|
ag (ASCII) 0.934 +/- 0.008 (lines: 971)
|
||||||
|
git grep 14.591 +/- 0.077 (lines: 611)
|
||||||
|
git grep (ASCII) 3.182 +/- 0.035 (lines: 610)
|
||||||
|
ugrep 6.196 +/- 0.052 (lines: 973)
|
||||||
|
ugrep (ASCII) 0.363 +/- 0.004 (lines: 972)
|
||||||
|
|
||||||
|
linux_alternates (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT)
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
rg* 0.142 +/- 0.010 (lines: 112)*
|
||||||
|
ag 0.991 +/- 0.019 (lines: 112)
|
||||||
|
git grep 0.571 +/- 0.011 (lines: 112)
|
||||||
|
ugrep 0.290 +/- 0.017 (lines: 112)
|
||||||
|
|
||||||
|
linux_alternates_casei (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT)
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
rg* 0.226 +/- 0.007 (lines: 203)*
|
||||||
|
ag 0.700 +/- 0.011 (lines: 203)
|
||||||
|
git grep 0.977 +/- 0.011 (lines: 203)
|
||||||
|
ugrep 0.275 +/- 0.005 (lines: 203)
|
||||||
|
|
||||||
|
subtitles_en_literal (pattern: Sherlock Holmes)
|
||||||
|
-----------------------------------------------
|
||||||
|
rg* 0.226 +/- 0.004 (lines: 830)*
|
||||||
|
rg (no mmap) 0.366 +/- 0.005 (lines: 830)
|
||||||
|
grep 0.800 +/- 0.006 (lines: 830)
|
||||||
|
rg (lines) 0.317 +/- 0.016 (lines: 830)
|
||||||
|
ag (lines) 2.547 +/- 0.013 (lines: 830)
|
||||||
|
grep (lines) 1.294 +/- 0.004 (lines: 830)
|
||||||
|
ugrep (lines) 0.404 +/- 0.011 (lines: 830)
|
||||||
|
|
||||||
|
subtitles_en_literal_casei (pattern: Sherlock Holmes)
|
||||||
|
-----------------------------------------------------
|
||||||
|
rg* 0.398 +/- 0.024 (lines: 871)*
|
||||||
|
grep 3.621 +/- 0.016 (lines: 871)
|
||||||
|
grep (ASCII) 0.938 +/- 0.020 (lines: 871)
|
||||||
|
rg (lines) 0.514 +/- 0.016 (lines: 871)
|
||||||
|
ag (lines) (ASCII) 2.595 +/- 0.030 (lines: 871)
|
||||||
|
ugrep (lines) 1.103 +/- 0.008 (lines: 871)
|
||||||
|
|
||||||
|
subtitles_en_literal_word (pattern: Sherlock Holmes)
|
||||||
|
----------------------------------------------------
|
||||||
|
rg (ASCII)* 0.317 +/- 0.007 (lines: 830)*
|
||||||
|
ag (ASCII) 2.584 +/- 0.022 (lines: 830)
|
||||||
|
grep (ASCII) 1.319 +/- 0.018 (lines: 830)
|
||||||
|
ugrep (ASCII) 0.414 +/- 0.004 (lines: 830)
|
||||||
|
rg 0.323 +/- 0.005 (lines: 830)
|
||||||
|
grep 1.317 +/- 0.023 (lines: 830)
|
||||||
|
|
||||||
|
subtitles_en_alternate (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty)
|
||||||
|
---------------------------------------------------------------------------------------------------------------
|
||||||
|
rg (lines) 0.429 +/- 0.027 (lines: 1094)
|
||||||
|
ag (lines) 3.608 +/- 0.036 (lines: 1094)
|
||||||
|
grep (lines) 3.325 +/- 0.017 (lines: 1094)
|
||||||
|
ugrep (lines) 1.133 +/- 0.045 (lines: 1094)
|
||||||
|
rg* 0.305 +/- 0.014 (lines: 1094)*
|
||||||
|
grep 2.821 +/- 0.013 (lines: 1094)
|
||||||
|
|
||||||
|
subtitles_en_alternate_casei (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty)
|
||||||
|
---------------------------------------------------------------------------------------------------------------------
|
||||||
|
ag (ASCII) 6.181 +/- 0.018 (lines: 1136)
|
||||||
|
grep (ASCII) 5.527 +/- 0.022 (lines: 1136)
|
||||||
|
ugrep (ASCII) 1.108 +/- 0.007 (lines: 1136)
|
||||||
|
rg* 0.799 +/- 0.042 (lines: 1136)*
|
||||||
|
grep 5.573 +/- 0.095 (lines: 1136)
|
||||||
|
|
||||||
|
subtitles_en_surrounding_words (pattern: \w+\s+Holmes\s+\w+)
|
||||||
|
------------------------------------------------------------
|
||||||
|
rg* 0.335 +/- 0.008 (lines: 483)
|
||||||
|
grep 1.764 +/- 0.028 (lines: 483)
|
||||||
|
ugrep 70.234 +/- 0.200 (lines: 489)
|
||||||
|
rg (ASCII) 0.329 +/- 0.002 (lines: 483)*
|
||||||
|
ag (ASCII) 7.418 +/- 0.182 (lines: 489)
|
||||||
|
grep (ASCII) 1.763 +/- 0.017 (lines: 483)
|
||||||
|
ugrep (ASCII) 31.230 +/- 0.176 (lines: 489)
|
||||||
|
|
||||||
|
subtitles_en_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5})
|
||||||
|
----------------------------------------------------------------------------------------
|
||||||
|
rg 2.898 +/- 0.026 (lines: 22)
|
||||||
|
ugrep 24.659 +/- 0.069 (lines: 309)
|
||||||
|
rg (ASCII)* 2.669 +/- 0.007 (lines: 22)*
|
||||||
|
ag (ASCII) 10.764 +/- 0.018 (lines: 302)
|
||||||
|
grep (ASCII) 6.258 +/- 0.018 (lines: 22)
|
||||||
|
ugrep (ASCII) 4.687 +/- 0.021 (lines: 302)
|
||||||
|
|
||||||
|
subtitles_ru_literal (pattern: Шерлок Холмс)
|
||||||
|
--------------------------------------------
|
||||||
|
rg* 0.215 +/- 0.018 (lines: 583)*
|
||||||
|
rg (no mmap) 0.320 +/- 0.005 (lines: 583)
|
||||||
|
grep 0.748 +/- 0.039 (lines: 583)
|
||||||
|
rg (lines) 0.282 +/- 0.004 (lines: 583)
|
||||||
|
ag (lines) 2.704 +/- 0.040 (lines: 583)
|
||||||
|
grep (lines) 1.093 +/- 0.009 (lines: 583)
|
||||||
|
ugrep (lines) 1.841 +/- 0.006 (lines: 583)
|
||||||
|
|
||||||
|
subtitles_ru_literal_casei (pattern: Шерлок Холмс)
|
||||||
|
--------------------------------------------------
|
||||||
|
rg* 0.484 +/- 0.002 (lines: 604)*
|
||||||
|
grep 6.709 +/- 0.029 (lines: 604)
|
||||||
|
grep (ASCII) 0.732 +/- 0.005 (lines: 583)
|
||||||
|
rg (lines) 0.556 +/- 0.032 (lines: 604)
|
||||||
|
ag (lines) (ASCII) 0.623 +/- 0.035 (lines: 0)
|
||||||
|
ugrep (lines) (ASCII) 1.835 +/- 0.003 (lines: 583)
|
||||||
|
|
||||||
|
subtitles_ru_literal_word (pattern: Шерлок Холмс)
|
||||||
|
-------------------------------------------------
|
||||||
|
rg (ASCII)* 0.283 +/- 0.006 (lines: 583)*
|
||||||
|
ag (ASCII) 0.673 +/- 0.014 (lines: 0)
|
||||||
|
grep (ASCII) 1.104 +/- 0.009 (lines: 583)
|
||||||
|
ugrep (ASCII) 1.872 +/- 0.032 (lines: 0)
|
||||||
|
rg 0.304 +/- 0.019 (lines: 579)
|
||||||
|
grep 1.100 +/- 0.006 (lines: 579)
|
||||||
|
|
||||||
|
subtitles_ru_alternate (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти)
|
||||||
|
-----------------------------------------------------------------------------------------------------------
|
||||||
|
rg (lines) 0.896 +/- 0.009 (lines: 691)
|
||||||
|
ag (lines) 3.715 +/- 0.032 (lines: 691)
|
||||||
|
grep (lines) 8.423 +/- 0.057 (lines: 691)
|
||||||
|
ugrep (lines) 13.250 +/- 0.056 (lines: 691)
|
||||||
|
rg* 0.853 +/- 0.022 (lines: 691)*
|
||||||
|
grep 8.073 +/- 0.105 (lines: 691)
|
||||||
|
|
||||||
|
subtitles_ru_alternate_casei (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти)
|
||||||
|
-----------------------------------------------------------------------------------------------------------------
|
||||||
|
ag (ASCII)* 3.685 +/- 0.024 (lines: 691)*
|
||||||
|
grep (ASCII) 8.422 +/- 0.024 (lines: 691)
|
||||||
|
ugrep (ASCII) 13.320 +/- 0.110 (lines: 691)
|
||||||
|
rg 6.162 +/- 0.024 (lines: 735)
|
||||||
|
grep 7.495 +/- 0.021 (lines: 735)
|
||||||
|
|
||||||
|
subtitles_ru_surrounding_words (pattern: \w+\s+Холмс\s+\w+)
|
||||||
|
-----------------------------------------------------------
|
||||||
|
rg* 0.310 +/- 0.020 (lines: 278)*
|
||||||
|
grep 1.419 +/- 0.002 (lines: 278)
|
||||||
|
ugrep 70.802 +/- 0.292 (lines: 326)
|
||||||
|
ag (ASCII) 1.873 +/- 0.008 (lines: 0)
|
||||||
|
grep (ASCII) 1.401 +/- 0.036 (lines: 0)
|
||||||
|
ugrep (ASCII) 1.281 +/- 0.013 (lines: 0)
|
||||||
|
|
||||||
|
subtitles_ru_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5})
|
||||||
|
----------------------------------------------------------------------------------------
|
||||||
|
rg 3.098 +/- 0.025 (lines: 41)
|
||||||
|
ugrep 50.840 +/- 0.032 (lines: 86)
|
||||||
|
rg (ASCII) 2.728 +/- 0.019 (lines: 0)
|
||||||
|
ag (ASCII) 1.902 +/- 0.014 (lines: 0)
|
||||||
|
grep (ASCII) 1.758 +/- 0.009 (lines: 0)
|
||||||
|
ugrep (ASCII)* 1.193 +/- 0.016 (lines: 0)*
|
||||||
38
benchsuite/runs/2022-12-16-archlinux-duff/README.md
Normal file
38
benchsuite/runs/2022-12-16-archlinux-duff/README.md
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
This directory contains updated benchmarks as of 2022-12-16. They were captured
|
||||||
|
via the benchsuite script at `benchsuite/benchsuite` from the root of this
|
||||||
|
repository. The command that was run:
|
||||||
|
|
||||||
|
$ ./benchsuite \
|
||||||
|
--dir /dev/shm/benchsuite \
|
||||||
|
--raw runs/2022-12-16-archlinux-duff/raw.csv \
|
||||||
|
| tee runs/2022-12-16-archlinux-duff/summary
|
||||||
|
|
||||||
|
The versions of each tool are as follows:
|
||||||
|
|
||||||
|
$ rg --version
|
||||||
|
ripgrep 13.0.0 (rev 87c4a2b4b1)
|
||||||
|
-SIMD -AVX (compiled)
|
||||||
|
+SIMD +AVX (runtime)
|
||||||
|
|
||||||
|
$ grep -V
|
||||||
|
grep (GNU grep) 3.8
|
||||||
|
|
||||||
|
$ ag -V
|
||||||
|
ag version 2.2.0
|
||||||
|
|
||||||
|
Features:
|
||||||
|
+jit +lzma +zlib
|
||||||
|
|
||||||
|
$ git --version
|
||||||
|
git version 2.39.0
|
||||||
|
|
||||||
|
$ ugrep --version
|
||||||
|
ugrep 3.9.2 x86_64-pc-linux-gnu +avx2 +pcre2jit +zlib +bzip2 +lzma +lz4 +zstd
|
||||||
|
License BSD-3-Clause: <https://opensource.org/licenses/BSD-3-Clause>
|
||||||
|
Written by Robert van Engelen and others: <https://github.com/Genivia/ugrep>
|
||||||
|
|
||||||
|
The version of ripgrep used was compiled from source on commit 7f23cd63:
|
||||||
|
|
||||||
|
$ cargo build --release --features 'pcre2'
|
||||||
|
|
||||||
|
This was run on a machine with an Intel i9-12900K with 128GB of memory.
|
||||||
400
benchsuite/runs/2022-12-16-archlinux-duff/raw.csv
Normal file
400
benchsuite/runs/2022-12-16-archlinux-duff/raw.csv
Normal file
@@ -0,0 +1,400 @@
|
|||||||
|
benchmark,warmup_iter,iter,name,command,duration,lines,env
|
||||||
|
linux_literal_default,1,3,rg,rg PM_RESUME,0.08678817749023438,39,
|
||||||
|
linux_literal_default,1,3,rg,rg PM_RESUME,0.08307123184204102,39,
|
||||||
|
linux_literal_default,1,3,rg,rg PM_RESUME,0.08347964286804199,39,
|
||||||
|
linux_literal_default,1,3,ag,ag PM_RESUME,0.2955434322357178,39,
|
||||||
|
linux_literal_default,1,3,ag,ag PM_RESUME,0.2954287528991699,39,
|
||||||
|
linux_literal_default,1,3,ag,ag PM_RESUME,0.2938194274902344,39,
|
||||||
|
linux_literal_default,1,3,git grep,git grep PM_RESUME,0.23198556900024414,39,LC_ALL=en_US.UTF-8
|
||||||
|
linux_literal_default,1,3,git grep,git grep PM_RESUME,0.22356963157653809,39,LC_ALL=en_US.UTF-8
|
||||||
|
linux_literal_default,1,3,git grep,git grep PM_RESUME,0.2189793586730957,39,LC_ALL=en_US.UTF-8
|
||||||
|
linux_literal_default,1,3,ugrep,ugrep -r PM_RESUME ./,0.10710000991821289,39,
|
||||||
|
linux_literal_default,1,3,ugrep,ugrep -r PM_RESUME ./,0.10364222526550293,39,
|
||||||
|
linux_literal_default,1,3,ugrep,ugrep -r PM_RESUME ./,0.1052248477935791,39,
|
||||||
|
linux_literal_default,1,3,grep,grep -r PM_RESUME ./,0.9994468688964844,39,LC_ALL=en_US.UTF-8
|
||||||
|
linux_literal_default,1,3,grep,grep -r PM_RESUME ./,0.9939279556274414,39,LC_ALL=en_US.UTF-8
|
||||||
|
linux_literal_default,1,3,grep,grep -r PM_RESUME ./,0.9957931041717529,39,LC_ALL=en_US.UTF-8
|
||||||
|
linux_literal,1,3,rg,rg -n PM_RESUME,0.08603358268737793,39,
|
||||||
|
linux_literal,1,3,rg,rg -n PM_RESUME,0.0837090015411377,39,
|
||||||
|
linux_literal,1,3,rg,rg -n PM_RESUME,0.08435535430908203,39,
|
||||||
|
linux_literal,1,3,rg (mmap),rg -n --mmap PM_RESUME,0.3215503692626953,39,
|
||||||
|
linux_literal,1,3,rg (mmap),rg -n --mmap PM_RESUME,0.32426929473876953,39,
|
||||||
|
linux_literal,1,3,rg (mmap),rg -n --mmap PM_RESUME,0.3215982913970947,39,
|
||||||
|
linux_literal,1,3,ag (mmap),ag -s PM_RESUME,0.2894856929779053,39,
|
||||||
|
linux_literal,1,3,ag (mmap),ag -s PM_RESUME,0.2892603874206543,39,
|
||||||
|
linux_literal,1,3,ag (mmap),ag -s PM_RESUME,0.29217028617858887,39,
|
||||||
|
linux_literal,1,3,git grep,git grep -I -n PM_RESUME,0.206068754196167,39,LC_ALL=C
|
||||||
|
linux_literal,1,3,git grep,git grep -I -n PM_RESUME,0.2218036651611328,39,LC_ALL=C
|
||||||
|
linux_literal,1,3,git grep,git grep -I -n PM_RESUME,0.20590710639953613,39,LC_ALL=C
|
||||||
|
linux_literal,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n PM_RESUME ./,0.18692874908447266,39,
|
||||||
|
linux_literal,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n PM_RESUME ./,0.19518327713012695,39,
|
||||||
|
linux_literal,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n PM_RESUME ./,0.18577361106872559,39,
|
||||||
|
linux_literal_casei,1,3,rg,rg -n -i PM_RESUME,0.08709383010864258,536,
|
||||||
|
linux_literal_casei,1,3,rg,rg -n -i PM_RESUME,0.08861064910888672,536,
|
||||||
|
linux_literal_casei,1,3,rg,rg -n -i PM_RESUME,0.08769798278808594,536,
|
||||||
|
linux_literal_casei,1,3,rg (mmap),rg -n -i --mmap PM_RESUME,0.3218965530395508,536,
|
||||||
|
linux_literal_casei,1,3,rg (mmap),rg -n -i --mmap PM_RESUME,0.30869364738464355,536,
|
||||||
|
linux_literal_casei,1,3,rg (mmap),rg -n -i --mmap PM_RESUME,0.31044936180114746,536,
|
||||||
|
linux_literal_casei,1,3,ag (mmap),ag -i PM_RESUME,0.2989068031311035,536,
|
||||||
|
linux_literal_casei,1,3,ag (mmap),ag -i PM_RESUME,0.2996039390563965,536,
|
||||||
|
linux_literal_casei,1,3,ag (mmap),ag -i PM_RESUME,0.29817700386047363,536,
|
||||||
|
linux_literal_casei,1,3,git grep,git grep -I -n -i PM_RESUME,0.2122786045074463,536,LC_ALL=C
|
||||||
|
linux_literal_casei,1,3,git grep,git grep -I -n -i PM_RESUME,0.20763754844665527,536,LC_ALL=C
|
||||||
|
linux_literal_casei,1,3,git grep,git grep -I -n -i PM_RESUME,0.220794677734375,536,LC_ALL=C
|
||||||
|
linux_literal_casei,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i PM_RESUME ./,0.17305850982666016,536,
|
||||||
|
linux_literal_casei,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i PM_RESUME ./,0.1745915412902832,536,
|
||||||
|
linux_literal_casei,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i PM_RESUME ./,0.17526865005493164,536,
|
||||||
|
linux_re_literal_suffix,1,3,rg,rg -n [A-Z]+_RESUME,0.08527851104736328,2160,
|
||||||
|
linux_re_literal_suffix,1,3,rg,rg -n [A-Z]+_RESUME,0.08487534523010254,2160,
|
||||||
|
linux_re_literal_suffix,1,3,rg,rg -n [A-Z]+_RESUME,0.0848684310913086,2160,
|
||||||
|
linux_re_literal_suffix,1,3,ag,ag -s [A-Z]+_RESUME,0.37945985794067383,2160,
|
||||||
|
linux_re_literal_suffix,1,3,ag,ag -s [A-Z]+_RESUME,0.36303210258483887,2160,
|
||||||
|
linux_re_literal_suffix,1,3,ag,ag -s [A-Z]+_RESUME,0.36359691619873047,2160,
|
||||||
|
linux_re_literal_suffix,1,3,git grep,git grep -E -I -n [A-Z]+_RESUME,0.9589834213256836,2160,LC_ALL=C
|
||||||
|
linux_re_literal_suffix,1,3,git grep,git grep -E -I -n [A-Z]+_RESUME,0.9206984043121338,2160,LC_ALL=C
|
||||||
|
linux_re_literal_suffix,1,3,git grep,git grep -E -I -n [A-Z]+_RESUME,0.8642933368682861,2160,LC_ALL=C
|
||||||
|
linux_re_literal_suffix,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n [A-Z]+_RESUME ./,0.40503501892089844,2160,
|
||||||
|
linux_re_literal_suffix,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n [A-Z]+_RESUME ./,0.4531714916229248,2160,
|
||||||
|
linux_re_literal_suffix,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n [A-Z]+_RESUME ./,0.4397866725921631,2160,
|
||||||
|
linux_word,1,3,rg,rg -n -w PM_RESUME,0.08639907836914062,9,
|
||||||
|
linux_word,1,3,rg,rg -n -w PM_RESUME,0.08583569526672363,9,
|
||||||
|
linux_word,1,3,rg,rg -n -w PM_RESUME,0.08414363861083984,9,
|
||||||
|
linux_word,1,3,ag,ag -s -w PM_RESUME,0.2853865623474121,9,
|
||||||
|
linux_word,1,3,ag,ag -s -w PM_RESUME,0.2871377468109131,9,
|
||||||
|
linux_word,1,3,ag,ag -s -w PM_RESUME,0.28753662109375,9,
|
||||||
|
linux_word,1,3,git grep,git grep -E -I -n -w PM_RESUME,0.20428204536437988,9,LC_ALL=C
|
||||||
|
linux_word,1,3,git grep,git grep -E -I -n -w PM_RESUME,0.20490717887878418,9,LC_ALL=C
|
||||||
|
linux_word,1,3,git grep,git grep -E -I -n -w PM_RESUME,0.20840072631835938,9,LC_ALL=C
|
||||||
|
linux_word,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n -w PM_RESUME ./,0.18790841102600098,9,
|
||||||
|
linux_word,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n -w PM_RESUME ./,0.18659543991088867,9,
|
||||||
|
linux_word,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n -w PM_RESUME ./,0.19104933738708496,9,
|
||||||
|
linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.19976496696472168,105,
|
||||||
|
linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.20618367195129395,105,
|
||||||
|
linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.19702935218811035,105,
|
||||||
|
linux_unicode_greek,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n \p{Greek} ./,0.17758727073669434,105,
|
||||||
|
linux_unicode_greek,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n \p{Greek} ./,0.17793798446655273,105,
|
||||||
|
linux_unicode_greek,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n \p{Greek} ./,0.1872577667236328,105,
|
||||||
|
linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.19808244705200195,245,
|
||||||
|
linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.1979837417602539,245,
|
||||||
|
linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.1984400749206543,245,
|
||||||
|
linux_unicode_greek_casei,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i \p{Greek} ./,0.1819148063659668,105,
|
||||||
|
linux_unicode_greek_casei,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i \p{Greek} ./,0.17530512809753418,105,
|
||||||
|
linux_unicode_greek_casei,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i \p{Greek} ./,0.17999005317687988,105,
|
||||||
|
linux_unicode_word,1,3,rg,rg -n \wAh,0.08527827262878418,247,
|
||||||
|
linux_unicode_word,1,3,rg,rg -n \wAh,0.08541679382324219,247,
|
||||||
|
linux_unicode_word,1,3,rg,rg -n \wAh,0.08553218841552734,247,
|
||||||
|
linux_unicode_word,1,3,rg (ASCII),rg -n (?-u)\wAh,0.08484745025634766,233,
|
||||||
|
linux_unicode_word,1,3,rg (ASCII),rg -n (?-u)\wAh,0.08466482162475586,233,
|
||||||
|
linux_unicode_word,1,3,rg (ASCII),rg -n (?-u)\wAh,0.08487439155578613,233,
|
||||||
|
linux_unicode_word,1,3,ag (ASCII),ag -s \wAh,0.3061795234680176,233,
|
||||||
|
linux_unicode_word,1,3,ag (ASCII),ag -s \wAh,0.2993617057800293,233,
|
||||||
|
linux_unicode_word,1,3,ag (ASCII),ag -s \wAh,0.29722046852111816,233,
|
||||||
|
linux_unicode_word,1,3,git grep,git grep -E -I -n \wAh,4.257144451141357,247,LC_ALL=en_US.UTF-8
|
||||||
|
linux_unicode_word,1,3,git grep,git grep -E -I -n \wAh,3.852163076400757,247,LC_ALL=en_US.UTF-8
|
||||||
|
linux_unicode_word,1,3,git grep,git grep -E -I -n \wAh,3.8293941020965576,247,LC_ALL=en_US.UTF-8
|
||||||
|
linux_unicode_word,1,3,git grep (ASCII),git grep -E -I -n \wAh,1.647632122039795,233,LC_ALL=C
|
||||||
|
linux_unicode_word,1,3,git grep (ASCII),git grep -E -I -n \wAh,1.6269629001617432,233,LC_ALL=C
|
||||||
|
linux_unicode_word,1,3,git grep (ASCII),git grep -E -I -n \wAh,1.5847914218902588,233,LC_ALL=C
|
||||||
|
linux_unicode_word,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n \wAh ./,0.1802208423614502,247,
|
||||||
|
linux_unicode_word,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n \wAh ./,0.17564702033996582,247,
|
||||||
|
linux_unicode_word,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n \wAh ./,0.1746981143951416,247,
|
||||||
|
linux_unicode_word,1,3,ugrep (ASCII),ugrep -r --ignore-files --no-hidden -I -n -U \wAh ./,0.1799161434173584,233,
|
||||||
|
linux_unicode_word,1,3,ugrep (ASCII),ugrep -r --ignore-files --no-hidden -I -n -U \wAh ./,0.18733000755310059,233,
|
||||||
|
linux_unicode_word,1,3,ugrep (ASCII),ugrep -r --ignore-files --no-hidden -I -n -U \wAh ./,0.18859529495239258,233,
|
||||||
|
linux_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.26203155517578125,721,
|
||||||
|
linux_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2615540027618408,721,
|
||||||
|
linux_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2730247974395752,721,
|
||||||
|
linux_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.19902300834655762,720,
|
||||||
|
linux_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.20034146308898926,720,
|
||||||
|
linux_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.20192813873291016,720,
|
||||||
|
linux_no_literal,1,3,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.8269081115722656,1134,
|
||||||
|
linux_no_literal,1,3,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.8393104076385498,1134,
|
||||||
|
linux_no_literal,1,3,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.8293666839599609,1134,
|
||||||
|
linux_no_literal,1,3,git grep,git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},7.334395408630371,721,LC_ALL=en_US.UTF-8
|
||||||
|
linux_no_literal,1,3,git grep,git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},7.338796854019165,721,LC_ALL=en_US.UTF-8
|
||||||
|
linux_no_literal,1,3,git grep,git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},7.36545991897583,721,LC_ALL=en_US.UTF-8
|
||||||
|
linux_no_literal,1,3,git grep (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},2.1588926315307617,720,LC_ALL=C
|
||||||
|
linux_no_literal,1,3,git grep (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},2.132209062576294,720,LC_ALL=C
|
||||||
|
linux_no_literal,1,3,git grep (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},2.1407439708709717,720,LC_ALL=C
|
||||||
|
linux_no_literal,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} ./,3.410162925720215,723,
|
||||||
|
linux_no_literal,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} ./,3.405057668685913,723,
|
||||||
|
linux_no_literal,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} ./,3.3945884704589844,723,
|
||||||
|
linux_no_literal,1,3,ugrep (ASCII),ugrep -r --ignore-files --no-hidden -I -n -U \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} ./,0.23865604400634766,722,
|
||||||
|
linux_no_literal,1,3,ugrep (ASCII),ugrep -r --ignore-files --no-hidden -I -n -U \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} ./,0.23371148109436035,722,
|
||||||
|
linux_no_literal,1,3,ugrep (ASCII),ugrep -r --ignore-files --no-hidden -I -n -U \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} ./,0.2343149185180664,722,
|
||||||
|
linux_alternates,1,3,rg,rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.08691263198852539,140,
|
||||||
|
linux_alternates,1,3,rg,rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.08707070350646973,140,
|
||||||
|
linux_alternates,1,3,rg,rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.08713960647583008,140,
|
||||||
|
linux_alternates,1,3,ag,ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.32947278022766113,140,
|
||||||
|
linux_alternates,1,3,ag,ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.33203840255737305,140,
|
||||||
|
linux_alternates,1,3,ag,ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.3292670249938965,140,
|
||||||
|
linux_alternates,1,3,git grep,git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.4576725959777832,140,LC_ALL=C
|
||||||
|
linux_alternates,1,3,git grep,git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.41936421394348145,140,LC_ALL=C
|
||||||
|
linux_alternates,1,3,git grep,git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.3639688491821289,140,LC_ALL=C
|
||||||
|
linux_alternates,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT ./,0.17806458473205566,140,
|
||||||
|
linux_alternates,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT ./,0.18224716186523438,140,
|
||||||
|
linux_alternates,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT ./,0.17795038223266602,140,
|
||||||
|
linux_alternates_casei,1,3,rg,rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.12421393394470215,241,
|
||||||
|
linux_alternates_casei,1,3,rg,rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.12235784530639648,241,
|
||||||
|
linux_alternates_casei,1,3,rg,rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.12151455879211426,241,
|
||||||
|
linux_alternates_casei,1,3,ag,ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.529585599899292,241,
|
||||||
|
linux_alternates_casei,1,3,ag,ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5305526256561279,241,
|
||||||
|
linux_alternates_casei,1,3,ag,ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5311264991760254,241,
|
||||||
|
linux_alternates_casei,1,3,git grep,git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.7589735984802246,241,LC_ALL=C
|
||||||
|
linux_alternates_casei,1,3,git grep,git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.7852108478546143,241,LC_ALL=C
|
||||||
|
linux_alternates_casei,1,3,git grep,git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.8308050632476807,241,LC_ALL=C
|
||||||
|
linux_alternates_casei,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT ./,0.17955923080444336,241,
|
||||||
|
linux_alternates_casei,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT ./,0.1745290756225586,241,
|
||||||
|
linux_alternates_casei,1,3,ugrep,ugrep -r --ignore-files --no-hidden -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT ./,0.1773686408996582,241,
|
||||||
|
subtitles_en_literal,1,3,rg,rg Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.1213979721069336,830,
|
||||||
|
subtitles_en_literal,1,3,rg,rg Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.1213991641998291,830,
|
||||||
|
subtitles_en_literal,1,3,rg,rg Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.12620782852172852,830,
|
||||||
|
subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.18207263946533203,830,
|
||||||
|
subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.17281484603881836,830,
|
||||||
|
subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.17368507385253906,830,
|
||||||
|
subtitles_en_literal,1,3,grep,grep Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.560560941696167,830,LC_ALL=C
|
||||||
|
subtitles_en_literal,1,3,grep,grep Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.563499927520752,830,LC_ALL=C
|
||||||
|
subtitles_en_literal,1,3,grep,grep Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.5916609764099121,830,LC_ALL=C
|
||||||
|
subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.19600844383239746,830,
|
||||||
|
subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.18436980247497559,830,
|
||||||
|
subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.18594050407409668,830,
|
||||||
|
subtitles_en_literal,1,3,ag (lines),ag -s Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,1.871025562286377,830,
|
||||||
|
subtitles_en_literal,1,3,ag (lines),ag -s Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,1.8636960983276367,830,
|
||||||
|
subtitles_en_literal,1,3,ag (lines),ag -s Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,1.8680994510650635,830,
|
||||||
|
subtitles_en_literal,1,3,grep (lines),grep -n Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.9978001117706299,830,LC_ALL=C
|
||||||
|
subtitles_en_literal,1,3,grep (lines),grep -n Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.9385361671447754,830,LC_ALL=C
|
||||||
|
subtitles_en_literal,1,3,grep (lines),grep -n Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,1.0036489963531494,830,LC_ALL=C
|
||||||
|
subtitles_en_literal,1,3,ugrep (lines),ugrep -n Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.18918490409851074,830,
|
||||||
|
subtitles_en_literal,1,3,ugrep (lines),ugrep -n Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.1769108772277832,830,
|
||||||
|
subtitles_en_literal,1,3,ugrep (lines),ugrep -n Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.18808293342590332,830,
|
||||||
|
subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.21876287460327148,871,
|
||||||
|
subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.2044692039489746,871,
|
||||||
|
subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.2184743881225586,871,
|
||||||
|
subtitles_en_literal_casei,1,3,grep,grep -i Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,2.224027156829834,871,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_literal_casei,1,3,grep,grep -i Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,2.223188877105713,871,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_literal_casei,1,3,grep,grep -i Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,2.223966598510742,871,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_literal_casei,1,3,grep (ASCII),grep -E -i Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.671149492263794,871,LC_ALL=C
|
||||||
|
subtitles_en_literal_casei,1,3,grep (ASCII),grep -E -i Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.6705749034881592,871,LC_ALL=C
|
||||||
|
subtitles_en_literal_casei,1,3,grep (ASCII),grep -E -i Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.6700258255004883,871,LC_ALL=C
|
||||||
|
subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.2624058723449707,871,
|
||||||
|
subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.25513339042663574,871,
|
||||||
|
subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.26088857650756836,871,
|
||||||
|
subtitles_en_literal_casei,1,3,ag (lines) (ASCII),ag -i Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,1.9144322872161865,871,
|
||||||
|
subtitles_en_literal_casei,1,3,ag (lines) (ASCII),ag -i Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,1.866628885269165,871,
|
||||||
|
subtitles_en_literal_casei,1,3,ag (lines) (ASCII),ag -i Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,1.9098389148712158,871,
|
||||||
|
subtitles_en_literal_casei,1,3,ugrep (lines),ugrep -n -i Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.7860472202301025,871,
|
||||||
|
subtitles_en_literal_casei,1,3,ugrep (lines),ugrep -n -i Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.7858343124389648,871,
|
||||||
|
subtitles_en_literal_casei,1,3,ugrep (lines),ugrep -n -i Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.782252311706543,871,
|
||||||
|
subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /dev/shm/benchsuite/subtitles/en.sample.txt,0.18424677848815918,830,
|
||||||
|
subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /dev/shm/benchsuite/subtitles/en.sample.txt,0.19610810279846191,830,
|
||||||
|
subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /dev/shm/benchsuite/subtitles/en.sample.txt,0.18711471557617188,830,
|
||||||
|
subtitles_en_literal_word,1,3,ag (ASCII),ag -sw Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,1.8301315307617188,830,
|
||||||
|
subtitles_en_literal_word,1,3,ag (ASCII),ag -sw Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,1.8689801692962646,830,
|
||||||
|
subtitles_en_literal_word,1,3,ag (ASCII),ag -sw Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,1.8279321193695068,830,
|
||||||
|
subtitles_en_literal_word,1,3,grep (ASCII),grep -nw Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,1.0036842823028564,830,LC_ALL=C
|
||||||
|
subtitles_en_literal_word,1,3,grep (ASCII),grep -nw Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,1.002833604812622,830,LC_ALL=C
|
||||||
|
subtitles_en_literal_word,1,3,grep (ASCII),grep -nw Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.9236147403717041,830,LC_ALL=C
|
||||||
|
subtitles_en_literal_word,1,3,ugrep (ASCII),ugrep -nw Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.17717313766479492,830,
|
||||||
|
subtitles_en_literal_word,1,3,ugrep (ASCII),ugrep -nw Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.18994617462158203,830,
|
||||||
|
subtitles_en_literal_word,1,3,ugrep (ASCII),ugrep -nw Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.17972850799560547,830,
|
||||||
|
subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.18804550170898438,830,
|
||||||
|
subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.18867778778076172,830,
|
||||||
|
subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.19913530349731445,830,
|
||||||
|
subtitles_en_literal_word,1,3,grep,grep -nw Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,1.0044364929199219,830,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_literal_word,1,3,grep,grep -nw Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,1.0040032863616943,830,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_literal_word,1,3,grep,grep -nw Sherlock Holmes /dev/shm/benchsuite/subtitles/en.sample.txt,0.9627983570098877,830,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,0.24848055839538574,1094,
|
||||||
|
subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,0.24738383293151855,1094,
|
||||||
|
subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,0.24789118766784668,1094,
|
||||||
|
subtitles_en_alternate,1,3,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,2.668708562850952,1094,
|
||||||
|
subtitles_en_alternate,1,3,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,2.57511305809021,1094,
|
||||||
|
subtitles_en_alternate,1,3,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,2.6714110374450684,1094,
|
||||||
|
subtitles_en_alternate,1,3,grep (lines),grep -E -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,2.0586187839508057,1094,LC_ALL=C
|
||||||
|
subtitles_en_alternate,1,3,grep (lines),grep -E -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,2.0227150917053223,1094,LC_ALL=C
|
||||||
|
subtitles_en_alternate,1,3,grep (lines),grep -E -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,2.075378179550171,1094,LC_ALL=C
|
||||||
|
subtitles_en_alternate,1,3,ugrep (lines),ugrep -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,0.7863781452178955,1094,
|
||||||
|
subtitles_en_alternate,1,3,ugrep (lines),ugrep -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,0.7874250411987305,1094,
|
||||||
|
subtitles_en_alternate,1,3,ugrep (lines),ugrep -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,0.7867889404296875,1094,
|
||||||
|
subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,0.18195557594299316,1094,
|
||||||
|
subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,0.18239641189575195,1094,
|
||||||
|
subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,0.1625690460205078,1094,
|
||||||
|
subtitles_en_alternate,1,3,grep,grep -E Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,1.6601614952087402,1094,LC_ALL=C
|
||||||
|
subtitles_en_alternate,1,3,grep,grep -E Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,1.6617567539215088,1094,LC_ALL=C
|
||||||
|
subtitles_en_alternate,1,3,grep,grep -E Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,1.6584677696228027,1094,LC_ALL=C
|
||||||
|
subtitles_en_alternate_casei,1,3,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,4.0028722286224365,1136,
|
||||||
|
subtitles_en_alternate_casei,1,3,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,3.991217851638794,1136,
|
||||||
|
subtitles_en_alternate_casei,1,3,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,4.00272274017334,1136,
|
||||||
|
subtitles_en_alternate_casei,1,3,grep (ASCII),grep -E -ni Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,3.549154758453369,1136,LC_ALL=C
|
||||||
|
subtitles_en_alternate_casei,1,3,grep (ASCII),grep -E -ni Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,3.5468921661376953,1136,LC_ALL=C
|
||||||
|
subtitles_en_alternate_casei,1,3,grep (ASCII),grep -E -ni Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,3.5873491764068604,1136,LC_ALL=C
|
||||||
|
subtitles_en_alternate_casei,1,3,ugrep (ASCII),ugrep -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,0.7872169017791748,1136,
|
||||||
|
subtitles_en_alternate_casei,1,3,ugrep (ASCII),ugrep -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,0.784674882888794,1136,
|
||||||
|
subtitles_en_alternate_casei,1,3,ugrep (ASCII),ugrep -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,0.7882401943206787,1136,
|
||||||
|
subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,0.4785435199737549,1136,
|
||||||
|
subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,0.4940922260284424,1136,
|
||||||
|
subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,0.4774627685546875,1136,
|
||||||
|
subtitles_en_alternate_casei,1,3,grep,grep -E -ni Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,3.5677175521850586,1136,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_alternate_casei,1,3,grep,grep -E -ni Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,3.603273391723633,1136,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_en_alternate_casei,1,3,grep,grep -E -ni Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /dev/shm/benchsuite/subtitles/en.sample.txt,3.5834741592407227,1136,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,0.20238041877746582,278,
|
||||||
|
subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,0.2031264305114746,278,
|
||||||
|
subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,0.20475172996520996,278,
|
||||||
|
subtitles_ru_surrounding_words,1,3,grep,grep -E -n \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,1.0288453102111816,278,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_surrounding_words,1,3,grep,grep -E -n \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,1.044802188873291,278,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_surrounding_words,1,3,grep,grep -E -n \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,1.0432109832763672,278,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_surrounding_words,1,3,ugrep,ugrep -an \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,43.00765633583069,278,
|
||||||
|
subtitles_ru_surrounding_words,1,3,ugrep,ugrep -an \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,42.832849740982056,278,
|
||||||
|
subtitles_ru_surrounding_words,1,3,ugrep,ugrep -an \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,42.915205240249634,278,
|
||||||
|
subtitles_ru_surrounding_words,1,3,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,1.083683967590332,,
|
||||||
|
subtitles_ru_surrounding_words,1,3,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,1.0841526985168457,,
|
||||||
|
subtitles_ru_surrounding_words,1,3,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,1.0850934982299805,,
|
||||||
|
subtitles_ru_surrounding_words,1,3,grep (ASCII),grep -E -n \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,1.0116353034973145,,LC_ALL=C
|
||||||
|
subtitles_ru_surrounding_words,1,3,grep (ASCII),grep -E -n \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,0.9868073463439941,,LC_ALL=C
|
||||||
|
subtitles_ru_surrounding_words,1,3,grep (ASCII),grep -E -n \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,1.0224814414978027,,LC_ALL=C
|
||||||
|
subtitles_ru_surrounding_words,1,3,ugrep (ASCII),ugrep -a -n -U \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,0.8892502784729004,,
|
||||||
|
subtitles_ru_surrounding_words,1,3,ugrep (ASCII),ugrep -a -n -U \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,0.8910088539123535,,
|
||||||
|
subtitles_ru_surrounding_words,1,3,ugrep (ASCII),ugrep -a -n -U \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,0.8897674083709717,,
|
||||||
|
subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/en.sample.txt,2.11850643157959,22,
|
||||||
|
subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/en.sample.txt,2.1359670162200928,22,
|
||||||
|
subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/en.sample.txt,2.103114128112793,22,
|
||||||
|
subtitles_en_no_literal,1,3,ugrep,ugrep -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/en.sample.txt,13.050881385803223,22,
|
||||||
|
subtitles_en_no_literal,1,3,ugrep,ugrep -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/en.sample.txt,13.050772190093994,22,
|
||||||
|
subtitles_en_no_literal,1,3,ugrep,ugrep -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/en.sample.txt,13.05719804763794,22,
|
||||||
|
subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/en.sample.txt,1.9961926937103271,22,
|
||||||
|
subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/en.sample.txt,2.019721508026123,22,
|
||||||
|
subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/en.sample.txt,1.9965126514434814,22,
|
||||||
|
subtitles_en_no_literal,1,3,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/en.sample.txt,6.849602222442627,302,
|
||||||
|
subtitles_en_no_literal,1,3,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/en.sample.txt,6.813834190368652,302,
|
||||||
|
subtitles_en_no_literal,1,3,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/en.sample.txt,6.8263633251190186,302,
|
||||||
|
subtitles_en_no_literal,1,3,grep (ASCII),grep -E -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/en.sample.txt,4.42924165725708,22,LC_ALL=C
|
||||||
|
subtitles_en_no_literal,1,3,grep (ASCII),grep -E -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/en.sample.txt,4.378557205200195,22,LC_ALL=C
|
||||||
|
subtitles_en_no_literal,1,3,grep (ASCII),grep -E -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/en.sample.txt,4.376646518707275,22,LC_ALL=C
|
||||||
|
subtitles_en_no_literal,1,3,ugrep (ASCII),ugrep -n -U \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/en.sample.txt,3.5110037326812744,22,
|
||||||
|
subtitles_en_no_literal,1,3,ugrep (ASCII),ugrep -n -U \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/en.sample.txt,3.5137360095977783,22,
|
||||||
|
subtitles_en_no_literal,1,3,ugrep (ASCII),ugrep -n -U \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/en.sample.txt,3.5051844120025635,22,
|
||||||
|
subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.13207745552062988,583,
|
||||||
|
subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.13084721565246582,583,
|
||||||
|
subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.13469862937927246,583,
|
||||||
|
subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.18022370338439941,583,
|
||||||
|
subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.1801767349243164,583,
|
||||||
|
subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.17995166778564453,583,
|
||||||
|
subtitles_ru_literal,1,3,grep,grep Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.5151040554046631,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal,1,3,grep,grep Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.5154542922973633,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal,1,3,grep,grep Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.49927639961242676,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.19464492797851562,583,
|
||||||
|
subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.18920588493347168,583,
|
||||||
|
subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.19465351104736328,583,
|
||||||
|
subtitles_ru_literal,1,3,ag (lines),ag -s Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,1.9595966339111328,583,
|
||||||
|
subtitles_ru_literal,1,3,ag (lines),ag -s Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,2.0014493465423584,583,
|
||||||
|
subtitles_ru_literal,1,3,ag (lines),ag -s Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,1.9567768573760986,583,
|
||||||
|
subtitles_ru_literal,1,3,grep (lines),grep -n Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.8119180202484131,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal,1,3,grep (lines),grep -n Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.8111097812652588,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal,1,3,grep (lines),grep -n Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.8006868362426758,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal,1,3,ugrep (lines),ugrep -a -n Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.70003342628479,583,
|
||||||
|
subtitles_ru_literal,1,3,ugrep (lines),ugrep -a -n Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.650275468826294,583,
|
||||||
|
subtitles_ru_literal,1,3,ugrep (lines),ugrep -a -n Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.689772367477417,583,
|
||||||
|
subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.267578125,604,
|
||||||
|
subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.2665982246398926,604,
|
||||||
|
subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.26861572265625,604,
|
||||||
|
subtitles_ru_literal_casei,1,3,grep,grep -i Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,4.764627456665039,604,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_literal_casei,1,3,grep,grep -i Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,4.767015695571899,604,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_literal_casei,1,3,grep,grep -i Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,4.7688889503479,604,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_literal_casei,1,3,grep (ASCII),grep -E -i Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.5046737194061279,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal_casei,1,3,grep (ASCII),grep -E -i Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.5139875411987305,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal_casei,1,3,grep (ASCII),grep -E -i Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.4993159770965576,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.33438658714294434,604,
|
||||||
|
subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.3398289680480957,604,
|
||||||
|
subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.3298227787017822,604,
|
||||||
|
subtitles_ru_literal_casei,1,3,ag (lines) (ASCII),ag -i Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.4468214511871338,,
|
||||||
|
subtitles_ru_literal_casei,1,3,ag (lines) (ASCII),ag -i Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.44559574127197266,,
|
||||||
|
subtitles_ru_literal_casei,1,3,ag (lines) (ASCII),ag -i Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.47882938385009766,,
|
||||||
|
subtitles_ru_literal_casei,1,3,ugrep (lines) (ASCII),ugrep -a -n -i Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.7039575576782227,583,
|
||||||
|
subtitles_ru_literal_casei,1,3,ugrep (lines) (ASCII),ugrep -a -n -i Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.6490752696990967,583,
|
||||||
|
subtitles_ru_literal_casei,1,3,ugrep (lines) (ASCII),ugrep -a -n -i Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.8081104755401611,583,
|
||||||
|
subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:^|\W)Шерлок Холмс(?-u:$|\W) /dev/shm/benchsuite/subtitles/ru.txt,0.20162224769592285,583,
|
||||||
|
subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:^|\W)Шерлок Холмс(?-u:$|\W) /dev/shm/benchsuite/subtitles/ru.txt,0.18215250968933105,583,
|
||||||
|
subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:^|\W)Шерлок Холмс(?-u:$|\W) /dev/shm/benchsuite/subtitles/ru.txt,0.20087671279907227,583,
|
||||||
|
subtitles_ru_literal_word,1,3,ag (ASCII),ag -sw Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.48624587059020996,,
|
||||||
|
subtitles_ru_literal_word,1,3,ag (ASCII),ag -sw Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.5212516784667969,,
|
||||||
|
subtitles_ru_literal_word,1,3,ag (ASCII),ag -sw Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.520557165145874,,
|
||||||
|
subtitles_ru_literal_word,1,3,grep (ASCII),grep -nw Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.8108196258544922,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal_word,1,3,grep (ASCII),grep -nw Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.8121066093444824,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal_word,1,3,grep (ASCII),grep -nw Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.7784581184387207,583,LC_ALL=C
|
||||||
|
subtitles_ru_literal_word,1,3,ugrep (ASCII),ugrep -anw Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.7469344139099121,583,
|
||||||
|
subtitles_ru_literal_word,1,3,ugrep (ASCII),ugrep -anw Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.6838233470916748,583,
|
||||||
|
subtitles_ru_literal_word,1,3,ugrep (ASCII),ugrep -anw Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.6921679973602295,583,
|
||||||
|
subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.19918251037597656,579,
|
||||||
|
subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.2046656608581543,579,
|
||||||
|
subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.1984848976135254,579,
|
||||||
|
subtitles_ru_literal_word,1,3,grep,grep -nw Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.794173002243042,579,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_literal_word,1,3,grep,grep -nw Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.7715346813201904,579,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_literal_word,1,3,grep,grep -nw Шерлок Холмс /dev/shm/benchsuite/subtitles/ru.txt,0.8116705417633057,579,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,0.6730976104736328,691,
|
||||||
|
subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,0.7020411491394043,691,
|
||||||
|
subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,0.6693949699401855,691,
|
||||||
|
subtitles_ru_alternate,1,3,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,2.7100515365600586,691,
|
||||||
|
subtitles_ru_alternate,1,3,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,2.7458419799804688,691,
|
||||||
|
subtitles_ru_alternate,1,3,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,2.7115116119384766,691,
|
||||||
|
subtitles_ru_alternate,1,3,grep (lines),grep -E -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,5.703738451004028,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate,1,3,grep (lines),grep -E -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,5.715883731842041,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate,1,3,grep (lines),grep -E -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,5.712724924087524,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate,1,3,ugrep (lines),ugrep -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,8.276995420455933,691,
|
||||||
|
subtitles_ru_alternate,1,3,ugrep (lines),ugrep -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,8.304608345031738,691,
|
||||||
|
subtitles_ru_alternate,1,3,ugrep (lines),ugrep -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,8.322760820388794,691,
|
||||||
|
subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,0.6119842529296875,691,
|
||||||
|
subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,0.6368775367736816,691,
|
||||||
|
subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,0.6258070468902588,691,
|
||||||
|
subtitles_ru_alternate,1,3,grep,grep -E Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,5.4300291538238525,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate,1,3,grep,grep -E Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,5.418199300765991,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate,1,3,grep,grep -E Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,5.425868511199951,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate_casei,1,3,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,2.7216460704803467,691,
|
||||||
|
subtitles_ru_alternate_casei,1,3,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,2.7108607292175293,691,
|
||||||
|
subtitles_ru_alternate_casei,1,3,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,2.747138500213623,691,
|
||||||
|
subtitles_ru_alternate_casei,1,3,grep (ASCII),grep -E -ni Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,5.711230039596558,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate_casei,1,3,grep (ASCII),grep -E -ni Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,5.709407329559326,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate_casei,1,3,grep (ASCII),grep -E -ni Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,5.714034557342529,691,LC_ALL=C
|
||||||
|
subtitles_ru_alternate_casei,1,3,ugrep (ASCII),ugrep -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,8.305904626846313,691,
|
||||||
|
subtitles_ru_alternate_casei,1,3,ugrep (ASCII),ugrep -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,8.307406187057495,691,
|
||||||
|
subtitles_ru_alternate_casei,1,3,ugrep (ASCII),ugrep -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,8.288233995437622,691,
|
||||||
|
subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,3.673624277114868,735,
|
||||||
|
subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,3.6759188175201416,735,
|
||||||
|
subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,3.66877818107605,735,
|
||||||
|
subtitles_ru_alternate_casei,1,3,grep,grep -E -ni Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,5.366282224655151,735,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_alternate_casei,1,3,grep,grep -E -ni Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,5.370524883270264,735,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_alternate_casei,1,3,grep,grep -E -ni Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /dev/shm/benchsuite/subtitles/ru.txt,5.342163324356079,735,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,0.20331382751464844,278,
|
||||||
|
subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,0.2034592628479004,278,
|
||||||
|
subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,0.20407724380493164,278,
|
||||||
|
subtitles_ru_surrounding_words,1,3,grep,grep -E -n \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,1.0436389446258545,278,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_surrounding_words,1,3,grep,grep -E -n \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,1.0388383865356445,278,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_surrounding_words,1,3,grep,grep -E -n \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,1.0446207523345947,278,LC_ALL=en_US.UTF-8
|
||||||
|
subtitles_ru_surrounding_words,1,3,ugrep,ugrep -n \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,0.29245424270629883,1,
|
||||||
|
subtitles_ru_surrounding_words,1,3,ugrep,ugrep -n \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,0.29168128967285156,1,
|
||||||
|
subtitles_ru_surrounding_words,1,3,ugrep,ugrep -n \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,0.29593825340270996,1,
|
||||||
|
subtitles_ru_surrounding_words,1,3,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,1.085604190826416,,
|
||||||
|
subtitles_ru_surrounding_words,1,3,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,1.083526372909546,,
|
||||||
|
subtitles_ru_surrounding_words,1,3,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,1.1223819255828857,,
|
||||||
|
subtitles_ru_surrounding_words,1,3,grep (ASCII),grep -E -n \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,0.9905192852020264,,LC_ALL=C
|
||||||
|
subtitles_ru_surrounding_words,1,3,grep (ASCII),grep -E -n \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,1.0222513675689697,,LC_ALL=C
|
||||||
|
subtitles_ru_surrounding_words,1,3,grep (ASCII),grep -E -n \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,1.0216262340545654,,LC_ALL=C
|
||||||
|
subtitles_ru_surrounding_words,1,3,ugrep (ASCII),ugrep -a -n -U \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,0.8875806331634521,,
|
||||||
|
subtitles_ru_surrounding_words,1,3,ugrep (ASCII),ugrep -a -n -U \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,0.8861405849456787,,
|
||||||
|
subtitles_ru_surrounding_words,1,3,ugrep (ASCII),ugrep -a -n -U \w+\s+Холмс\s+\w+ /dev/shm/benchsuite/subtitles/ru.txt,0.8898241519927979,,
|
||||||
|
subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/ru.txt,2.237398147583008,41,
|
||||||
|
subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/ru.txt,2.253706693649292,41,
|
||||||
|
subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/ru.txt,2.2161178588867188,41,
|
||||||
|
subtitles_ru_no_literal,1,3,ugrep,ugrep -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/ru.txt,28.85959553718567,41,
|
||||||
|
subtitles_ru_no_literal,1,3,ugrep,ugrep -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/ru.txt,28.666419982910156,41,
|
||||||
|
subtitles_ru_no_literal,1,3,ugrep,ugrep -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/ru.txt,28.90555214881897,41,
|
||||||
|
subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/ru.txt,2.051813840866089,,
|
||||||
|
subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/ru.txt,2.026675224304199,,
|
||||||
|
subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/ru.txt,2.027498245239258,,
|
||||||
|
subtitles_ru_no_literal,1,3,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/ru.txt,1.0998010635375977,,
|
||||||
|
subtitles_ru_no_literal,1,3,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/ru.txt,1.0900018215179443,,
|
||||||
|
subtitles_ru_no_literal,1,3,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/ru.txt,1.0901548862457275,,
|
||||||
|
subtitles_ru_no_literal,1,3,grep (ASCII),grep -E -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/ru.txt,1.0691263675689697,,LC_ALL=C
|
||||||
|
subtitles_ru_no_literal,1,3,grep (ASCII),grep -E -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/ru.txt,1.0875153541564941,,LC_ALL=C
|
||||||
|
subtitles_ru_no_literal,1,3,grep (ASCII),grep -E -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/ru.txt,1.0997354984283447,,LC_ALL=C
|
||||||
|
subtitles_ru_no_literal,1,3,ugrep (ASCII),ugrep -anU \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/ru.txt,0.8329172134399414,,
|
||||||
|
subtitles_ru_no_literal,1,3,ugrep (ASCII),ugrep -anU \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/ru.txt,0.8292679786682129,,
|
||||||
|
subtitles_ru_no_literal,1,3,ugrep (ASCII),ugrep -anU \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /dev/shm/benchsuite/subtitles/ru.txt,0.8326950073242188,,
|
||||||
|
208
benchsuite/runs/2022-12-16-archlinux-duff/summary
Normal file
208
benchsuite/runs/2022-12-16-archlinux-duff/summary
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
linux_literal_default (pattern: PM_RESUME)
|
||||||
|
------------------------------------------
|
||||||
|
rg* 0.084 +/- 0.002 (lines: 39)*
|
||||||
|
ag 0.295 +/- 0.001 (lines: 39)
|
||||||
|
git grep 0.225 +/- 0.007 (lines: 39)
|
||||||
|
ugrep 0.105 +/- 0.002 (lines: 39)
|
||||||
|
grep 0.996 +/- 0.003 (lines: 39)
|
||||||
|
|
||||||
|
linux_literal (pattern: PM_RESUME)
|
||||||
|
----------------------------------
|
||||||
|
rg* 0.085 +/- 0.001 (lines: 39)*
|
||||||
|
rg (mmap) 0.322 +/- 0.002 (lines: 39)
|
||||||
|
ag (mmap) 0.290 +/- 0.002 (lines: 39)
|
||||||
|
git grep 0.211 +/- 0.009 (lines: 39)
|
||||||
|
ugrep 0.189 +/- 0.005 (lines: 39)
|
||||||
|
|
||||||
|
linux_literal_casei (pattern: PM_RESUME)
|
||||||
|
----------------------------------------
|
||||||
|
rg* 0.088 +/- 0.001 (lines: 536)*
|
||||||
|
rg (mmap) 0.314 +/- 0.007 (lines: 536)
|
||||||
|
ag (mmap) 0.299 +/- 0.001 (lines: 536)
|
||||||
|
git grep 0.214 +/- 0.007 (lines: 536)
|
||||||
|
ugrep 0.174 +/- 0.001 (lines: 536)
|
||||||
|
|
||||||
|
linux_re_literal_suffix (pattern: [A-Z]+_RESUME)
|
||||||
|
------------------------------------------------
|
||||||
|
rg* 0.085 +/- 0.000 (lines: 2160)*
|
||||||
|
ag 0.369 +/- 0.009 (lines: 2160)
|
||||||
|
git grep 0.915 +/- 0.048 (lines: 2160)
|
||||||
|
ugrep 0.433 +/- 0.025 (lines: 2160)
|
||||||
|
|
||||||
|
linux_word (pattern: PM_RESUME)
|
||||||
|
-------------------------------
|
||||||
|
rg* 0.085 +/- 0.001 (lines: 9)*
|
||||||
|
ag 0.287 +/- 0.001 (lines: 9)
|
||||||
|
git grep 0.206 +/- 0.002 (lines: 9)
|
||||||
|
ugrep 0.189 +/- 0.002 (lines: 9)
|
||||||
|
|
||||||
|
linux_unicode_greek (pattern: \p{Greek})
|
||||||
|
----------------------------------------
|
||||||
|
rg 0.201 +/- 0.005 (lines: 105)
|
||||||
|
ugrep* 0.181 +/- 0.005 (lines: 105)*
|
||||||
|
|
||||||
|
linux_unicode_greek_casei (pattern: \p{Greek})
|
||||||
|
----------------------------------------------
|
||||||
|
rg 0.198 +/- 0.000 (lines: 245)
|
||||||
|
ugrep* 0.179 +/- 0.003 (lines: 105)*
|
||||||
|
|
||||||
|
linux_unicode_word (pattern: \wAh)
|
||||||
|
----------------------------------
|
||||||
|
rg 0.085 +/- 0.000 (lines: 247)
|
||||||
|
rg (ASCII)* 0.085 +/- 0.000 (lines: 233)*
|
||||||
|
ag (ASCII) 0.301 +/- 0.005 (lines: 233)
|
||||||
|
git grep 3.980 +/- 0.241 (lines: 247)
|
||||||
|
git grep (ASCII) 1.620 +/- 0.032 (lines: 233)
|
||||||
|
ugrep 0.177 +/- 0.003 (lines: 247)
|
||||||
|
ugrep (ASCII) 0.185 +/- 0.005 (lines: 233)
|
||||||
|
|
||||||
|
linux_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5})
|
||||||
|
-----------------------------------------------------------------
|
||||||
|
rg 0.266 +/- 0.006 (lines: 721)
|
||||||
|
rg (ASCII)* 0.200 +/- 0.001 (lines: 720)*
|
||||||
|
ag (ASCII) 0.832 +/- 0.007 (lines: 1134)
|
||||||
|
git grep 7.346 +/- 0.017 (lines: 721)
|
||||||
|
git grep (ASCII) 2.144 +/- 0.014 (lines: 720)
|
||||||
|
ugrep 3.403 +/- 0.008 (lines: 723)
|
||||||
|
ugrep (ASCII) 0.236 +/- 0.003 (lines: 722)
|
||||||
|
|
||||||
|
linux_alternates (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT)
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
rg* 0.087 +/- 0.000 (lines: 140)*
|
||||||
|
ag 0.330 +/- 0.002 (lines: 140)
|
||||||
|
git grep 0.414 +/- 0.047 (lines: 140)
|
||||||
|
ugrep 0.179 +/- 0.002 (lines: 140)
|
||||||
|
|
||||||
|
linux_alternates_casei (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT)
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
rg* 0.123 +/- 0.001 (lines: 241)*
|
||||||
|
ag 0.530 +/- 0.001 (lines: 241)
|
||||||
|
git grep 0.792 +/- 0.036 (lines: 241)
|
||||||
|
ugrep 0.177 +/- 0.003 (lines: 241)
|
||||||
|
|
||||||
|
subtitles_en_literal (pattern: Sherlock Holmes)
|
||||||
|
-----------------------------------------------
|
||||||
|
rg* 0.123 +/- 0.003 (lines: 830)*
|
||||||
|
rg (no mmap) 0.176 +/- 0.005 (lines: 830)
|
||||||
|
grep 0.572 +/- 0.017 (lines: 830)
|
||||||
|
rg (lines) 0.189 +/- 0.006 (lines: 830)
|
||||||
|
ag (lines) 1.868 +/- 0.004 (lines: 830)
|
||||||
|
grep (lines) 0.980 +/- 0.036 (lines: 830)
|
||||||
|
ugrep (lines) 0.185 +/- 0.007 (lines: 830)
|
||||||
|
|
||||||
|
subtitles_en_literal_casei (pattern: Sherlock Holmes)
|
||||||
|
-----------------------------------------------------
|
||||||
|
rg* 0.214 +/- 0.008 (lines: 871)*
|
||||||
|
grep 2.224 +/- 0.000 (lines: 871)
|
||||||
|
grep (ASCII) 0.671 +/- 0.001 (lines: 871)
|
||||||
|
rg (lines) 0.259 +/- 0.004 (lines: 871)
|
||||||
|
ag (lines) (ASCII) 1.897 +/- 0.026 (lines: 871)
|
||||||
|
ugrep (lines) 0.785 +/- 0.002 (lines: 871)
|
||||||
|
|
||||||
|
subtitles_en_literal_word (pattern: Sherlock Holmes)
|
||||||
|
----------------------------------------------------
|
||||||
|
rg (ASCII) 0.189 +/- 0.006 (lines: 830)
|
||||||
|
ag (ASCII) 1.842 +/- 0.023 (lines: 830)
|
||||||
|
grep (ASCII) 0.977 +/- 0.046 (lines: 830)
|
||||||
|
ugrep (ASCII)* 0.182 +/- 0.007 (lines: 830)*
|
||||||
|
rg 0.192 +/- 0.006 (lines: 830)
|
||||||
|
grep 0.990 +/- 0.024 (lines: 830)
|
||||||
|
|
||||||
|
subtitles_en_alternate (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty)
|
||||||
|
---------------------------------------------------------------------------------------------------------------
|
||||||
|
rg (lines) 0.248 +/- 0.001 (lines: 1094)
|
||||||
|
ag (lines) 2.638 +/- 0.055 (lines: 1094)
|
||||||
|
grep (lines) 2.052 +/- 0.027 (lines: 1094)
|
||||||
|
ugrep (lines) 0.787 +/- 0.001 (lines: 1094)
|
||||||
|
rg* 0.176 +/- 0.011 (lines: 1094)*
|
||||||
|
grep 1.660 +/- 0.002 (lines: 1094)
|
||||||
|
|
||||||
|
subtitles_en_alternate_casei (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty)
|
||||||
|
---------------------------------------------------------------------------------------------------------------------
|
||||||
|
ag (ASCII) 3.999 +/- 0.007 (lines: 1136)
|
||||||
|
grep (ASCII) 3.561 +/- 0.023 (lines: 1136)
|
||||||
|
ugrep (ASCII) 0.787 +/- 0.002 (lines: 1136)
|
||||||
|
rg* 0.483 +/- 0.009 (lines: 1136)*
|
||||||
|
grep 3.585 +/- 0.018 (lines: 1136)
|
||||||
|
|
||||||
|
subtitles_en_surrounding_words (pattern: \w+\s+Holmes\s+\w+)
|
||||||
|
------------------------------------------------------------
|
||||||
|
rg 0.200 +/- 0.001 (lines: 483)
|
||||||
|
grep 1.303 +/- 0.040 (lines: 483)
|
||||||
|
ugrep 43.220 +/- 0.047 (lines: 483)
|
||||||
|
rg (ASCII)* 0.197 +/- 0.000 (lines: 483)*
|
||||||
|
ag (ASCII) 5.223 +/- 0.056 (lines: 489)
|
||||||
|
grep (ASCII) 1.316 +/- 0.043 (lines: 483)
|
||||||
|
ugrep (ASCII) 17.647 +/- 0.219 (lines: 483)
|
||||||
|
|
||||||
|
subtitles_en_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5})
|
||||||
|
----------------------------------------------------------------------------------------
|
||||||
|
rg 2.119 +/- 0.016 (lines: 22)
|
||||||
|
ugrep 13.053 +/- 0.004 (lines: 22)
|
||||||
|
rg (ASCII)* 2.004 +/- 0.013 (lines: 22)*
|
||||||
|
ag (ASCII) 6.830 +/- 0.018 (lines: 302)
|
||||||
|
grep (ASCII) 4.395 +/- 0.030 (lines: 22)
|
||||||
|
ugrep (ASCII) 3.510 +/- 0.004 (lines: 22)
|
||||||
|
|
||||||
|
subtitles_ru_literal (pattern: Шерлок Холмс)
|
||||||
|
--------------------------------------------
|
||||||
|
rg* 0.133 +/- 0.002 (lines: 583)*
|
||||||
|
rg (no mmap) 0.180 +/- 0.000 (lines: 583)
|
||||||
|
grep 0.510 +/- 0.009 (lines: 583)
|
||||||
|
rg (lines) 0.193 +/- 0.003 (lines: 583)
|
||||||
|
ag (lines) 1.973 +/- 0.025 (lines: 583)
|
||||||
|
grep (lines) 0.808 +/- 0.006 (lines: 583)
|
||||||
|
ugrep (lines) 0.680 +/- 0.026 (lines: 583)
|
||||||
|
|
||||||
|
subtitles_ru_literal_casei (pattern: Шерлок Холмс)
|
||||||
|
--------------------------------------------------
|
||||||
|
rg* 0.268 +/- 0.001 (lines: 604)*
|
||||||
|
grep 4.767 +/- 0.002 (lines: 604)
|
||||||
|
grep (ASCII) 0.506 +/- 0.007 (lines: 583)
|
||||||
|
rg (lines) 0.335 +/- 0.005 (lines: 604)
|
||||||
|
ag (lines) (ASCII) 0.457 +/- 0.019 (lines: 0)
|
||||||
|
ugrep (lines) (ASCII) 0.720 +/- 0.081 (lines: 583)
|
||||||
|
|
||||||
|
subtitles_ru_literal_word (pattern: Шерлок Холмс)
|
||||||
|
-------------------------------------------------
|
||||||
|
rg (ASCII)* 0.195 +/- 0.011 (lines: 583)*
|
||||||
|
ag (ASCII) 0.509 +/- 0.020 (lines: 0)
|
||||||
|
grep (ASCII) 0.800 +/- 0.019 (lines: 583)
|
||||||
|
ugrep (ASCII) 0.708 +/- 0.034 (lines: 583)
|
||||||
|
rg 0.201 +/- 0.003 (lines: 579)
|
||||||
|
grep 0.792 +/- 0.020 (lines: 579)
|
||||||
|
|
||||||
|
subtitles_ru_alternate (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти)
|
||||||
|
-----------------------------------------------------------------------------------------------------------
|
||||||
|
rg (lines) 0.682 +/- 0.018 (lines: 691)
|
||||||
|
ag (lines) 2.722 +/- 0.020 (lines: 691)
|
||||||
|
grep (lines) 5.711 +/- 0.006 (lines: 691)
|
||||||
|
ugrep (lines) 8.301 +/- 0.023 (lines: 691)
|
||||||
|
rg* 0.625 +/- 0.012 (lines: 691)*
|
||||||
|
grep 5.425 +/- 0.006 (lines: 691)
|
||||||
|
|
||||||
|
subtitles_ru_alternate_casei (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти)
|
||||||
|
-----------------------------------------------------------------------------------------------------------------
|
||||||
|
ag (ASCII)* 2.727 +/- 0.019 (lines: 691)*
|
||||||
|
grep (ASCII) 5.712 +/- 0.002 (lines: 691)
|
||||||
|
ugrep (ASCII) 8.301 +/- 0.011 (lines: 691)
|
||||||
|
rg 3.673 +/- 0.004 (lines: 735)
|
||||||
|
grep 5.360 +/- 0.015 (lines: 735)
|
||||||
|
|
||||||
|
subtitles_ru_surrounding_words (pattern: \w+\s+Холмс\s+\w+)
|
||||||
|
-----------------------------------------------------------
|
||||||
|
rg* 0.203 +/- 0.001 (lines: 278)*
|
||||||
|
grep 1.039 +/- 0.009 (lines: 278)
|
||||||
|
ugrep 42.919 +/- 0.087 (lines: 278)
|
||||||
|
ag (ASCII) 1.084 +/- 0.001 (lines: 0)
|
||||||
|
grep (ASCII) 1.007 +/- 0.018 (lines: 0)
|
||||||
|
ugrep (ASCII) 0.890 +/- 0.001 (lines: 0)
|
||||||
|
|
||||||
|
subtitles_ru_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5})
|
||||||
|
----------------------------------------------------------------------------------------
|
||||||
|
rg 2.236 +/- 0.019 (lines: 41)
|
||||||
|
ugrep 28.811 +/- 0.127 (lines: 41)
|
||||||
|
rg (ASCII) 2.035 +/- 0.014 (lines: 0)
|
||||||
|
ag (ASCII) 1.093 +/- 0.006 (lines: 0)
|
||||||
|
grep (ASCII) 1.085 +/- 0.015 (lines: 0)
|
||||||
|
ugrep (ASCII)* 0.832 +/- 0.002 (lines: 0)*
|
||||||
71
build.rs
71
build.rs
@@ -9,7 +9,7 @@ use clap::Shell;
|
|||||||
use app::{RGArg, RGArgKind};
|
use app::{RGArg, RGArgKind};
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[path = "src/app.rs"]
|
#[path = "crates/core/app.rs"]
|
||||||
mod app;
|
mod app;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@@ -21,7 +21,8 @@ fn main() {
|
|||||||
eprintln!(
|
eprintln!(
|
||||||
"OUT_DIR environment variable not defined. \
|
"OUT_DIR environment variable not defined. \
|
||||||
Please file a bug: \
|
Please file a bug: \
|
||||||
https://github.com/BurntSushi/ripgrep/issues/new");
|
https://github.com/BurntSushi/ripgrep/issues/new"
|
||||||
|
);
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -64,6 +65,51 @@ fn git_revision_hash() -> Option<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn generate_man_page<P: AsRef<Path>>(outdir: P) -> io::Result<()> {
|
fn generate_man_page<P: AsRef<Path>>(outdir: P) -> io::Result<()> {
|
||||||
|
// If asciidoctor isn't installed, fallback to asciidoc.
|
||||||
|
if let Err(err) = process::Command::new("asciidoctor").output() {
|
||||||
|
eprintln!(
|
||||||
|
"Could not run 'asciidoctor' binary, falling back to 'a2x'."
|
||||||
|
);
|
||||||
|
eprintln!("Error from running 'asciidoctor': {}", err);
|
||||||
|
return legacy_generate_man_page::<P>(outdir);
|
||||||
|
}
|
||||||
|
// 1. Read asciidoctor template.
|
||||||
|
// 2. Interpolate template with auto-generated docs.
|
||||||
|
// 3. Save interpolation to disk.
|
||||||
|
// 4. Use asciidoctor to convert to man page.
|
||||||
|
let outdir = outdir.as_ref();
|
||||||
|
let cwd = env::current_dir()?;
|
||||||
|
let tpl_path = cwd.join("doc").join("rg.1.txt.tpl");
|
||||||
|
let txt_path = outdir.join("rg.1.txt");
|
||||||
|
|
||||||
|
let mut tpl = String::new();
|
||||||
|
File::open(&tpl_path)?.read_to_string(&mut tpl)?;
|
||||||
|
let options =
|
||||||
|
formatted_options()?.replace("{", "{").replace("}", "}");
|
||||||
|
tpl = tpl.replace("{OPTIONS}", &options);
|
||||||
|
|
||||||
|
let githash = git_revision_hash();
|
||||||
|
let githash = githash.as_ref().map(|x| &**x);
|
||||||
|
tpl = tpl.replace("{VERSION}", &app::long_version(githash, false));
|
||||||
|
|
||||||
|
File::create(&txt_path)?.write_all(tpl.as_bytes())?;
|
||||||
|
let result = process::Command::new("asciidoctor")
|
||||||
|
.arg("--doctype")
|
||||||
|
.arg("manpage")
|
||||||
|
.arg("--backend")
|
||||||
|
.arg("manpage")
|
||||||
|
.arg(&txt_path)
|
||||||
|
.spawn()?
|
||||||
|
.wait()?;
|
||||||
|
if !result.success() {
|
||||||
|
let msg =
|
||||||
|
format!("'asciidoctor' failed with exit code {:?}", result.code());
|
||||||
|
return Err(ioerr(msg));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn legacy_generate_man_page<P: AsRef<Path>>(outdir: P) -> io::Result<()> {
|
||||||
// If asciidoc isn't installed, then don't do anything.
|
// If asciidoc isn't installed, then don't do anything.
|
||||||
if let Err(err) = process::Command::new("a2x").output() {
|
if let Err(err) = process::Command::new("a2x").output() {
|
||||||
eprintln!("Could not run 'a2x' binary, skipping man page generation.");
|
eprintln!("Could not run 'a2x' binary, skipping man page generation.");
|
||||||
@@ -85,13 +131,15 @@ fn generate_man_page<P: AsRef<Path>>(outdir: P) -> io::Result<()> {
|
|||||||
|
|
||||||
let githash = git_revision_hash();
|
let githash = git_revision_hash();
|
||||||
let githash = githash.as_ref().map(|x| &**x);
|
let githash = githash.as_ref().map(|x| &**x);
|
||||||
tpl = tpl.replace("{VERSION}", &app::long_version(githash));
|
tpl = tpl.replace("{VERSION}", &app::long_version(githash, false));
|
||||||
|
|
||||||
File::create(&txt_path)?.write_all(tpl.as_bytes())?;
|
File::create(&txt_path)?.write_all(tpl.as_bytes())?;
|
||||||
let result = process::Command::new("a2x")
|
let result = process::Command::new("a2x")
|
||||||
.arg("--no-xmllint")
|
.arg("--no-xmllint")
|
||||||
.arg("--doctype").arg("manpage")
|
.arg("--doctype")
|
||||||
.arg("--format").arg("manpage")
|
.arg("manpage")
|
||||||
|
.arg("--format")
|
||||||
|
.arg("manpage")
|
||||||
.arg(&txt_path)
|
.arg(&txt_path)
|
||||||
.spawn()?
|
.spawn()?
|
||||||
.wait()?;
|
.wait()?;
|
||||||
@@ -114,7 +162,7 @@ fn formatted_options() -> io::Result<String> {
|
|||||||
// ripgrep only has two positional arguments, and probably will only
|
// ripgrep only has two positional arguments, and probably will only
|
||||||
// ever have two positional arguments, so we just hardcode them into
|
// ever have two positional arguments, so we just hardcode them into
|
||||||
// the template.
|
// the template.
|
||||||
if let app::RGArgKind::Positional{..} = arg.kind {
|
if let app::RGArgKind::Positional { .. } = arg.kind {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
formatted.push(formatted_arg(&arg)?);
|
formatted.push(formatted_arg(&arg)?);
|
||||||
@@ -124,7 +172,9 @@ fn formatted_options() -> io::Result<String> {
|
|||||||
|
|
||||||
fn formatted_arg(arg: &RGArg) -> io::Result<String> {
|
fn formatted_arg(arg: &RGArg) -> io::Result<String> {
|
||||||
match arg.kind {
|
match arg.kind {
|
||||||
RGArgKind::Positional{..} => panic!("unexpected positional argument"),
|
RGArgKind::Positional { .. } => {
|
||||||
|
panic!("unexpected positional argument")
|
||||||
|
}
|
||||||
RGArgKind::Switch { long, short, multiple } => {
|
RGArgKind::Switch { long, short, multiple } => {
|
||||||
let mut out = vec![];
|
let mut out = vec![];
|
||||||
|
|
||||||
@@ -163,9 +213,14 @@ fn formatted_arg(arg: &RGArg) -> io::Result<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn formatted_doc_txt(arg: &RGArg) -> io::Result<String> {
|
fn formatted_doc_txt(arg: &RGArg) -> io::Result<String> {
|
||||||
let paragraphs: Vec<String> = arg.doc_long
|
let paragraphs: Vec<String> = arg
|
||||||
|
.doc_long
|
||||||
.replace("{", "{")
|
.replace("{", "{")
|
||||||
.replace("}", r"}")
|
.replace("}", r"}")
|
||||||
|
// Hack to render ** literally in man page correctly. We can't put
|
||||||
|
// these crazy +++ in the help text directly, since that shows
|
||||||
|
// literally in --help output.
|
||||||
|
.replace("*-g 'foo/**'*", "*-g +++'foo/**'+++*")
|
||||||
.split("\n\n")
|
.split("\n\n")
|
||||||
.map(|s| s.to_string())
|
.map(|s| s.to_string())
|
||||||
.collect();
|
.collect();
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# package the build artifacts
|
|
||||||
|
|
||||||
set -ex
|
|
||||||
|
|
||||||
. "$(dirname $0)/utils.sh"
|
|
||||||
|
|
||||||
# Generate artifacts for release
|
|
||||||
mk_artifacts() {
|
|
||||||
if is_arm; then
|
|
||||||
cargo build --target "$TARGET" --release
|
|
||||||
else
|
|
||||||
# Technically, MUSL builds will force PCRE2 to get statically compiled,
|
|
||||||
# but we also want PCRE2 statically build for macOS binaries.
|
|
||||||
PCRE2_SYS_STATIC=1 cargo build --target "$TARGET" --release --features 'pcre2'
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
mk_tarball() {
|
|
||||||
# When cross-compiling, use the right `strip` tool on the binary.
|
|
||||||
local gcc_prefix="$(gcc_prefix)"
|
|
||||||
# Create a temporary dir that contains our staging area.
|
|
||||||
# $tmpdir/$name is what eventually ends up as the deployed archive.
|
|
||||||
local tmpdir="$(mktemp -d)"
|
|
||||||
local name="${PROJECT_NAME}-${TRAVIS_TAG}-${TARGET}"
|
|
||||||
local staging="$tmpdir/$name"
|
|
||||||
mkdir -p "$staging"/{complete,doc}
|
|
||||||
# The deployment directory is where the final archive will reside.
|
|
||||||
# This path is known by the .travis.yml configuration.
|
|
||||||
local out_dir="$(pwd)/deployment"
|
|
||||||
mkdir -p "$out_dir"
|
|
||||||
# Find the correct (most recent) Cargo "out" directory. The out directory
|
|
||||||
# contains shell completion files and the man page.
|
|
||||||
local cargo_out_dir="$(cargo_out_dir "target/$TARGET")"
|
|
||||||
|
|
||||||
# Copy the ripgrep binary and strip it.
|
|
||||||
cp "target/$TARGET/release/rg" "$staging/rg"
|
|
||||||
"${gcc_prefix}strip" "$staging/rg"
|
|
||||||
# Copy the licenses and README.
|
|
||||||
cp {README.md,UNLICENSE,COPYING,LICENSE-MIT} "$staging/"
|
|
||||||
# Copy documentation and man page.
|
|
||||||
cp {CHANGELOG.md,FAQ.md,GUIDE.md} "$staging/doc/"
|
|
||||||
if command -V a2x 2>&1 > /dev/null; then
|
|
||||||
# The man page should only exist if we have asciidoc installed.
|
|
||||||
cp "$cargo_out_dir/rg.1" "$staging/doc/"
|
|
||||||
fi
|
|
||||||
# Copy shell completion files.
|
|
||||||
cp "$cargo_out_dir"/{rg.bash,rg.fish,_rg.ps1} "$staging/complete/"
|
|
||||||
cp complete/_rg "$staging/complete/"
|
|
||||||
|
|
||||||
(cd "$tmpdir" && tar czf "$out_dir/$name.tar.gz" "$name")
|
|
||||||
rm -rf "$tmpdir"
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
mk_artifacts
|
|
||||||
mk_tarball
|
|
||||||
}
|
|
||||||
|
|
||||||
main
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
D="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
|
||||||
|
|
||||||
# This script builds a binary dpkg for Debian based distros. It does not
|
# This script builds a binary dpkg for Debian based distros. It does not
|
||||||
# currently run in CI, and is instead run manually and the resulting dpkg is
|
# currently run in CI, and is instead run manually and the resulting dpkg is
|
||||||
@@ -16,28 +17,26 @@ if ! command -V cargo-deb > /dev/null 2>&1; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if ! command -V asciidoctor > /dev/null 2>&1; then
|
||||||
|
echo "asciidoctor command missing" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# 'cargo deb' does not seem to provide a way to specify an asset that is
|
# 'cargo deb' does not seem to provide a way to specify an asset that is
|
||||||
# created at build time, such as ripgrep's man page. To work around this,
|
# created at build time, such as ripgrep's man page. To work around this,
|
||||||
# we force a debug build, copy out the man page (and shell completions)
|
# we force a debug build, copy out the man page (and shell completions)
|
||||||
# produced from that build, put it into a predictable location and then build
|
# produced from that build, put it into a predictable location and then build
|
||||||
# the deb, which knows where to look.
|
# the deb, which knows where to look.
|
||||||
|
|
||||||
DEPLOY_DIR=deployment/deb
|
|
||||||
mkdir -p "$DEPLOY_DIR"
|
|
||||||
cargo build
|
cargo build
|
||||||
|
|
||||||
# Find and copy man page.
|
DEPLOY_DIR=deployment/deb
|
||||||
manpage="$(find ./target/debug -name rg.1 -print0 | xargs -0 ls -t | head -n1)"
|
OUT_DIR="$("$D"/cargo-out-dir target/debug/)"
|
||||||
cp "$manpage" "$DEPLOY_DIR/"
|
mkdir -p "$DEPLOY_DIR"
|
||||||
|
|
||||||
# Do the same for shell completions.
|
# Copy man page and shell completions.
|
||||||
compbash="$(find ./target/debug -name rg.bash -print0 | xargs -0 ls -t | head -n1)"
|
cp "$OUT_DIR"/{rg.1,rg.bash,rg.fish} "$DEPLOY_DIR/"
|
||||||
cp "$compbash" "$DEPLOY_DIR/"
|
cp complete/_rg "$DEPLOY_DIR/"
|
||||||
compfish="$(find ./target/debug -name rg.fish -print0 | xargs -0 ls -t | head -n1)"
|
|
||||||
cp "$compfish" "$DEPLOY_DIR/"
|
|
||||||
compzsh="complete/_rg"
|
|
||||||
cp "$compzsh" "$DEPLOY_DIR/"
|
|
||||||
|
|
||||||
# Since we're distributing the dpkg, we don't know whether the user will have
|
# Since we're distributing the dpkg, we don't know whether the user will have
|
||||||
# PCRE2 installed, so just do a static build.
|
# PCRE2 installed, so just do a static build.
|
||||||
PCRE2_SYS_STATIC=1 cargo deb
|
PCRE2_SYS_STATIC=1 cargo deb --target x86_64-unknown-linux-musl
|
||||||
19
ci/cargo-out-dir
Executable file
19
ci/cargo-out-dir
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Finds Cargo's `OUT_DIR` directory from the most recent build.
|
||||||
|
#
|
||||||
|
# This requires one parameter corresponding to the target directory
|
||||||
|
# to search for the build output.
|
||||||
|
|
||||||
|
if [ $# != 1 ]; then
|
||||||
|
echo "Usage: $(basename "$0") <target-dir>" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# This works by finding the most recent stamp file, which is produced by
|
||||||
|
# every ripgrep build.
|
||||||
|
target_dir="$1"
|
||||||
|
find "$target_dir" -name ripgrep-stamp -print0 \
|
||||||
|
| xargs -0 ls -t \
|
||||||
|
| head -n1 \
|
||||||
|
| xargs dirname
|
||||||
24
ci/docker/README.md
Normal file
24
ci/docker/README.md
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
These are Docker images used for cross compilation in CI builds (or locally)
|
||||||
|
via the [Cross](https://github.com/rust-embedded/cross) tool.
|
||||||
|
|
||||||
|
The Cross tool actually provides its own Docker images, and all Docker images
|
||||||
|
in this directory are derived from one of them. We provide our own in order
|
||||||
|
to customize the environment. For example, we need to install some things like
|
||||||
|
`asciidoctor` in order to generate man pages. We also install compression tools
|
||||||
|
like `xz` so that tests for the `-z/--search-zip` flag are run.
|
||||||
|
|
||||||
|
If you make a change to a Docker image, then you can re-build it. `cd` into the
|
||||||
|
directory containing the `Dockerfile` and run:
|
||||||
|
|
||||||
|
$ cd x86_64-unknown-linux-musl
|
||||||
|
$ ./build
|
||||||
|
|
||||||
|
At this point, subsequent uses of `cross` will now use your built image since
|
||||||
|
Docker prefers local images over remote images. In order to make these changes
|
||||||
|
stick, they need to be pushed to Docker Hub:
|
||||||
|
|
||||||
|
$ docker push burntsushi/cross:x86_64-unknown-linux-musl
|
||||||
|
|
||||||
|
Of course, only I (BurntSushi) can push to that location. To make `cross` use
|
||||||
|
a different location, then edit `Cross.toml` in the root of this repo to use
|
||||||
|
a different image name for the desired target.
|
||||||
4
ci/docker/arm-unknown-linux-gnueabihf/Dockerfile
Normal file
4
ci/docker/arm-unknown-linux-gnueabihf/Dockerfile
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
FROM rustembedded/cross:arm-unknown-linux-gnueabihf
|
||||||
|
|
||||||
|
COPY stage/ubuntu-install-packages /
|
||||||
|
RUN /ubuntu-install-packages
|
||||||
5
ci/docker/arm-unknown-linux-gnueabihf/build
Executable file
5
ci/docker/arm-unknown-linux-gnueabihf/build
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
mkdir -p stage
|
||||||
|
cp ../../ubuntu-install-packages ./stage/
|
||||||
|
docker build -t burntsushi/cross:arm-unknown-linux-gnueabihf .
|
||||||
4
ci/docker/i686-unknown-linux-gnu/Dockerfile
Normal file
4
ci/docker/i686-unknown-linux-gnu/Dockerfile
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
FROM rustembedded/cross:i686-unknown-linux-gnu
|
||||||
|
|
||||||
|
COPY stage/ubuntu-install-packages /
|
||||||
|
RUN /ubuntu-install-packages
|
||||||
5
ci/docker/i686-unknown-linux-gnu/build
Executable file
5
ci/docker/i686-unknown-linux-gnu/build
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
mkdir -p stage
|
||||||
|
cp ../../ubuntu-install-packages ./stage/
|
||||||
|
docker build -t burntsushi/cross:i686-unknown-linux-gnu .
|
||||||
4
ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile
Normal file
4
ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
FROM rustembedded/cross:mips64-unknown-linux-gnuabi64
|
||||||
|
|
||||||
|
COPY stage/ubuntu-install-packages /
|
||||||
|
RUN /ubuntu-install-packages
|
||||||
5
ci/docker/mips64-unknown-linux-gnuabi64/build
Executable file
5
ci/docker/mips64-unknown-linux-gnuabi64/build
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
mkdir -p stage
|
||||||
|
cp ../../ubuntu-install-packages ./stage/
|
||||||
|
docker build -t burntsushi/cross:mips64-unknown-linux-gnuabi64 .
|
||||||
4
ci/docker/x86_64-unknown-linux-musl/Dockerfile
Normal file
4
ci/docker/x86_64-unknown-linux-musl/Dockerfile
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
FROM rustembedded/cross:x86_64-unknown-linux-musl
|
||||||
|
|
||||||
|
COPY stage/ubuntu-install-packages /
|
||||||
|
RUN /ubuntu-install-packages
|
||||||
5
ci/docker/x86_64-unknown-linux-musl/build
Executable file
5
ci/docker/x86_64-unknown-linux-musl/build
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
mkdir -p stage
|
||||||
|
cp ../../ubuntu-install-packages ./stage/
|
||||||
|
docker build -t burntsushi/cross:x86_64-unknown-linux-musl .
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# install stuff needed for the `script` phase
|
|
||||||
|
|
||||||
# Where rustup gets installed.
|
|
||||||
export PATH="$PATH:$HOME/.cargo/bin"
|
|
||||||
|
|
||||||
set -ex
|
|
||||||
|
|
||||||
. "$(dirname $0)/utils.sh"
|
|
||||||
|
|
||||||
install_rustup() {
|
|
||||||
curl https://sh.rustup.rs -sSf \
|
|
||||||
| sh -s -- -y --default-toolchain="$TRAVIS_RUST_VERSION"
|
|
||||||
rustc -V
|
|
||||||
cargo -V
|
|
||||||
}
|
|
||||||
|
|
||||||
install_targets() {
|
|
||||||
if [ $(host) != "$TARGET" ]; then
|
|
||||||
rustup target add $TARGET
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
install_osx_dependencies() {
|
|
||||||
if ! is_osx; then
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
brew install asciidoc docbook-xsl
|
|
||||||
}
|
|
||||||
|
|
||||||
configure_cargo() {
|
|
||||||
local prefix=$(gcc_prefix)
|
|
||||||
if [ -n "${prefix}" ]; then
|
|
||||||
local gcc_suffix=
|
|
||||||
if [ -n "$GCC_VERSION" ]; then
|
|
||||||
gcc_suffix="-$GCC_VERSION"
|
|
||||||
fi
|
|
||||||
local gcc="${prefix}gcc${gcc_suffix}"
|
|
||||||
|
|
||||||
# information about the cross compiler
|
|
||||||
"${gcc}" -v
|
|
||||||
|
|
||||||
# tell cargo which linker to use for cross compilation
|
|
||||||
mkdir -p .cargo
|
|
||||||
cat >>.cargo/config <<EOF
|
|
||||||
[target.$TARGET]
|
|
||||||
linker = "${gcc}"
|
|
||||||
EOF
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
install_osx_dependencies
|
|
||||||
install_rustup
|
|
||||||
install_targets
|
|
||||||
configure_cargo
|
|
||||||
}
|
|
||||||
|
|
||||||
main
|
|
||||||
3
ci/macos-install-packages
Executable file
3
ci/macos-install-packages
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
brew install asciidoctor
|
||||||
50
ci/script.sh
50
ci/script.sh
@@ -1,50 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# build, test and generate docs in this phase
|
|
||||||
|
|
||||||
set -ex
|
|
||||||
|
|
||||||
. "$(dirname $0)/utils.sh"
|
|
||||||
|
|
||||||
main() {
|
|
||||||
# Test a normal debug build.
|
|
||||||
if is_arm; then
|
|
||||||
cargo build --target "$TARGET" --verbose
|
|
||||||
else
|
|
||||||
cargo build --target "$TARGET" --verbose --all --features 'pcre2'
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Show the output of the most recent build.rs stderr.
|
|
||||||
set +x
|
|
||||||
stderr="$(find "target/$TARGET/debug" -name stderr -print0 | xargs -0 ls -t | head -n1)"
|
|
||||||
if [ -s "$stderr" ]; then
|
|
||||||
echo "===== $stderr ====="
|
|
||||||
cat "$stderr"
|
|
||||||
echo "====="
|
|
||||||
fi
|
|
||||||
set -x
|
|
||||||
|
|
||||||
# sanity check the file type
|
|
||||||
file target/"$TARGET"/debug/rg
|
|
||||||
|
|
||||||
# Check that we've generated man page and other shell completions.
|
|
||||||
outdir="$(cargo_out_dir "target/$TARGET/debug")"
|
|
||||||
file "$outdir/rg.bash"
|
|
||||||
file "$outdir/rg.fish"
|
|
||||||
file "$outdir/_rg.ps1"
|
|
||||||
file "$outdir/rg.1"
|
|
||||||
|
|
||||||
# Apparently tests don't work on arm, so just bail now. I guess we provide
|
|
||||||
# ARM releases on a best effort basis?
|
|
||||||
if is_arm; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test that zsh completions are in sync with ripgrep's actual args.
|
|
||||||
"$(dirname "${0}")/test_complete.sh"
|
|
||||||
|
|
||||||
# Run tests for ripgrep and all sub-crates.
|
|
||||||
cargo test --target "$TARGET" --verbose --all --features 'pcre2'
|
|
||||||
}
|
|
||||||
|
|
||||||
main
|
|
||||||
@@ -18,7 +18,7 @@ get_comp_args() {
|
|||||||
|
|
||||||
main() {
|
main() {
|
||||||
local diff
|
local diff
|
||||||
local rg="${0:a:h}/../target/${TARGET:-}/release/rg"
|
local rg="${0:a:h}/../${TARGET_DIR:-target}/release/rg"
|
||||||
local _rg="${0:a:h}/../complete/_rg"
|
local _rg="${0:a:h}/../complete/_rg"
|
||||||
local -a help_args comp_args
|
local -a help_args comp_args
|
||||||
|
|
||||||
@@ -44,8 +44,8 @@ main() {
|
|||||||
# Occasionally we may have to handle some manually, however
|
# Occasionally we may have to handle some manually, however
|
||||||
help_args=( ${(f)"$(
|
help_args=( ${(f)"$(
|
||||||
$rg --help |
|
$rg --help |
|
||||||
$rg -i -- '^\s+--?[a-z0-9]|--[imnp]' |
|
$rg -i -- '^\s+--?[a-z0-9.]|--[a-z]' |
|
||||||
$rg -ior '$1' -- $'[\t /\"\'`.,](-[a-z0-9]|--[a-z0-9-]+)\\b' |
|
$rg -ior '$1' -- $'[\t /\"\'`.,](-[a-z0-9.]|--[a-z0-9-]+)(,|\\b)' |
|
||||||
$rg -v -- --print0 | # False positives
|
$rg -v -- --print0 | # False positives
|
||||||
sort -u
|
sort -u
|
||||||
)"} )
|
)"} )
|
||||||
16
ci/ubuntu-install-packages
Executable file
16
ci/ubuntu-install-packages
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# This script gets run in weird environments that have been stripped of just
|
||||||
|
# about every inessential thing. In order to keep this script versatile, we
|
||||||
|
# just install 'sudo' and use it like normal if it doesn't exist. If it doesn't
|
||||||
|
# exist, we assume we're root. (Otherwise we ain't doing much of anything
|
||||||
|
# anyway.)
|
||||||
|
if ! command -V sudo; then
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y --no-install-recommends sudo
|
||||||
|
fi
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y --no-install-recommends \
|
||||||
|
asciidoctor \
|
||||||
|
zsh xz-utils liblz4-tool musl-tools \
|
||||||
|
brotli zstd
|
||||||
23
ci/utils.sh
23
ci/utils.sh
@@ -55,6 +55,13 @@ gcc_prefix() {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is_musl() {
|
||||||
|
case "$TARGET" in
|
||||||
|
*-musl) return 0 ;;
|
||||||
|
*) return 1 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
is_x86() {
|
is_x86() {
|
||||||
case "$(architecture)" in
|
case "$(architecture)" in
|
||||||
amd64|i386) return 0 ;;
|
amd64|i386) return 0 ;;
|
||||||
@@ -62,6 +69,13 @@ is_x86() {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is_x86_64() {
|
||||||
|
case "$(architecture)" in
|
||||||
|
amd64) return 0 ;;
|
||||||
|
*) return 1 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
is_arm() {
|
is_arm() {
|
||||||
case "$(architecture)" in
|
case "$(architecture)" in
|
||||||
armhf) return 0 ;;
|
armhf) return 0 ;;
|
||||||
@@ -82,3 +96,12 @@ is_osx() {
|
|||||||
*) return 1 ;;
|
*) return 1 ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
builder() {
|
||||||
|
if is_musl && is_x86_64; then
|
||||||
|
cargo install cross
|
||||||
|
echo "cross"
|
||||||
|
else
|
||||||
|
echo "cargo"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|||||||
40
complete/_rg
40
complete/_rg
@@ -3,7 +3,7 @@
|
|||||||
##
|
##
|
||||||
# zsh completion function for ripgrep
|
# zsh completion function for ripgrep
|
||||||
#
|
#
|
||||||
# Run ci/test_complete.sh after building to ensure that the options supported by
|
# Run ci/test-complete after building to ensure that the options supported by
|
||||||
# this function stay in synch with the `rg` binary.
|
# this function stay in synch with the `rg` binary.
|
||||||
#
|
#
|
||||||
# For convenience, a completion reference guide is included at the bottom of
|
# For convenience, a completion reference guide is included at the bottom of
|
||||||
@@ -72,11 +72,19 @@ _rg() {
|
|||||||
+ '(count)' # Counting options
|
+ '(count)' # Counting options
|
||||||
{-c,--count}'[only show count of matching lines for each file]'
|
{-c,--count}'[only show count of matching lines for each file]'
|
||||||
'--count-matches[only show count of individual matches for each file]'
|
'--count-matches[only show count of individual matches for each file]'
|
||||||
|
'--include-zero[include files with zero matches in summary]'
|
||||||
|
|
||||||
+ '(encoding)' # Encoding options
|
+ '(encoding)' # Encoding options
|
||||||
{-E+,--encoding=}'[specify text encoding of files to search]: :_rg_encodings'
|
{-E+,--encoding=}'[specify text encoding of files to search]: :_rg_encodings'
|
||||||
$no'--no-encoding[use default text encoding]'
|
$no'--no-encoding[use default text encoding]'
|
||||||
|
|
||||||
|
+ '(engine)' # Engine choice options
|
||||||
|
'--engine=[select which regex engine to use]:when:((
|
||||||
|
default\:"use default engine"
|
||||||
|
pcre2\:"identical to --pcre2"
|
||||||
|
auto\:"identical to --auto-hybrid-regex"
|
||||||
|
))'
|
||||||
|
|
||||||
+ file # File-input options
|
+ file # File-input options
|
||||||
'(1)*'{-f+,--file=}'[specify file containing patterns to search for]: :_files'
|
'(1)*'{-f+,--file=}'[specify file containing patterns to search for]: :_files'
|
||||||
|
|
||||||
@@ -104,12 +112,16 @@ _rg() {
|
|||||||
'*'{-g+,--glob=}'[include/exclude files matching specified glob]:glob'
|
'*'{-g+,--glob=}'[include/exclude files matching specified glob]:glob'
|
||||||
'*--iglob=[include/exclude files matching specified case-insensitive glob]:glob'
|
'*--iglob=[include/exclude files matching specified case-insensitive glob]:glob'
|
||||||
|
|
||||||
|
+ '(glob-case-insensitive)' # File-glob case sensitivity options
|
||||||
|
'--glob-case-insensitive[treat -g/--glob patterns case insensitively]'
|
||||||
|
$no'--no-glob-case-insensitive[treat -g/--glob patterns case sensitively]'
|
||||||
|
|
||||||
+ '(heading)' # Heading options
|
+ '(heading)' # Heading options
|
||||||
'(pretty-vimgrep)--heading[show matches grouped by file name]'
|
'(pretty-vimgrep)--heading[show matches grouped by file name]'
|
||||||
"(pretty-vimgrep)--no-heading[don't show matches grouped by file name]"
|
"(pretty-vimgrep)--no-heading[don't show matches grouped by file name]"
|
||||||
|
|
||||||
+ '(hidden)' # Hidden-file options
|
+ '(hidden)' # Hidden-file options
|
||||||
'--hidden[search hidden files and directories]'
|
{-.,--hidden}'[search hidden files and directories]'
|
||||||
$no"--no-hidden[don't search hidden files and directories]"
|
$no"--no-hidden[don't search hidden files and directories]"
|
||||||
|
|
||||||
+ '(hybrid)' # hybrid regex options
|
+ '(hybrid)' # hybrid regex options
|
||||||
@@ -124,6 +136,10 @@ _rg() {
|
|||||||
'--ignore-file-case-insensitive[process ignore files case insensitively]'
|
'--ignore-file-case-insensitive[process ignore files case insensitively]'
|
||||||
$no'--no-ignore-file-case-insensitive[process ignore files case sensitively]'
|
$no'--no-ignore-file-case-insensitive[process ignore files case sensitively]'
|
||||||
|
|
||||||
|
+ '(ignore-exclude)' # Local exclude (ignore)-file options
|
||||||
|
"--no-ignore-exclude[don't respect local exclude (ignore) files]"
|
||||||
|
$no'--ignore-exclude[respect local exclude (ignore) files]'
|
||||||
|
|
||||||
+ '(ignore-global)' # Global ignore-file options
|
+ '(ignore-global)' # Global ignore-file options
|
||||||
"--no-ignore-global[don't respect global ignore files]"
|
"--no-ignore-global[don't respect global ignore files]"
|
||||||
$no'--ignore-global[respect global ignore files]'
|
$no'--ignore-global[respect global ignore files]'
|
||||||
@@ -136,10 +152,18 @@ _rg() {
|
|||||||
"--no-ignore-vcs[don't respect version control ignore files]"
|
"--no-ignore-vcs[don't respect version control ignore files]"
|
||||||
$no'--ignore-vcs[respect version control ignore files]'
|
$no'--ignore-vcs[respect version control ignore files]'
|
||||||
|
|
||||||
+ '(ignore-dot)' # .ignore-file options
|
+ '(require-git)' # git specific settings
|
||||||
|
"--no-require-git[don't require git repository to respect gitignore rules]"
|
||||||
|
$no'--require-git[require git repository to respect gitignore rules]'
|
||||||
|
|
||||||
|
+ '(ignore-dot)' # .ignore options
|
||||||
"--no-ignore-dot[don't respect .ignore files]"
|
"--no-ignore-dot[don't respect .ignore files]"
|
||||||
$no'--ignore-dot[respect .ignore files]'
|
$no'--ignore-dot[respect .ignore files]'
|
||||||
|
|
||||||
|
+ '(ignore-files)' # custom global ignore file options
|
||||||
|
"--no-ignore-files[don't respect --ignore-file flags]"
|
||||||
|
$no'--ignore-files[respect --ignore-file files]'
|
||||||
|
|
||||||
+ '(json)' # JSON options
|
+ '(json)' # JSON options
|
||||||
'--json[output results in JSON Lines format]'
|
'--json[output results in JSON Lines format]'
|
||||||
$no"--no-json[don't output results in JSON Lines format]"
|
$no"--no-json[don't output results in JSON Lines format]"
|
||||||
@@ -259,6 +283,10 @@ _rg() {
|
|||||||
{-w,--word-regexp}'[only show matches surrounded by word boundaries]'
|
{-w,--word-regexp}'[only show matches surrounded by word boundaries]'
|
||||||
{-x,--line-regexp}'[only show matches surrounded by line boundaries]'
|
{-x,--line-regexp}'[only show matches surrounded by line boundaries]'
|
||||||
|
|
||||||
|
+ '(unicode)' # Unicode options
|
||||||
|
$no'--unicode[enable Unicode mode]'
|
||||||
|
'--no-unicode[disable Unicode mode]'
|
||||||
|
|
||||||
+ '(zip)' # Compression options
|
+ '(zip)' # Compression options
|
||||||
'(--pre)'{-z,--search-zip}'[search in compressed files]'
|
'(--pre)'{-z,--search-zip}'[search in compressed files]'
|
||||||
$no"--no-search-zip[don't search in compressed files]"
|
$no"--no-search-zip[don't search in compressed files]"
|
||||||
@@ -273,7 +301,11 @@ _rg() {
|
|||||||
))'
|
))'
|
||||||
'*--colors=[specify color and style settings]: :->colorspec'
|
'*--colors=[specify color and style settings]: :->colorspec'
|
||||||
'--context-separator=[specify string used to separate non-continuous context lines in output]:separator'
|
'--context-separator=[specify string used to separate non-continuous context lines in output]:separator'
|
||||||
|
$no"--no-context-separator[don't print context separators]"
|
||||||
'--debug[show debug messages]'
|
'--debug[show debug messages]'
|
||||||
|
'--field-context-separator[set string to delimit fields in context lines]'
|
||||||
|
'--field-match-separator[set string to delimit fields in matching lines]'
|
||||||
|
'--trace[show more verbose debug messages]'
|
||||||
'--dfa-size-limit=[specify upper size limit of generated DFA]:DFA size (bytes)'
|
'--dfa-size-limit=[specify upper size limit of generated DFA]:DFA size (bytes)'
|
||||||
"(1 stats)--files[show each file that would be searched (but don't search)]"
|
"(1 stats)--files[show each file that would be searched (but don't search)]"
|
||||||
'*--ignore-file=[specify additional ignore file]:ignore file:_files'
|
'*--ignore-file=[specify additional ignore file]:ignore file:_files'
|
||||||
@@ -293,7 +325,7 @@ _rg() {
|
|||||||
'(--type-list)*: :_files'
|
'(--type-list)*: :_files'
|
||||||
)
|
)
|
||||||
|
|
||||||
# This is used with test_complete.sh to verify that there are no options
|
# This is used with test-complete to verify that there are no options
|
||||||
# listed in the help output that aren't also defined here
|
# listed in the help output that aren't also defined here
|
||||||
[[ $_RG_COMPLETE_LIST_ARGS == (1|t*|y*) ]] && {
|
[[ $_RG_COMPLETE_LIST_ARGS == (1|t*|y*) ]] && {
|
||||||
print -rl - $args
|
print -rl - $args
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "grep-cli"
|
name = "grep-cli"
|
||||||
version = "0.1.1" #:version
|
version = "0.1.7" #:version
|
||||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||||
description = """
|
description = """
|
||||||
Utilities for search oriented command line applications.
|
Utilities for search oriented command line applications.
|
||||||
"""
|
"""
|
||||||
documentation = "https://docs.rs/grep-cli"
|
documentation = "https://docs.rs/grep-cli"
|
||||||
homepage = "https://github.com/BurntSushi/ripgrep"
|
homepage = "https://github.com/BurntSushi/ripgrep/tree/master/crates/cli"
|
||||||
repository = "https://github.com/BurntSushi/ripgrep"
|
repository = "https://github.com/BurntSushi/ripgrep/tree/master/crates/cli"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
keywords = ["regex", "grep", "cli", "utility", "util"]
|
keywords = ["regex", "grep", "cli", "utility", "util"]
|
||||||
license = "Unlicense/MIT"
|
license = "Unlicense OR MIT"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
atty = "0.2.11"
|
atty = "0.2.11"
|
||||||
bstr = "0.1.2"
|
bstr = "1.1.0"
|
||||||
globset = { version = "0.4.3", path = "../globset" }
|
globset = { version = "0.4.10", path = "../globset" }
|
||||||
lazy_static = "1.1.0"
|
lazy_static = "1.1.0"
|
||||||
log = "0.4.5"
|
log = "0.4.5"
|
||||||
regex = "1.1"
|
regex = "1.1"
|
||||||
@@ -5,11 +5,10 @@ command line applications. This includes, but is not limited to, parsing hex
|
|||||||
escapes, detecting whether stdin is readable and more. To the extent possible,
|
escapes, detecting whether stdin is readable and more. To the extent possible,
|
||||||
this crate strives for compatibility across Windows, macOS and Linux.
|
this crate strives for compatibility across Windows, macOS and Linux.
|
||||||
|
|
||||||
[](https://travis-ci.org/BurntSushi/ripgrep)
|
[](https://github.com/BurntSushi/ripgrep/actions)
|
||||||
[](https://ci.appveyor.com/project/BurntSushi/ripgrep)
|
|
||||||
[](https://crates.io/crates/grep-cli)
|
[](https://crates.io/crates/grep-cli)
|
||||||
|
|
||||||
Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org).
|
Dual-licensed under MIT or the [UNLICENSE](https://unlicense.org/).
|
||||||
|
|
||||||
|
|
||||||
### Documentation
|
### Documentation
|
||||||
@@ -30,9 +29,3 @@ Add this to your `Cargo.toml`:
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
grep-cli = "0.1"
|
grep-cli = "0.1"
|
||||||
```
|
```
|
||||||
|
|
||||||
and this to your crate root:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
extern crate grep_cli;
|
|
||||||
```
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
use std::ffi::{OsStr, OsString};
|
use std::ffi::{OsStr, OsString};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::Path;
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use globset::{Glob, GlobSet, GlobSetBuilder};
|
use globset::{Glob, GlobSet, GlobSetBuilder};
|
||||||
|
|
||||||
use process::{CommandError, CommandReader, CommandReaderBuilder};
|
use crate::process::{CommandError, CommandReader, CommandReaderBuilder};
|
||||||
|
|
||||||
/// A builder for a matcher that determines which files get decompressed.
|
/// A builder for a matcher that determines which files get decompressed.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@@ -24,7 +24,7 @@ struct DecompressionCommand {
|
|||||||
/// The glob that matches this command.
|
/// The glob that matches this command.
|
||||||
glob: String,
|
glob: String,
|
||||||
/// The command or binary name.
|
/// The command or binary name.
|
||||||
bin: OsString,
|
bin: PathBuf,
|
||||||
/// The arguments to invoke with the command.
|
/// The arguments to invoke with the command.
|
||||||
args: Vec<OsString>,
|
args: Vec<OsString>,
|
||||||
}
|
}
|
||||||
@@ -38,10 +38,7 @@ impl Default for DecompressionMatcherBuilder {
|
|||||||
impl DecompressionMatcherBuilder {
|
impl DecompressionMatcherBuilder {
|
||||||
/// Create a new builder for configuring a decompression matcher.
|
/// Create a new builder for configuring a decompression matcher.
|
||||||
pub fn new() -> DecompressionMatcherBuilder {
|
pub fn new() -> DecompressionMatcherBuilder {
|
||||||
DecompressionMatcherBuilder {
|
DecompressionMatcherBuilder { commands: vec![], defaults: true }
|
||||||
commands: vec![],
|
|
||||||
defaults: true,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build a matcher for determining how to decompress files.
|
/// Build a matcher for determining how to decompress files.
|
||||||
@@ -49,12 +46,11 @@ impl DecompressionMatcherBuilder {
|
|||||||
/// If there was a problem compiling the matcher, then an error is
|
/// If there was a problem compiling the matcher, then an error is
|
||||||
/// returned.
|
/// returned.
|
||||||
pub fn build(&self) -> Result<DecompressionMatcher, CommandError> {
|
pub fn build(&self) -> Result<DecompressionMatcher, CommandError> {
|
||||||
let defaults =
|
let defaults = if !self.defaults {
|
||||||
if !self.defaults {
|
vec![]
|
||||||
vec![]
|
} else {
|
||||||
} else {
|
default_decompression_commands()
|
||||||
default_decompression_commands()
|
};
|
||||||
};
|
|
||||||
let mut glob_builder = GlobSetBuilder::new();
|
let mut glob_builder = GlobSetBuilder::new();
|
||||||
let mut commands = vec![];
|
let mut commands = vec![];
|
||||||
for decomp_cmd in defaults.iter().chain(&self.commands) {
|
for decomp_cmd in defaults.iter().chain(&self.commands) {
|
||||||
@@ -87,26 +83,61 @@ impl DecompressionMatcherBuilder {
|
|||||||
///
|
///
|
||||||
/// The syntax for the glob is documented in the
|
/// The syntax for the glob is documented in the
|
||||||
/// [`globset` crate](https://docs.rs/globset/#syntax).
|
/// [`globset` crate](https://docs.rs/globset/#syntax).
|
||||||
|
///
|
||||||
|
/// The `program` given is resolved with respect to `PATH` and turned
|
||||||
|
/// into an absolute path internally before being executed by the current
|
||||||
|
/// platform. Notably, on Windows, this avoids a security problem where
|
||||||
|
/// passing a relative path to `CreateProcess` will automatically search
|
||||||
|
/// the current directory for a matching program. If the program could
|
||||||
|
/// not be resolved, then it is silently ignored and the association is
|
||||||
|
/// dropped. For this reason, callers should prefer `try_associate`.
|
||||||
pub fn associate<P, I, A>(
|
pub fn associate<P, I, A>(
|
||||||
&mut self,
|
&mut self,
|
||||||
glob: &str,
|
glob: &str,
|
||||||
program: P,
|
program: P,
|
||||||
args: I,
|
args: I,
|
||||||
) -> &mut DecompressionMatcherBuilder
|
) -> &mut DecompressionMatcherBuilder
|
||||||
where P: AsRef<OsStr>,
|
where
|
||||||
I: IntoIterator<Item=A>,
|
P: AsRef<OsStr>,
|
||||||
A: AsRef<OsStr>,
|
I: IntoIterator<Item = A>,
|
||||||
|
A: AsRef<OsStr>,
|
||||||
{
|
{
|
||||||
|
let _ = self.try_associate(glob, program, args);
|
||||||
let glob = glob.to_string();
|
|
||||||
let bin = program.as_ref().to_os_string();
|
|
||||||
let args = args
|
|
||||||
.into_iter()
|
|
||||||
.map(|a| a.as_ref().to_os_string())
|
|
||||||
.collect();
|
|
||||||
self.commands.push(DecompressionCommand { glob, bin, args });
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Associates a glob with a command to decompress files matching the glob.
|
||||||
|
///
|
||||||
|
/// If multiple globs match the same file, then the most recently added
|
||||||
|
/// glob takes precedence.
|
||||||
|
///
|
||||||
|
/// The syntax for the glob is documented in the
|
||||||
|
/// [`globset` crate](https://docs.rs/globset/#syntax).
|
||||||
|
///
|
||||||
|
/// The `program` given is resolved with respect to `PATH` and turned
|
||||||
|
/// into an absolute path internally before being executed by the current
|
||||||
|
/// platform. Notably, on Windows, this avoids a security problem where
|
||||||
|
/// passing a relative path to `CreateProcess` will automatically search
|
||||||
|
/// the current directory for a matching program. If the program could not
|
||||||
|
/// be resolved, then an error is returned.
|
||||||
|
pub fn try_associate<P, I, A>(
|
||||||
|
&mut self,
|
||||||
|
glob: &str,
|
||||||
|
program: P,
|
||||||
|
args: I,
|
||||||
|
) -> Result<&mut DecompressionMatcherBuilder, CommandError>
|
||||||
|
where
|
||||||
|
P: AsRef<OsStr>,
|
||||||
|
I: IntoIterator<Item = A>,
|
||||||
|
A: AsRef<OsStr>,
|
||||||
|
{
|
||||||
|
let glob = glob.to_string();
|
||||||
|
let bin = resolve_binary(Path::new(program.as_ref()))?;
|
||||||
|
let args =
|
||||||
|
args.into_iter().map(|a| a.as_ref().to_os_string()).collect();
|
||||||
|
self.commands.push(DecompressionCommand { glob, bin, args });
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A matcher for determining how to decompress files.
|
/// A matcher for determining how to decompress files.
|
||||||
@@ -199,7 +230,7 @@ impl DecompressionReaderBuilder {
|
|||||||
match self.command_builder.build(&mut cmd) {
|
match self.command_builder.build(&mut cmd) {
|
||||||
Ok(cmd_reader) => Ok(DecompressionReader { rdr: Ok(cmd_reader) }),
|
Ok(cmd_reader) => Ok(DecompressionReader { rdr: Ok(cmd_reader) }),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
debug!(
|
log::debug!(
|
||||||
"{}: error spawning command '{:?}': {} \
|
"{}: error spawning command '{:?}': {} \
|
||||||
(falling back to uncompressed reader)",
|
(falling back to uncompressed reader)",
|
||||||
path.display(),
|
path.display(),
|
||||||
@@ -335,6 +366,30 @@ impl DecompressionReader {
|
|||||||
let file = File::open(path)?;
|
let file = File::open(path)?;
|
||||||
Ok(DecompressionReader { rdr: Err(file) })
|
Ok(DecompressionReader { rdr: Err(file) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Closes this reader, freeing any resources used by its underlying child
|
||||||
|
/// process, if one was used. If the child process exits with a nonzero
|
||||||
|
/// exit code, the returned Err value will include its stderr.
|
||||||
|
///
|
||||||
|
/// `close` is idempotent, meaning it can be safely called multiple times.
|
||||||
|
/// The first call closes the CommandReader and any subsequent calls do
|
||||||
|
/// nothing.
|
||||||
|
///
|
||||||
|
/// This method should be called after partially reading a file to prevent
|
||||||
|
/// resource leakage. However there is no need to call `close` explicitly
|
||||||
|
/// if your code always calls `read` to EOF, as `read` takes care of
|
||||||
|
/// calling `close` in this case.
|
||||||
|
///
|
||||||
|
/// `close` is also called in `drop` as a last line of defense against
|
||||||
|
/// resource leakage. Any error from the child process is then printed as a
|
||||||
|
/// warning to stderr. This can be avoided by explicitly calling `close`
|
||||||
|
/// before the CommandReader is dropped.
|
||||||
|
pub fn close(&mut self) -> io::Result<()> {
|
||||||
|
match self.rdr {
|
||||||
|
Ok(ref mut rdr) => rdr.close(),
|
||||||
|
Err(_) => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl io::Read for DecompressionReader {
|
impl io::Read for DecompressionReader {
|
||||||
@@ -346,6 +401,70 @@ impl io::Read for DecompressionReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolves a path to a program to a path by searching for the program in
|
||||||
|
/// `PATH`.
|
||||||
|
///
|
||||||
|
/// If the program could not be resolved, then an error is returned.
|
||||||
|
///
|
||||||
|
/// The purpose of doing this instead of passing the path to the program
|
||||||
|
/// directly to Command::new is that Command::new will hand relative paths
|
||||||
|
/// to CreateProcess on Windows, which will implicitly search the current
|
||||||
|
/// working directory for the executable. This could be undesirable for
|
||||||
|
/// security reasons. e.g., running ripgrep with the -z/--search-zip flag on an
|
||||||
|
/// untrusted directory tree could result in arbitrary programs executing on
|
||||||
|
/// Windows.
|
||||||
|
///
|
||||||
|
/// Note that this could still return a relative path if PATH contains a
|
||||||
|
/// relative path. We permit this since it is assumed that the user has set
|
||||||
|
/// this explicitly, and thus, desires this behavior.
|
||||||
|
///
|
||||||
|
/// On non-Windows, this is a no-op.
|
||||||
|
pub fn resolve_binary<P: AsRef<Path>>(
|
||||||
|
prog: P,
|
||||||
|
) -> Result<PathBuf, CommandError> {
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
fn is_exe(path: &Path) -> bool {
|
||||||
|
let md = match path.metadata() {
|
||||||
|
Err(_) => return false,
|
||||||
|
Ok(md) => md,
|
||||||
|
};
|
||||||
|
!md.is_dir()
|
||||||
|
}
|
||||||
|
|
||||||
|
let prog = prog.as_ref();
|
||||||
|
if !cfg!(windows) || prog.is_absolute() {
|
||||||
|
return Ok(prog.to_path_buf());
|
||||||
|
}
|
||||||
|
let syspaths = match env::var_os("PATH") {
|
||||||
|
Some(syspaths) => syspaths,
|
||||||
|
None => {
|
||||||
|
let msg = "system PATH environment variable not found";
|
||||||
|
return Err(CommandError::io(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
msg,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for syspath in env::split_paths(&syspaths) {
|
||||||
|
if syspath.as_os_str().is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let abs_prog = syspath.join(prog);
|
||||||
|
if is_exe(&abs_prog) {
|
||||||
|
return Ok(abs_prog.to_path_buf());
|
||||||
|
}
|
||||||
|
if abs_prog.extension().is_none() {
|
||||||
|
let abs_prog = abs_prog.with_extension("exe");
|
||||||
|
if is_exe(&abs_prog) {
|
||||||
|
return Ok(abs_prog.to_path_buf());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let msg = format!("{}: could not find executable in PATH", prog.display());
|
||||||
|
return Err(CommandError::io(io::Error::new(io::ErrorKind::Other, msg)));
|
||||||
|
}
|
||||||
|
|
||||||
fn default_decompression_commands() -> Vec<DecompressionCommand> {
|
fn default_decompression_commands() -> Vec<DecompressionCommand> {
|
||||||
const ARGS_GZIP: &[&str] = &["gzip", "-d", "-c"];
|
const ARGS_GZIP: &[&str] = &["gzip", "-d", "-c"];
|
||||||
const ARGS_BZIP: &[&str] = &["bzip2", "-d", "-c"];
|
const ARGS_BZIP: &[&str] = &["bzip2", "-d", "-c"];
|
||||||
@@ -354,29 +473,38 @@ fn default_decompression_commands() -> Vec<DecompressionCommand> {
|
|||||||
const ARGS_LZMA: &[&str] = &["xz", "--format=lzma", "-d", "-c"];
|
const ARGS_LZMA: &[&str] = &["xz", "--format=lzma", "-d", "-c"];
|
||||||
const ARGS_BROTLI: &[&str] = &["brotli", "-d", "-c"];
|
const ARGS_BROTLI: &[&str] = &["brotli", "-d", "-c"];
|
||||||
const ARGS_ZSTD: &[&str] = &["zstd", "-q", "-d", "-c"];
|
const ARGS_ZSTD: &[&str] = &["zstd", "-q", "-d", "-c"];
|
||||||
|
const ARGS_UNCOMPRESS: &[&str] = &["uncompress", "-c"];
|
||||||
|
|
||||||
fn cmd(glob: &str, args: &[&str]) -> DecompressionCommand {
|
fn add(glob: &str, args: &[&str], cmds: &mut Vec<DecompressionCommand>) {
|
||||||
DecompressionCommand {
|
let bin = match resolve_binary(Path::new(args[0])) {
|
||||||
|
Ok(bin) => bin,
|
||||||
|
Err(err) => {
|
||||||
|
log::debug!("{}", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
cmds.push(DecompressionCommand {
|
||||||
glob: glob.to_string(),
|
glob: glob.to_string(),
|
||||||
bin: OsStr::new(&args[0]).to_os_string(),
|
bin,
|
||||||
args: args
|
args: args
|
||||||
.iter()
|
.iter()
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.map(|s| OsStr::new(s).to_os_string())
|
.map(|s| OsStr::new(s).to_os_string())
|
||||||
.collect(),
|
.collect(),
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
vec![
|
let mut cmds = vec![];
|
||||||
cmd("*.gz", ARGS_GZIP),
|
add("*.gz", ARGS_GZIP, &mut cmds);
|
||||||
cmd("*.tgz", ARGS_GZIP),
|
add("*.tgz", ARGS_GZIP, &mut cmds);
|
||||||
cmd("*.bz2", ARGS_BZIP),
|
add("*.bz2", ARGS_BZIP, &mut cmds);
|
||||||
cmd("*.tbz2", ARGS_BZIP),
|
add("*.tbz2", ARGS_BZIP, &mut cmds);
|
||||||
cmd("*.xz", ARGS_XZ),
|
add("*.xz", ARGS_XZ, &mut cmds);
|
||||||
cmd("*.txz", ARGS_XZ),
|
add("*.txz", ARGS_XZ, &mut cmds);
|
||||||
cmd("*.lz4", ARGS_LZ4),
|
add("*.lz4", ARGS_LZ4, &mut cmds);
|
||||||
cmd("*.lzma", ARGS_LZMA),
|
add("*.lzma", ARGS_LZMA, &mut cmds);
|
||||||
cmd("*.br", ARGS_BROTLI),
|
add("*.br", ARGS_BROTLI, &mut cmds);
|
||||||
cmd("*.zst", ARGS_ZSTD),
|
add("*.zst", ARGS_ZSTD, &mut cmds);
|
||||||
cmd("*.zstd", ARGS_ZSTD),
|
add("*.zstd", ARGS_ZSTD, &mut cmds);
|
||||||
]
|
add("*.Z", ARGS_UNCOMPRESS, &mut cmds);
|
||||||
|
cmds
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use bstr::{BStr, BString};
|
use bstr::{ByteSlice, ByteVec};
|
||||||
|
|
||||||
/// A single state in the state machine used by `unescape`.
|
/// A single state in the state machine used by `unescape`.
|
||||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
@@ -38,7 +38,6 @@ enum State {
|
|||||||
/// assert_eq!(r"foo\nbar\xFFbaz", escape(b"foo\nbar\xFFbaz"));
|
/// assert_eq!(r"foo\nbar\xFFbaz", escape(b"foo\nbar\xFFbaz"));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn escape(bytes: &[u8]) -> String {
|
pub fn escape(bytes: &[u8]) -> String {
|
||||||
let bytes = BStr::new(bytes);
|
|
||||||
let mut escaped = String::new();
|
let mut escaped = String::new();
|
||||||
for (s, e, ch) in bytes.char_indices() {
|
for (s, e, ch) in bytes.char_indices() {
|
||||||
if ch == '\u{FFFD}' {
|
if ch == '\u{FFFD}' {
|
||||||
@@ -56,7 +55,7 @@ pub fn escape(bytes: &[u8]) -> String {
|
|||||||
///
|
///
|
||||||
/// This is like [`escape`](fn.escape.html), but accepts an OS string.
|
/// This is like [`escape`](fn.escape.html), but accepts an OS string.
|
||||||
pub fn escape_os(string: &OsStr) -> String {
|
pub fn escape_os(string: &OsStr) -> String {
|
||||||
escape(BString::from_os_str_lossy(string).as_bytes())
|
escape(Vec::from_os_str_lossy(string).as_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unescapes a string.
|
/// Unescapes a string.
|
||||||
@@ -96,51 +95,61 @@ pub fn unescape(s: &str) -> Vec<u8> {
|
|||||||
let mut state = Literal;
|
let mut state = Literal;
|
||||||
for c in s.chars() {
|
for c in s.chars() {
|
||||||
match state {
|
match state {
|
||||||
Escape => {
|
Escape => match c {
|
||||||
match c {
|
'\\' => {
|
||||||
'\\' => { bytes.push(b'\\'); state = Literal; }
|
bytes.push(b'\\');
|
||||||
'n' => { bytes.push(b'\n'); state = Literal; }
|
state = Literal;
|
||||||
'r' => { bytes.push(b'\r'); state = Literal; }
|
|
||||||
't' => { bytes.push(b'\t'); state = Literal; }
|
|
||||||
'x' => { state = HexFirst; }
|
|
||||||
c => {
|
|
||||||
bytes.extend(format!(r"\{}", c).into_bytes());
|
|
||||||
state = Literal;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
'n' => {
|
||||||
HexFirst => {
|
bytes.push(b'\n');
|
||||||
match c {
|
state = Literal;
|
||||||
'0'...'9' | 'A'...'F' | 'a'...'f' => {
|
|
||||||
state = HexSecond(c);
|
|
||||||
}
|
|
||||||
c => {
|
|
||||||
bytes.extend(format!(r"\x{}", c).into_bytes());
|
|
||||||
state = Literal;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
'r' => {
|
||||||
HexSecond(first) => {
|
bytes.push(b'\r');
|
||||||
match c {
|
state = Literal;
|
||||||
'0'...'9' | 'A'...'F' | 'a'...'f' => {
|
|
||||||
let ordinal = format!("{}{}", first, c);
|
|
||||||
let byte = u8::from_str_radix(&ordinal, 16).unwrap();
|
|
||||||
bytes.push(byte);
|
|
||||||
state = Literal;
|
|
||||||
}
|
|
||||||
c => {
|
|
||||||
let original = format!(r"\x{}{}", first, c);
|
|
||||||
bytes.extend(original.into_bytes());
|
|
||||||
state = Literal;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
't' => {
|
||||||
Literal => {
|
bytes.push(b'\t');
|
||||||
match c {
|
state = Literal;
|
||||||
'\\' => { state = Escape; }
|
|
||||||
c => { bytes.extend(c.to_string().as_bytes()); }
|
|
||||||
}
|
}
|
||||||
}
|
'x' => {
|
||||||
|
state = HexFirst;
|
||||||
|
}
|
||||||
|
c => {
|
||||||
|
bytes.extend(format!(r"\{}", c).into_bytes());
|
||||||
|
state = Literal;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
HexFirst => match c {
|
||||||
|
'0'..='9' | 'A'..='F' | 'a'..='f' => {
|
||||||
|
state = HexSecond(c);
|
||||||
|
}
|
||||||
|
c => {
|
||||||
|
bytes.extend(format!(r"\x{}", c).into_bytes());
|
||||||
|
state = Literal;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
HexSecond(first) => match c {
|
||||||
|
'0'..='9' | 'A'..='F' | 'a'..='f' => {
|
||||||
|
let ordinal = format!("{}{}", first, c);
|
||||||
|
let byte = u8::from_str_radix(&ordinal, 16).unwrap();
|
||||||
|
bytes.push(byte);
|
||||||
|
state = Literal;
|
||||||
|
}
|
||||||
|
c => {
|
||||||
|
let original = format!(r"\x{}{}", first, c);
|
||||||
|
bytes.extend(original.into_bytes());
|
||||||
|
state = Literal;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Literal => match c {
|
||||||
|
'\\' => {
|
||||||
|
state = Escape;
|
||||||
|
}
|
||||||
|
c => {
|
||||||
|
bytes.extend(c.to_string().as_bytes());
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match state {
|
match state {
|
||||||
@@ -174,7 +183,7 @@ fn escape_char(cp: char, into: &mut String) {
|
|||||||
/// Adds the given byte to the given string, escaping it if necessary.
|
/// Adds the given byte to the given string, escaping it if necessary.
|
||||||
fn escape_byte(byte: u8, into: &mut String) {
|
fn escape_byte(byte: u8, into: &mut String) {
|
||||||
match byte {
|
match byte {
|
||||||
0x21...0x5B | 0x5D...0x7D => into.push(byte as char),
|
0x21..=0x5B | 0x5D..=0x7D => into.push(byte as char),
|
||||||
b'\n' => into.push_str(r"\n"),
|
b'\n' => into.push_str(r"\n"),
|
||||||
b'\r' => into.push_str(r"\r"),
|
b'\r' => into.push_str(r"\r"),
|
||||||
b'\t' => into.push_str(r"\t"),
|
b'\t' => into.push_str(r"\t"),
|
||||||
@@ -7,8 +7,8 @@ use regex::Regex;
|
|||||||
|
|
||||||
/// An error that occurs when parsing a human readable size description.
|
/// An error that occurs when parsing a human readable size description.
|
||||||
///
|
///
|
||||||
/// This error provides a end user friendly message describing why the
|
/// This error provides an end user friendly message describing why the
|
||||||
/// description coudln't be parsed and what the expected format is.
|
/// description couldn't be parsed and what the expected format is.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct ParseSizeError {
|
pub struct ParseSizeError {
|
||||||
original: String,
|
original: String,
|
||||||
@@ -46,34 +46,29 @@ impl ParseSizeError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl error::Error for ParseSizeError {
|
impl error::Error for ParseSizeError {
|
||||||
fn description(&self) -> &str { "invalid size" }
|
fn description(&self) -> &str {
|
||||||
|
"invalid size"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ParseSizeError {
|
impl fmt::Display for ParseSizeError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
use self::ParseSizeErrorKind::*;
|
use self::ParseSizeErrorKind::*;
|
||||||
|
|
||||||
match self.kind {
|
match self.kind {
|
||||||
InvalidFormat => {
|
InvalidFormat => write!(
|
||||||
write!(
|
f,
|
||||||
f,
|
"invalid format for size '{}', which should be a sequence \
|
||||||
"invalid format for size '{}', which should be a sequence \
|
|
||||||
of digits followed by an optional 'K', 'M' or 'G' \
|
of digits followed by an optional 'K', 'M' or 'G' \
|
||||||
suffix",
|
suffix",
|
||||||
self.original
|
self.original
|
||||||
)
|
),
|
||||||
}
|
InvalidInt(ref err) => write!(
|
||||||
InvalidInt(ref err) => {
|
f,
|
||||||
write!(
|
"invalid integer found in size '{}': {}",
|
||||||
f,
|
self.original, err
|
||||||
"invalid integer found in size '{}': {}",
|
),
|
||||||
self.original,
|
Overflow => write!(f, "size too big in '{}'", self.original),
|
||||||
err
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Overflow => {
|
|
||||||
write!(f, "size too big in '{}'", self.original)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,7 +88,7 @@ impl From<ParseSizeError> for io::Error {
|
|||||||
///
|
///
|
||||||
/// Additional suffixes may be added over time.
|
/// Additional suffixes may be added over time.
|
||||||
pub fn parse_human_readable_size(size: &str) -> Result<u64, ParseSizeError> {
|
pub fn parse_human_readable_size(size: &str) -> Result<u64, ParseSizeError> {
|
||||||
lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
// Normally I'd just parse something this simple by hand to avoid the
|
// Normally I'd just parse something this simple by hand to avoid the
|
||||||
// regex dep, but we bring regex in any way for glob matching, so might
|
// regex dep, but we bring regex in any way for glob matching, so might
|
||||||
// as well use it.
|
// as well use it.
|
||||||
@@ -104,17 +99,16 @@ pub fn parse_human_readable_size(size: &str) -> Result<u64, ParseSizeError> {
|
|||||||
Some(caps) => caps,
|
Some(caps) => caps,
|
||||||
None => return Err(ParseSizeError::format(size)),
|
None => return Err(ParseSizeError::format(size)),
|
||||||
};
|
};
|
||||||
let value: u64 = caps[1].parse().map_err(|err| {
|
let value: u64 =
|
||||||
ParseSizeError::int(size, err)
|
caps[1].parse().map_err(|err| ParseSizeError::int(size, err))?;
|
||||||
})?;
|
|
||||||
let suffix = match caps.get(2) {
|
let suffix = match caps.get(2) {
|
||||||
None => return Ok(value),
|
None => return Ok(value),
|
||||||
Some(cap) => cap.as_str(),
|
Some(cap) => cap.as_str(),
|
||||||
};
|
};
|
||||||
let bytes = match suffix {
|
let bytes = match suffix {
|
||||||
"K" => value.checked_mul(1<<10),
|
"K" => value.checked_mul(1 << 10),
|
||||||
"M" => value.checked_mul(1<<20),
|
"M" => value.checked_mul(1 << 20),
|
||||||
"G" => value.checked_mul(1<<30),
|
"G" => value.checked_mul(1 << 30),
|
||||||
// Because if the regex matches this group, it must be [KMG].
|
// Because if the regex matches this group, it must be [KMG].
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
@@ -134,19 +128,19 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn suffix_k() {
|
fn suffix_k() {
|
||||||
let x = parse_human_readable_size("123K").unwrap();
|
let x = parse_human_readable_size("123K").unwrap();
|
||||||
assert_eq!(123 * (1<<10), x);
|
assert_eq!(123 * (1 << 10), x);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn suffix_m() {
|
fn suffix_m() {
|
||||||
let x = parse_human_readable_size("123M").unwrap();
|
let x = parse_human_readable_size("123M").unwrap();
|
||||||
assert_eq!(123 * (1<<20), x);
|
assert_eq!(123 * (1 << 20), x);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn suffix_g() {
|
fn suffix_g() {
|
||||||
let x = parse_human_readable_size("123G").unwrap();
|
let x = parse_human_readable_size("123G").unwrap();
|
||||||
assert_eq!(123 * (1<<30), x);
|
assert_eq!(123 * (1 << 30), x);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -158,19 +158,6 @@ error message is crafted that typically tells the user how to fix the problem.
|
|||||||
|
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
extern crate atty;
|
|
||||||
extern crate bstr;
|
|
||||||
extern crate globset;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate lazy_static;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate log;
|
|
||||||
extern crate regex;
|
|
||||||
extern crate same_file;
|
|
||||||
extern crate termcolor;
|
|
||||||
#[cfg(windows)]
|
|
||||||
extern crate winapi_util;
|
|
||||||
|
|
||||||
mod decompress;
|
mod decompress;
|
||||||
mod escape;
|
mod escape;
|
||||||
mod human;
|
mod human;
|
||||||
@@ -178,21 +165,19 @@ mod pattern;
|
|||||||
mod process;
|
mod process;
|
||||||
mod wtr;
|
mod wtr;
|
||||||
|
|
||||||
pub use decompress::{
|
pub use crate::decompress::{
|
||||||
DecompressionMatcher, DecompressionMatcherBuilder,
|
resolve_binary, DecompressionMatcher, DecompressionMatcherBuilder,
|
||||||
DecompressionReader, DecompressionReaderBuilder,
|
DecompressionReader, DecompressionReaderBuilder,
|
||||||
};
|
};
|
||||||
pub use escape::{escape, escape_os, unescape, unescape_os};
|
pub use crate::escape::{escape, escape_os, unescape, unescape_os};
|
||||||
pub use human::{ParseSizeError, parse_human_readable_size};
|
pub use crate::human::{parse_human_readable_size, ParseSizeError};
|
||||||
pub use pattern::{
|
pub use crate::pattern::{
|
||||||
InvalidPatternError,
|
pattern_from_bytes, pattern_from_os, patterns_from_path,
|
||||||
pattern_from_os, pattern_from_bytes,
|
patterns_from_reader, patterns_from_stdin, InvalidPatternError,
|
||||||
patterns_from_path, patterns_from_reader, patterns_from_stdin,
|
|
||||||
};
|
};
|
||||||
pub use process::{CommandError, CommandReader, CommandReaderBuilder};
|
pub use crate::process::{CommandError, CommandReader, CommandReaderBuilder};
|
||||||
pub use wtr::{
|
pub use crate::wtr::{
|
||||||
StandardStream,
|
stdout, stdout_buffered_block, stdout_buffered_line, StandardStream,
|
||||||
stdout, stdout_buffered_line, stdout_buffered_block,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Returns true if and only if stdin is believed to be readable.
|
/// Returns true if and only if stdin is believed to be readable.
|
||||||
@@ -205,14 +190,14 @@ pub use wtr::{
|
|||||||
pub fn is_readable_stdin() -> bool {
|
pub fn is_readable_stdin() -> bool {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn imp() -> bool {
|
fn imp() -> bool {
|
||||||
use std::os::unix::fs::FileTypeExt;
|
|
||||||
use same_file::Handle;
|
use same_file::Handle;
|
||||||
|
use std::os::unix::fs::FileTypeExt;
|
||||||
|
|
||||||
let ft = match Handle::stdin().and_then(|h| h.as_file().metadata()) {
|
let ft = match Handle::stdin().and_then(|h| h.as_file().metadata()) {
|
||||||
Err(_) => return false,
|
Err(_) => return false,
|
||||||
Ok(md) => md.file_type(),
|
Ok(md) => md.file_type(),
|
||||||
};
|
};
|
||||||
ft.is_file() || ft.is_fifo()
|
ft.is_file() || ft.is_fifo() || ft.is_socket()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@@ -227,13 +212,13 @@ pub fn is_readable_stdin() -> bool {
|
|||||||
!is_tty_stdin() && imp()
|
!is_tty_stdin() && imp()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if and only if stdin is believed to be connectted to a tty
|
/// Returns true if and only if stdin is believed to be connected to a tty
|
||||||
/// or a console.
|
/// or a console.
|
||||||
pub fn is_tty_stdin() -> bool {
|
pub fn is_tty_stdin() -> bool {
|
||||||
atty::is(atty::Stream::Stdin)
|
atty::is(atty::Stream::Stdin)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if and only if stdout is believed to be connectted to a tty
|
/// Returns true if and only if stdout is believed to be connected to a tty
|
||||||
/// or a console.
|
/// or a console.
|
||||||
///
|
///
|
||||||
/// This is useful for when you want your command line program to produce
|
/// This is useful for when you want your command line program to produce
|
||||||
@@ -245,7 +230,7 @@ pub fn is_tty_stdout() -> bool {
|
|||||||
atty::is(atty::Stream::Stdout)
|
atty::is(atty::Stream::Stdout)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if and only if stderr is believed to be connectted to a tty
|
/// Returns true if and only if stderr is believed to be connected to a tty
|
||||||
/// or a console.
|
/// or a console.
|
||||||
pub fn is_tty_stderr() -> bool {
|
pub fn is_tty_stderr() -> bool {
|
||||||
atty::is(atty::Stream::Stderr)
|
atty::is(atty::Stream::Stderr)
|
||||||
@@ -2,11 +2,13 @@ use std::error;
|
|||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{self, BufRead};
|
use std::io;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use escape::{escape, escape_os};
|
use bstr::io::BufReadExt;
|
||||||
|
|
||||||
|
use crate::escape::{escape, escape_os};
|
||||||
|
|
||||||
/// An error that occurs when a pattern could not be converted to valid UTF-8.
|
/// An error that occurs when a pattern could not be converted to valid UTF-8.
|
||||||
///
|
///
|
||||||
@@ -27,18 +29,19 @@ impl InvalidPatternError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl error::Error for InvalidPatternError {
|
impl error::Error for InvalidPatternError {
|
||||||
fn description(&self) -> &str { "invalid pattern" }
|
fn description(&self) -> &str {
|
||||||
|
"invalid pattern"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for InvalidPatternError {
|
impl fmt::Display for InvalidPatternError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"found invalid UTF-8 in pattern at byte offset {} \
|
"found invalid UTF-8 in pattern at byte offset {}: {} \
|
||||||
(use hex escape sequences to match arbitrary bytes \
|
(disable Unicode mode and use hex escape sequences to match \
|
||||||
in a pattern, e.g., \\xFF): '{}'",
|
arbitrary bytes in a pattern, e.g., '(?-u)\\xFF')",
|
||||||
self.valid_up_to,
|
self.valid_up_to, self.original,
|
||||||
self.original,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,10 +64,7 @@ pub fn pattern_from_os(pattern: &OsStr) -> Result<&str, InvalidPatternError> {
|
|||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.find('\u{FFFD}')
|
.find('\u{FFFD}')
|
||||||
.expect("a Unicode replacement codepoint for invalid UTF-8");
|
.expect("a Unicode replacement codepoint for invalid UTF-8");
|
||||||
InvalidPatternError {
|
InvalidPatternError { original: escape_os(pattern), valid_up_to }
|
||||||
original: escape_os(pattern),
|
|
||||||
valid_up_to: valid_up_to,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,11 +77,9 @@ pub fn pattern_from_os(pattern: &OsStr) -> Result<&str, InvalidPatternError> {
|
|||||||
pub fn pattern_from_bytes(
|
pub fn pattern_from_bytes(
|
||||||
pattern: &[u8],
|
pattern: &[u8],
|
||||||
) -> Result<&str, InvalidPatternError> {
|
) -> Result<&str, InvalidPatternError> {
|
||||||
str::from_utf8(pattern).map_err(|err| {
|
str::from_utf8(pattern).map_err(|err| InvalidPatternError {
|
||||||
InvalidPatternError {
|
original: escape(pattern),
|
||||||
original: escape(pattern),
|
valid_up_to: err.valid_up_to(),
|
||||||
valid_up_to: err.valid_up_to(),
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,10 +115,7 @@ pub fn patterns_from_stdin() -> io::Result<Vec<String>> {
|
|||||||
let stdin = io::stdin();
|
let stdin = io::stdin();
|
||||||
let locked = stdin.lock();
|
let locked = stdin.lock();
|
||||||
patterns_from_reader(locked).map_err(|err| {
|
patterns_from_reader(locked).map_err(|err| {
|
||||||
io::Error::new(
|
io::Error::new(io::ErrorKind::Other, format!("<stdin>:{}", err))
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("<stdin>:{}", err),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,28 +151,20 @@ pub fn patterns_from_stdin() -> io::Result<Vec<String>> {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn patterns_from_reader<R: io::Read>(rdr: R) -> io::Result<Vec<String>> {
|
pub fn patterns_from_reader<R: io::Read>(rdr: R) -> io::Result<Vec<String>> {
|
||||||
let mut patterns = vec![];
|
let mut patterns = vec![];
|
||||||
let mut bufrdr = io::BufReader::new(rdr);
|
|
||||||
let mut line = vec![];
|
|
||||||
let mut line_number = 0;
|
let mut line_number = 0;
|
||||||
while {
|
io::BufReader::new(rdr).for_byte_line(|line| {
|
||||||
line.clear();
|
|
||||||
line_number += 1;
|
line_number += 1;
|
||||||
bufrdr.read_until(b'\n', &mut line)? > 0
|
match pattern_from_bytes(line) {
|
||||||
} {
|
Ok(pattern) => {
|
||||||
line.pop().unwrap(); // remove trailing '\n'
|
patterns.push(pattern.to_string());
|
||||||
if line.last() == Some(&b'\r') {
|
Ok(true)
|
||||||
line.pop().unwrap();
|
|
||||||
}
|
|
||||||
match pattern_from_bytes(&line) {
|
|
||||||
Ok(pattern) => patterns.push(pattern.to_string()),
|
|
||||||
Err(err) => {
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("{}: {}", line_number, err),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
Err(err) => Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!("{}: {}", line_number, err),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
})?;
|
||||||
Ok(patterns)
|
Ok(patterns)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,8 +182,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn os() {
|
fn os() {
|
||||||
use std::os::unix::ffi::OsStrExt;
|
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
|
use std::os::unix::ffi::OsStrExt;
|
||||||
|
|
||||||
let pat = OsStr::from_bytes(b"abc\xFFxyz");
|
let pat = OsStr::from_bytes(b"abc\xFFxyz");
|
||||||
let err = pattern_from_os(pat).unwrap_err();
|
let err = pattern_from_os(pat).unwrap_err();
|
||||||
@@ -30,14 +30,24 @@ impl CommandError {
|
|||||||
pub(crate) fn stderr(bytes: Vec<u8>) -> CommandError {
|
pub(crate) fn stderr(bytes: Vec<u8>) -> CommandError {
|
||||||
CommandError { kind: CommandErrorKind::Stderr(bytes) }
|
CommandError { kind: CommandErrorKind::Stderr(bytes) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if and only if this error has empty data from stderr.
|
||||||
|
pub(crate) fn is_empty(&self) -> bool {
|
||||||
|
match self.kind {
|
||||||
|
CommandErrorKind::Stderr(ref bytes) => bytes.is_empty(),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl error::Error for CommandError {
|
impl error::Error for CommandError {
|
||||||
fn description(&self) -> &str { "command error" }
|
fn description(&self) -> &str {
|
||||||
|
"command error"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for CommandError {
|
impl fmt::Display for CommandError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
CommandErrorKind::Io(ref e) => e.fmt(f),
|
CommandErrorKind::Io(ref e) => e.fmt(f),
|
||||||
CommandErrorKind::Stderr(ref bytes) => {
|
CommandErrorKind::Stderr(ref bytes) => {
|
||||||
@@ -46,7 +56,12 @@ impl fmt::Display for CommandError {
|
|||||||
write!(f, "<stderr is empty>")
|
write!(f, "<stderr is empty>")
|
||||||
} else {
|
} else {
|
||||||
let div = iter::repeat('-').take(79).collect::<String>();
|
let div = iter::repeat('-').take(79).collect::<String>();
|
||||||
write!(f, "\n{div}\n{msg}\n{div}", div=div, msg=msg.trim())
|
write!(
|
||||||
|
f,
|
||||||
|
"\n{div}\n{msg}\n{div}",
|
||||||
|
div = div,
|
||||||
|
msg = msg.trim()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,19 +115,12 @@ impl CommandReaderBuilder {
|
|||||||
.stdout(process::Stdio::piped())
|
.stdout(process::Stdio::piped())
|
||||||
.stderr(process::Stdio::piped())
|
.stderr(process::Stdio::piped())
|
||||||
.spawn()?;
|
.spawn()?;
|
||||||
let stdout = child.stdout.take().unwrap();
|
let stderr = if self.async_stderr {
|
||||||
let stderr =
|
StderrReader::r#async(child.stderr.take().unwrap())
|
||||||
if self.async_stderr {
|
} else {
|
||||||
StderrReader::async(child.stderr.take().unwrap())
|
StderrReader::sync(child.stderr.take().unwrap())
|
||||||
} else {
|
};
|
||||||
StderrReader::sync(child.stderr.take().unwrap())
|
Ok(CommandReader { child, stderr, eof: false })
|
||||||
};
|
|
||||||
Ok(CommandReader {
|
|
||||||
child: child,
|
|
||||||
stdout: stdout,
|
|
||||||
stderr: stderr,
|
|
||||||
done: false,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When enabled, the reader will asynchronously read the contents of the
|
/// When enabled, the reader will asynchronously read the contents of the
|
||||||
@@ -169,9 +177,11 @@ impl CommandReaderBuilder {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CommandReader {
|
pub struct CommandReader {
|
||||||
child: process::Child,
|
child: process::Child,
|
||||||
stdout: process::ChildStdout,
|
|
||||||
stderr: StderrReader,
|
stderr: StderrReader,
|
||||||
done: bool,
|
/// This is set to true once 'read' returns zero bytes. When this isn't
|
||||||
|
/// set and we close the reader, then we anticipate a pipe error when
|
||||||
|
/// reaping the child process and silence it.
|
||||||
|
eof: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommandReader {
|
impl CommandReader {
|
||||||
@@ -195,23 +205,73 @@ impl CommandReader {
|
|||||||
) -> Result<CommandReader, CommandError> {
|
) -> Result<CommandReader, CommandError> {
|
||||||
CommandReaderBuilder::new().build(cmd)
|
CommandReaderBuilder::new().build(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Closes the CommandReader, freeing any resources used by its underlying
|
||||||
|
/// child process. If the child process exits with a nonzero exit code, the
|
||||||
|
/// returned Err value will include its stderr.
|
||||||
|
///
|
||||||
|
/// `close` is idempotent, meaning it can be safely called multiple times.
|
||||||
|
/// The first call closes the CommandReader and any subsequent calls do
|
||||||
|
/// nothing.
|
||||||
|
///
|
||||||
|
/// This method should be called after partially reading a file to prevent
|
||||||
|
/// resource leakage. However there is no need to call `close` explicitly
|
||||||
|
/// if your code always calls `read` to EOF, as `read` takes care of
|
||||||
|
/// calling `close` in this case.
|
||||||
|
///
|
||||||
|
/// `close` is also called in `drop` as a last line of defense against
|
||||||
|
/// resource leakage. Any error from the child process is then printed as a
|
||||||
|
/// warning to stderr. This can be avoided by explicitly calling `close`
|
||||||
|
/// before the CommandReader is dropped.
|
||||||
|
pub fn close(&mut self) -> io::Result<()> {
|
||||||
|
// Dropping stdout closes the underlying file descriptor, which should
|
||||||
|
// cause a well-behaved child process to exit. If child.stdout is None
|
||||||
|
// we assume that close() has already been called and do nothing.
|
||||||
|
let stdout = match self.child.stdout.take() {
|
||||||
|
None => return Ok(()),
|
||||||
|
Some(stdout) => stdout,
|
||||||
|
};
|
||||||
|
drop(stdout);
|
||||||
|
if self.child.wait()?.success() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
let err = self.stderr.read_to_end();
|
||||||
|
// In the specific case where we haven't consumed the full data
|
||||||
|
// from the child process, then closing stdout above results in
|
||||||
|
// a pipe signal being thrown in most cases. But I don't think
|
||||||
|
// there is any reliable and portable way of detecting it. Instead,
|
||||||
|
// if we know we haven't hit EOF (so we anticipate a broken pipe
|
||||||
|
// error) and if stderr otherwise doesn't have anything on it, then
|
||||||
|
// we assume total success.
|
||||||
|
if !self.eof && err.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
Err(io::Error::from(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for CommandReader {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Err(error) = self.close() {
|
||||||
|
log::warn!("{}", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl io::Read for CommandReader {
|
impl io::Read for CommandReader {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
if self.done {
|
let stdout = match self.child.stdout {
|
||||||
return Ok(0);
|
None => return Ok(0),
|
||||||
}
|
Some(ref mut stdout) => stdout,
|
||||||
let nread = self.stdout.read(buf)?;
|
};
|
||||||
|
let nread = stdout.read(buf)?;
|
||||||
if nread == 0 {
|
if nread == 0 {
|
||||||
self.done = true;
|
self.eof = true;
|
||||||
// Reap the child now that we're done reading. If the command
|
self.close().map(|_| 0)
|
||||||
// failed, report stderr as an error.
|
} else {
|
||||||
if !self.child.wait()?.success() {
|
Ok(nread)
|
||||||
return Err(io::Error::from(self.stderr.read_to_end()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(nread)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,10 +285,9 @@ enum StderrReader {
|
|||||||
|
|
||||||
impl StderrReader {
|
impl StderrReader {
|
||||||
/// Create a reader for stderr that reads contents asynchronously.
|
/// Create a reader for stderr that reads contents asynchronously.
|
||||||
fn async(mut stderr: process::ChildStderr) -> StderrReader {
|
fn r#async(mut stderr: process::ChildStderr) -> StderrReader {
|
||||||
let handle = thread::spawn(move || {
|
let handle =
|
||||||
stderr_to_command_error(&mut stderr)
|
thread::spawn(move || stderr_to_command_error(&mut stderr));
|
||||||
});
|
|
||||||
StderrReader::Async(Some(handle))
|
StderrReader::Async(Some(handle))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,9 +306,7 @@ impl StderrReader {
|
|||||||
let handle = handle
|
let handle = handle
|
||||||
.take()
|
.take()
|
||||||
.expect("read_to_end cannot be called more than once");
|
.expect("read_to_end cannot be called more than once");
|
||||||
handle
|
handle.join().expect("stderr reading thread does not panic")
|
||||||
.join()
|
|
||||||
.expect("stderr reading thread does not panic")
|
|
||||||
}
|
}
|
||||||
StderrReader::Sync(ref mut stderr) => {
|
StderrReader::Sync(ref mut stderr) => {
|
||||||
stderr_to_command_error(stderr)
|
stderr_to_command_error(stderr)
|
||||||
@@ -2,7 +2,7 @@ use std::io;
|
|||||||
|
|
||||||
use termcolor;
|
use termcolor;
|
||||||
|
|
||||||
use is_tty_stdout;
|
use crate::is_tty_stdout;
|
||||||
|
|
||||||
/// A writer that supports coloring with either line or block buffering.
|
/// A writer that supports coloring with either line or block buffering.
|
||||||
pub struct StandardStream(StandardStreamKind);
|
pub struct StandardStream(StandardStreamKind);
|
||||||
15
crates/core/README.md
Normal file
15
crates/core/README.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
ripgrep core
|
||||||
|
------------
|
||||||
|
This is the core ripgrep crate. In particular, `main.rs` is where the `main`
|
||||||
|
function lives.
|
||||||
|
|
||||||
|
Most of ripgrep core consists of two things:
|
||||||
|
|
||||||
|
* The definition of the CLI interface, including docs for every flag.
|
||||||
|
* Glue code that brings the `grep-matcher`, `grep-regex`, `grep-searcher` and
|
||||||
|
`grep-printer` crates together to actually execute the search.
|
||||||
|
|
||||||
|
Currently, there are no plans to make ripgrep core available as an independent
|
||||||
|
library. However, much of the heavy lifting of ripgrep is done via its
|
||||||
|
constituent crates, which can be reused independent of ripgrep. Unfortunately,
|
||||||
|
there is no guide or tutorial to teach folks how to do this yet.
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -17,11 +17,8 @@ use grep::pcre2::{
|
|||||||
RegexMatcherBuilder as PCRE2RegexMatcherBuilder,
|
RegexMatcherBuilder as PCRE2RegexMatcherBuilder,
|
||||||
};
|
};
|
||||||
use grep::printer::{
|
use grep::printer::{
|
||||||
ColorSpecs, Stats,
|
default_color_specs, ColorSpecs, JSONBuilder, Standard, StandardBuilder,
|
||||||
JSON, JSONBuilder,
|
Stats, Summary, SummaryBuilder, SummaryKind, JSON,
|
||||||
Standard, StandardBuilder,
|
|
||||||
Summary, SummaryBuilder, SummaryKind,
|
|
||||||
default_color_specs,
|
|
||||||
};
|
};
|
||||||
use grep::regex::{
|
use grep::regex::{
|
||||||
RegexMatcher as RustRegexMatcher,
|
RegexMatcher as RustRegexMatcher,
|
||||||
@@ -34,17 +31,13 @@ use ignore::overrides::{Override, OverrideBuilder};
|
|||||||
use ignore::types::{FileTypeDef, Types, TypesBuilder};
|
use ignore::types::{FileTypeDef, Types, TypesBuilder};
|
||||||
use ignore::{Walk, WalkBuilder, WalkParallel};
|
use ignore::{Walk, WalkBuilder, WalkParallel};
|
||||||
use log;
|
use log;
|
||||||
use num_cpus;
|
|
||||||
use regex;
|
use regex;
|
||||||
use termcolor::{
|
use termcolor::{BufferWriter, ColorChoice, WriteColor};
|
||||||
WriteColor,
|
|
||||||
BufferWriter, ColorChoice,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::app;
|
use crate::app;
|
||||||
use crate::config;
|
use crate::config;
|
||||||
use crate::logger::Logger;
|
use crate::logger::Logger;
|
||||||
use crate::messages::{set_messages, set_ignore_messages};
|
use crate::messages::{set_ignore_messages, set_messages};
|
||||||
use crate::path_printer::{PathPrinter, PathPrinterBuilder};
|
use crate::path_printer::{PathPrinter, PathPrinterBuilder};
|
||||||
use crate::search::{
|
use crate::search::{
|
||||||
PatternMatcher, Printer, SearchWorker, SearchWorkerBuilder,
|
PatternMatcher, Printer, SearchWorker, SearchWorkerBuilder,
|
||||||
@@ -84,11 +77,9 @@ impl Command {
|
|||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
Search | SearchParallel => true,
|
Search | SearchParallel => true,
|
||||||
| SearchNever
|
SearchNever | Files | FilesParallel | Types | PCRE2Version => {
|
||||||
| Files
|
false
|
||||||
| FilesParallel
|
}
|
||||||
| Types
|
|
||||||
| PCRE2Version => false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -105,14 +96,17 @@ pub struct Args(Arc<ArgsImp>);
|
|||||||
struct ArgsImp {
|
struct ArgsImp {
|
||||||
/// Mid-to-low level routines for extracting CLI arguments.
|
/// Mid-to-low level routines for extracting CLI arguments.
|
||||||
matches: ArgMatches,
|
matches: ArgMatches,
|
||||||
/// The patterns provided at the command line and/or via the -f/--file
|
/// The command we want to execute.
|
||||||
/// flag. This may be empty.
|
command: Command,
|
||||||
patterns: Vec<String>,
|
/// The number of threads to use. This is based in part on available
|
||||||
|
/// threads, in part on the number of threads requested and in part on the
|
||||||
|
/// command we're running.
|
||||||
|
threads: usize,
|
||||||
/// A matcher built from the patterns.
|
/// A matcher built from the patterns.
|
||||||
///
|
///
|
||||||
/// It's important that this is only built once, since building this goes
|
/// It's important that this is only built once, since building this goes
|
||||||
/// through regex compilation and various types of analyses. That is, if
|
/// through regex compilation and various types of analyses. That is, if
|
||||||
/// you need many of theses (one per thread, for example), it is better to
|
/// you need many of these (one per thread, for example), it is better to
|
||||||
/// build it once and then clone it.
|
/// build it once and then clone it.
|
||||||
matcher: PatternMatcher,
|
matcher: PatternMatcher,
|
||||||
/// The paths provided at the command line. This is guaranteed to be
|
/// The paths provided at the command line. This is guaranteed to be
|
||||||
@@ -173,12 +167,6 @@ impl Args {
|
|||||||
&self.0.matches
|
&self.0.matches
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the patterns found in the command line arguments. This includes
|
|
||||||
/// patterns read via the -f/--file flags.
|
|
||||||
fn patterns(&self) -> &[String] {
|
|
||||||
&self.0.patterns
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the matcher builder from the patterns.
|
/// Return the matcher builder from the patterns.
|
||||||
fn matcher(&self) -> &PatternMatcher {
|
fn matcher(&self) -> &PatternMatcher {
|
||||||
&self.0.matcher
|
&self.0.matcher
|
||||||
@@ -194,7 +182,7 @@ impl Args {
|
|||||||
/// Returns true if and only if `paths` had to be populated with a default
|
/// Returns true if and only if `paths` had to be populated with a default
|
||||||
/// path, which occurs only when no paths were given as command line
|
/// path, which occurs only when no paths were given as command line
|
||||||
/// arguments.
|
/// arguments.
|
||||||
fn using_default_path(&self) -> bool {
|
pub fn using_default_path(&self) -> bool {
|
||||||
self.0.using_default_path
|
self.0.using_default_path
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,20 +193,17 @@ impl Args {
|
|||||||
fn printer<W: WriteColor>(&self, wtr: W) -> Result<Printer<W>> {
|
fn printer<W: WriteColor>(&self, wtr: W) -> Result<Printer<W>> {
|
||||||
match self.matches().output_kind() {
|
match self.matches().output_kind() {
|
||||||
OutputKind::Standard => {
|
OutputKind::Standard => {
|
||||||
let separator_search = self.command()? == Command::Search;
|
let separator_search = self.command() == Command::Search;
|
||||||
self.matches()
|
self.matches()
|
||||||
.printer_standard(self.paths(), wtr, separator_search)
|
.printer_standard(self.paths(), wtr, separator_search)
|
||||||
.map(Printer::Standard)
|
.map(Printer::Standard)
|
||||||
}
|
}
|
||||||
OutputKind::Summary => {
|
OutputKind::Summary => self
|
||||||
self.matches()
|
.matches()
|
||||||
.printer_summary(self.paths(), wtr)
|
.printer_summary(self.paths(), wtr)
|
||||||
.map(Printer::Summary)
|
.map(Printer::Summary),
|
||||||
}
|
|
||||||
OutputKind::JSON => {
|
OutputKind::JSON => {
|
||||||
self.matches()
|
self.matches().printer_json(wtr).map(Printer::JSON)
|
||||||
.printer_json(wtr)
|
|
||||||
.map(Printer::JSON)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -236,28 +221,8 @@ impl Args {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return the high-level command that ripgrep should run.
|
/// Return the high-level command that ripgrep should run.
|
||||||
pub fn command(&self) -> Result<Command> {
|
pub fn command(&self) -> Command {
|
||||||
let is_one_search = self.matches().is_one_search(self.paths());
|
self.0.command
|
||||||
let threads = self.matches().threads()?;
|
|
||||||
let one_thread = is_one_search || threads == 1;
|
|
||||||
|
|
||||||
Ok(if self.matches().is_present("pcre2-version") {
|
|
||||||
Command::PCRE2Version
|
|
||||||
} else if self.matches().is_present("type-list") {
|
|
||||||
Command::Types
|
|
||||||
} else if self.matches().is_present("files") {
|
|
||||||
if one_thread {
|
|
||||||
Command::Files
|
|
||||||
} else {
|
|
||||||
Command::FilesParallel
|
|
||||||
}
|
|
||||||
} else if self.matches().can_never_match(self.patterns()) {
|
|
||||||
Command::SearchNever
|
|
||||||
} else if one_thread {
|
|
||||||
Command::Search
|
|
||||||
} else {
|
|
||||||
Command::SearchParallel
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builder a path printer that can be used for printing just file paths,
|
/// Builder a path printer that can be used for printing just file paths,
|
||||||
@@ -301,7 +266,7 @@ impl Args {
|
|||||||
let mut builder = SearchWorkerBuilder::new();
|
let mut builder = SearchWorkerBuilder::new();
|
||||||
builder
|
builder
|
||||||
.json_stats(matches.is_present("json"))
|
.json_stats(matches.is_present("json"))
|
||||||
.preprocessor(matches.preprocessor())
|
.preprocessor(matches.preprocessor())?
|
||||||
.preprocessor_globs(matches.preprocessor_globs()?)
|
.preprocessor_globs(matches.preprocessor_globs()?)
|
||||||
.search_zip(matches.is_present("search-zip"))
|
.search_zip(matches.is_present("search-zip"))
|
||||||
.binary_detection_implicit(matches.binary_detection_implicit())
|
.binary_detection_implicit(matches.binary_detection_implicit())
|
||||||
@@ -315,7 +280,7 @@ impl Args {
|
|||||||
/// When this returns a `Stats` value, then it is guaranteed that the
|
/// When this returns a `Stats` value, then it is guaranteed that the
|
||||||
/// search worker will be configured to track statistics as well.
|
/// search worker will be configured to track statistics as well.
|
||||||
pub fn stats(&self) -> Result<Option<Stats>> {
|
pub fn stats(&self) -> Result<Option<Stats>> {
|
||||||
Ok(if self.command()?.is_search() && self.matches().stats() {
|
Ok(if self.command().is_search() && self.matches().stats() {
|
||||||
Some(Stats::new())
|
Some(Stats::new())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@@ -354,12 +319,18 @@ impl Args {
|
|||||||
|
|
||||||
/// Return a walker that never uses additional threads.
|
/// Return a walker that never uses additional threads.
|
||||||
pub fn walker(&self) -> Result<Walk> {
|
pub fn walker(&self) -> Result<Walk> {
|
||||||
Ok(self.matches().walker_builder(self.paths())?.build())
|
Ok(self
|
||||||
|
.matches()
|
||||||
|
.walker_builder(self.paths(), self.0.threads)?
|
||||||
|
.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a walker that never uses additional threads.
|
/// Return a parallel walker that may use additional threads.
|
||||||
pub fn walker_parallel(&self) -> Result<WalkParallel> {
|
pub fn walker_parallel(&self) -> Result<WalkParallel> {
|
||||||
Ok(self.matches().walker_builder(self.paths())?.build_parallel())
|
Ok(self
|
||||||
|
.matches()
|
||||||
|
.walker_builder(self.paths(), self.0.threads)?
|
||||||
|
.build_parallel())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,11 +376,11 @@ enum SortByKind {
|
|||||||
|
|
||||||
impl SortBy {
|
impl SortBy {
|
||||||
fn asc(kind: SortByKind) -> SortBy {
|
fn asc(kind: SortByKind) -> SortBy {
|
||||||
SortBy { reverse: false, kind: kind }
|
SortBy { reverse: false, kind }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn desc(kind: SortByKind) -> SortBy {
|
fn desc(kind: SortByKind) -> SortBy {
|
||||||
SortBy { reverse: true, kind: kind }
|
SortBy { reverse: true, kind }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn none() -> SortBy {
|
fn none() -> SortBy {
|
||||||
@@ -452,29 +423,23 @@ impl SortBy {
|
|||||||
}
|
}
|
||||||
SortByKind::LastModified => {
|
SortByKind::LastModified => {
|
||||||
builder.sort_by_file_path(move |a, b| {
|
builder.sort_by_file_path(move |a, b| {
|
||||||
sort_by_metadata_time(
|
sort_by_metadata_time(a, b, self.reverse, |md| {
|
||||||
a, b,
|
md.modified()
|
||||||
self.reverse,
|
})
|
||||||
|md| md.modified(),
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
SortByKind::LastAccessed => {
|
SortByKind::LastAccessed => {
|
||||||
builder.sort_by_file_path(move |a, b| {
|
builder.sort_by_file_path(move |a, b| {
|
||||||
sort_by_metadata_time(
|
sort_by_metadata_time(a, b, self.reverse, |md| {
|
||||||
a, b,
|
md.accessed()
|
||||||
self.reverse,
|
})
|
||||||
|md| md.accessed(),
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
SortByKind::Created => {
|
SortByKind::Created => {
|
||||||
builder.sort_by_file_path(move |a, b| {
|
builder.sort_by_file_path(move |a, b| {
|
||||||
sort_by_metadata_time(
|
sort_by_metadata_time(a, b, self.reverse, |md| {
|
||||||
a, b,
|
md.created()
|
||||||
self.reverse,
|
})
|
||||||
|md| md.created(),
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -520,7 +485,7 @@ impl EncodingMode {
|
|||||||
fn has_explicit_encoding(&self) -> bool {
|
fn has_explicit_encoding(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
EncodingMode::Some(_) => true,
|
EncodingMode::Some(_) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -568,19 +533,45 @@ impl ArgMatches {
|
|||||||
let patterns = self.patterns()?;
|
let patterns = self.patterns()?;
|
||||||
let matcher = self.matcher(&patterns)?;
|
let matcher = self.matcher(&patterns)?;
|
||||||
let mut paths = self.paths();
|
let mut paths = self.paths();
|
||||||
let using_default_path =
|
let using_default_path = if paths.is_empty() {
|
||||||
if paths.is_empty() {
|
paths.push(self.path_default());
|
||||||
paths.push(self.path_default());
|
true
|
||||||
true
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
// Now figure out the number of threads we'll use and which
|
||||||
|
// command will run.
|
||||||
|
let is_one_search = self.is_one_search(&paths);
|
||||||
|
let threads = if is_one_search { 1 } else { self.threads()? };
|
||||||
|
if threads == 1 {
|
||||||
|
log::debug!("running in single threaded mode");
|
||||||
|
} else {
|
||||||
|
log::debug!("running with {threads} threads for parallelism");
|
||||||
|
}
|
||||||
|
let command = if self.is_present("pcre2-version") {
|
||||||
|
Command::PCRE2Version
|
||||||
|
} else if self.is_present("type-list") {
|
||||||
|
Command::Types
|
||||||
|
} else if self.is_present("files") {
|
||||||
|
if threads == 1 {
|
||||||
|
Command::Files
|
||||||
} else {
|
} else {
|
||||||
false
|
Command::FilesParallel
|
||||||
};
|
}
|
||||||
|
} else if self.can_never_match(&patterns) {
|
||||||
|
Command::SearchNever
|
||||||
|
} else if threads == 1 {
|
||||||
|
Command::Search
|
||||||
|
} else {
|
||||||
|
Command::SearchParallel
|
||||||
|
};
|
||||||
Ok(Args(Arc::new(ArgsImp {
|
Ok(Args(Arc::new(ArgsImp {
|
||||||
matches: self,
|
matches: self,
|
||||||
patterns: patterns,
|
command,
|
||||||
matcher: matcher,
|
threads,
|
||||||
paths: paths,
|
matcher,
|
||||||
using_default_path: using_default_path,
|
paths,
|
||||||
|
using_default_path,
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -594,54 +585,78 @@ impl ArgMatches {
|
|||||||
///
|
///
|
||||||
/// If there was a problem building the matcher (e.g., a syntax error),
|
/// If there was a problem building the matcher (e.g., a syntax error),
|
||||||
/// then this returns an error.
|
/// then this returns an error.
|
||||||
#[cfg(feature = "pcre2")]
|
|
||||||
fn matcher(&self, patterns: &[String]) -> Result<PatternMatcher> {
|
fn matcher(&self, patterns: &[String]) -> Result<PatternMatcher> {
|
||||||
if self.is_present("pcre2") {
|
if self.is_present("pcre2") {
|
||||||
let matcher = self.matcher_pcre2(patterns)?;
|
self.matcher_engine("pcre2", patterns)
|
||||||
Ok(PatternMatcher::PCRE2(matcher))
|
|
||||||
} else if self.is_present("auto-hybrid-regex") {
|
} else if self.is_present("auto-hybrid-regex") {
|
||||||
let rust_err = match self.matcher_rust(patterns) {
|
self.matcher_engine("auto", patterns)
|
||||||
Ok(matcher) => return Ok(PatternMatcher::RustRegex(matcher)),
|
|
||||||
Err(err) => err,
|
|
||||||
};
|
|
||||||
log::debug!(
|
|
||||||
"error building Rust regex in hybrid mode:\n{}", rust_err,
|
|
||||||
);
|
|
||||||
let pcre_err = match self.matcher_pcre2(patterns) {
|
|
||||||
Ok(matcher) => return Ok(PatternMatcher::PCRE2(matcher)),
|
|
||||||
Err(err) => err,
|
|
||||||
};
|
|
||||||
Err(From::from(format!(
|
|
||||||
"regex could not be compiled with either the default regex \
|
|
||||||
engine or with PCRE2.\n\n\
|
|
||||||
default regex engine error:\n{}\n{}\n{}\n\n\
|
|
||||||
PCRE2 regex engine error:\n{}",
|
|
||||||
"~".repeat(79), rust_err, "~".repeat(79), pcre_err,
|
|
||||||
)))
|
|
||||||
} else {
|
} else {
|
||||||
let matcher = match self.matcher_rust(patterns) {
|
let engine = self.value_of_lossy("engine").unwrap();
|
||||||
Ok(matcher) => matcher,
|
self.matcher_engine(&engine, patterns)
|
||||||
Err(err) => {
|
|
||||||
return Err(From::from(suggest_pcre2(err.to_string())));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(PatternMatcher::RustRegex(matcher))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the matcher that should be used for searching.
|
/// Return the matcher that should be used for searching using engine
|
||||||
|
/// as the engine for the patterns.
|
||||||
///
|
///
|
||||||
/// If there was a problem building the matcher (e.g., a syntax error),
|
/// If there was a problem building the matcher (e.g., a syntax error),
|
||||||
/// then this returns an error.
|
/// then this returns an error.
|
||||||
#[cfg(not(feature = "pcre2"))]
|
fn matcher_engine(
|
||||||
fn matcher(&self, patterns: &[String]) -> Result<PatternMatcher> {
|
&self,
|
||||||
if self.is_present("pcre2") {
|
engine: &str,
|
||||||
return Err(From::from(
|
patterns: &[String],
|
||||||
|
) -> Result<PatternMatcher> {
|
||||||
|
match engine {
|
||||||
|
"default" => {
|
||||||
|
let matcher = match self.matcher_rust(patterns) {
|
||||||
|
Ok(matcher) => matcher,
|
||||||
|
Err(err) => {
|
||||||
|
return Err(From::from(suggest(err.to_string())));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(PatternMatcher::RustRegex(matcher))
|
||||||
|
}
|
||||||
|
#[cfg(feature = "pcre2")]
|
||||||
|
"pcre2" => {
|
||||||
|
let matcher = self.matcher_pcre2(patterns)?;
|
||||||
|
Ok(PatternMatcher::PCRE2(matcher))
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "pcre2"))]
|
||||||
|
"pcre2" => Err(From::from(
|
||||||
"PCRE2 is not available in this build of ripgrep",
|
"PCRE2 is not available in this build of ripgrep",
|
||||||
));
|
)),
|
||||||
|
"auto" => {
|
||||||
|
let rust_err = match self.matcher_rust(patterns) {
|
||||||
|
Ok(matcher) => {
|
||||||
|
return Ok(PatternMatcher::RustRegex(matcher));
|
||||||
|
}
|
||||||
|
Err(err) => err,
|
||||||
|
};
|
||||||
|
log::debug!(
|
||||||
|
"error building Rust regex in hybrid mode:\n{}",
|
||||||
|
rust_err,
|
||||||
|
);
|
||||||
|
|
||||||
|
let pcre_err = match self.matcher_engine("pcre2", patterns) {
|
||||||
|
Ok(matcher) => return Ok(matcher),
|
||||||
|
Err(err) => err,
|
||||||
|
};
|
||||||
|
Err(From::from(format!(
|
||||||
|
"regex could not be compiled with either the default \
|
||||||
|
regex engine or with PCRE2.\n\n\
|
||||||
|
default regex engine error:\n{}\n{}\n{}\n\n\
|
||||||
|
PCRE2 regex engine error:\n{}",
|
||||||
|
"~".repeat(79),
|
||||||
|
rust_err,
|
||||||
|
"~".repeat(79),
|
||||||
|
pcre_err,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
_ => Err(From::from(format!(
|
||||||
|
"unrecognized regex engine '{}'",
|
||||||
|
engine
|
||||||
|
))),
|
||||||
}
|
}
|
||||||
let matcher = self.matcher_rust(patterns)?;
|
|
||||||
Ok(PatternMatcher::RustRegex(matcher))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build a matcher using Rust's regex engine.
|
/// Build a matcher using Rust's regex engine.
|
||||||
@@ -654,20 +669,16 @@ impl ArgMatches {
|
|||||||
.case_smart(self.case_smart())
|
.case_smart(self.case_smart())
|
||||||
.case_insensitive(self.case_insensitive())
|
.case_insensitive(self.case_insensitive())
|
||||||
.multi_line(true)
|
.multi_line(true)
|
||||||
.unicode(true)
|
.unicode(self.unicode())
|
||||||
.octal(false)
|
.octal(false)
|
||||||
.word(self.is_present("word-regexp"));
|
.word(self.is_present("word-regexp"));
|
||||||
if self.is_present("multiline") {
|
if self.is_present("multiline") {
|
||||||
builder.dot_matches_new_line(self.is_present("multiline-dotall"));
|
builder.dot_matches_new_line(self.is_present("multiline-dotall"));
|
||||||
if self.is_present("crlf") {
|
if self.is_present("crlf") {
|
||||||
builder
|
builder.crlf(true).line_terminator(None);
|
||||||
.crlf(true)
|
|
||||||
.line_terminator(None);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
builder
|
builder.line_terminator(Some(b'\n')).dot_matches_new_line(false);
|
||||||
.line_terminator(Some(b'\n'))
|
|
||||||
.dot_matches_new_line(false);
|
|
||||||
if self.is_present("crlf") {
|
if self.is_present("crlf") {
|
||||||
builder.crlf(true);
|
builder.crlf(true);
|
||||||
}
|
}
|
||||||
@@ -686,12 +697,11 @@ impl ArgMatches {
|
|||||||
if let Some(limit) = self.dfa_size_limit()? {
|
if let Some(limit) = self.dfa_size_limit()? {
|
||||||
builder.dfa_size_limit(limit);
|
builder.dfa_size_limit(limit);
|
||||||
}
|
}
|
||||||
let res =
|
let res = if self.is_present("fixed-strings") {
|
||||||
if self.is_present("fixed-strings") {
|
builder.build_literals(patterns)
|
||||||
builder.build_literals(patterns)
|
} else {
|
||||||
} else {
|
builder.build(&patterns.join("|"))
|
||||||
builder.build(&patterns.join("|"))
|
};
|
||||||
};
|
|
||||||
match res {
|
match res {
|
||||||
Ok(m) => Ok(m),
|
Ok(m) => Ok(m),
|
||||||
Err(err) => Err(From::from(suggest_multiline(err.to_string()))),
|
Err(err) => Err(From::from(suggest_multiline(err.to_string()))),
|
||||||
@@ -718,9 +728,9 @@ impl ArgMatches {
|
|||||||
// The PCRE2 docs say that 32KB is the default, and that 1MB
|
// The PCRE2 docs say that 32KB is the default, and that 1MB
|
||||||
// should be big enough for anything. But let's crank it to
|
// should be big enough for anything. But let's crank it to
|
||||||
// 10MB.
|
// 10MB.
|
||||||
.max_jit_stack_size(Some(10 * (1<<20)));
|
.max_jit_stack_size(Some(10 * (1 << 20)));
|
||||||
}
|
}
|
||||||
if self.pcre2_unicode() {
|
if self.unicode() {
|
||||||
builder.utf(true).ucp(true);
|
builder.utf(true).ucp(true);
|
||||||
if self.encoding()?.has_explicit_encoding() {
|
if self.encoding()?.has_explicit_encoding() {
|
||||||
// SAFETY: If an encoding was specified, then we're guaranteed
|
// SAFETY: If an encoding was specified, then we're guaranteed
|
||||||
@@ -776,6 +786,7 @@ impl ArgMatches {
|
|||||||
.path(self.with_filename(paths))
|
.path(self.with_filename(paths))
|
||||||
.only_matching(self.is_present("only-matching"))
|
.only_matching(self.is_present("only-matching"))
|
||||||
.per_match(self.is_present("vimgrep"))
|
.per_match(self.is_present("vimgrep"))
|
||||||
|
.per_match_one_line(true)
|
||||||
.replacement(self.replacement())
|
.replacement(self.replacement())
|
||||||
.max_columns(self.max_columns()?)
|
.max_columns(self.max_columns()?)
|
||||||
.max_columns_preview(self.max_columns_preview())
|
.max_columns_preview(self.max_columns_preview())
|
||||||
@@ -784,9 +795,9 @@ impl ArgMatches {
|
|||||||
.byte_offset(self.is_present("byte-offset"))
|
.byte_offset(self.is_present("byte-offset"))
|
||||||
.trim_ascii(self.is_present("trim"))
|
.trim_ascii(self.is_present("trim"))
|
||||||
.separator_search(None)
|
.separator_search(None)
|
||||||
.separator_context(Some(self.context_separator()))
|
.separator_context(self.context_separator())
|
||||||
.separator_field_match(b":".to_vec())
|
.separator_field_match(self.field_match_separator())
|
||||||
.separator_field_context(b"-".to_vec())
|
.separator_field_context(self.field_context_separator())
|
||||||
.separator_path(self.path_separator()?)
|
.separator_path(self.path_separator()?)
|
||||||
.path_terminator(self.path_terminator());
|
.path_terminator(self.path_terminator());
|
||||||
if separator_search {
|
if separator_search {
|
||||||
@@ -812,6 +823,7 @@ impl ArgMatches {
|
|||||||
.stats(self.stats())
|
.stats(self.stats())
|
||||||
.path(self.with_filename(paths))
|
.path(self.with_filename(paths))
|
||||||
.max_matches(self.max_count()?)
|
.max_matches(self.max_count()?)
|
||||||
|
.exclude_zero(!self.is_present("include-zero"))
|
||||||
.separator_field(b":".to_vec())
|
.separator_field(b":".to_vec())
|
||||||
.separator_path(self.path_separator()?)
|
.separator_path(self.path_separator()?)
|
||||||
.path_terminator(self.path_terminator());
|
.path_terminator(self.path_terminator());
|
||||||
@@ -821,14 +833,13 @@ impl ArgMatches {
|
|||||||
/// Build a searcher from the command line parameters.
|
/// Build a searcher from the command line parameters.
|
||||||
fn searcher(&self, paths: &[PathBuf]) -> Result<Searcher> {
|
fn searcher(&self, paths: &[PathBuf]) -> Result<Searcher> {
|
||||||
let (ctx_before, ctx_after) = self.contexts()?;
|
let (ctx_before, ctx_after) = self.contexts()?;
|
||||||
let line_term =
|
let line_term = if self.is_present("crlf") {
|
||||||
if self.is_present("crlf") {
|
LineTerminator::crlf()
|
||||||
LineTerminator::crlf()
|
} else if self.is_present("null-data") {
|
||||||
} else if self.is_present("null-data") {
|
LineTerminator::byte(b'\x00')
|
||||||
LineTerminator::byte(b'\x00')
|
} else {
|
||||||
} else {
|
LineTerminator::byte(b'\n')
|
||||||
LineTerminator::byte(b'\n')
|
};
|
||||||
};
|
|
||||||
let mut builder = SearcherBuilder::new();
|
let mut builder = SearcherBuilder::new();
|
||||||
builder
|
builder
|
||||||
.line_terminator(line_term)
|
.line_terminator(line_term)
|
||||||
@@ -856,21 +867,27 @@ impl ArgMatches {
|
|||||||
///
|
///
|
||||||
/// If there was a problem parsing the CLI arguments necessary for
|
/// If there was a problem parsing the CLI arguments necessary for
|
||||||
/// constructing the builder, then this returns an error.
|
/// constructing the builder, then this returns an error.
|
||||||
fn walker_builder(&self, paths: &[PathBuf]) -> Result<WalkBuilder> {
|
fn walker_builder(
|
||||||
|
&self,
|
||||||
|
paths: &[PathBuf],
|
||||||
|
threads: usize,
|
||||||
|
) -> Result<WalkBuilder> {
|
||||||
let mut builder = WalkBuilder::new(&paths[0]);
|
let mut builder = WalkBuilder::new(&paths[0]);
|
||||||
for path in &paths[1..] {
|
for path in &paths[1..] {
|
||||||
builder.add(path);
|
builder.add(path);
|
||||||
}
|
}
|
||||||
for path in self.ignore_paths() {
|
if !self.no_ignore_files() {
|
||||||
if let Some(err) = builder.add_ignore(path) {
|
for path in self.ignore_paths() {
|
||||||
ignore_message!("{}", err);
|
if let Some(err) = builder.add_ignore(path) {
|
||||||
|
ignore_message!("{}", err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
builder
|
builder
|
||||||
.max_depth(self.usize_of("max-depth")?)
|
.max_depth(self.usize_of("max-depth")?)
|
||||||
.follow_links(self.is_present("follow"))
|
.follow_links(self.is_present("follow"))
|
||||||
.max_filesize(self.max_file_size()?)
|
.max_filesize(self.max_file_size()?)
|
||||||
.threads(self.threads()?)
|
.threads(threads)
|
||||||
.same_file_system(self.is_present("one-file-system"))
|
.same_file_system(self.is_present("one-file-system"))
|
||||||
.skip_stdout(!self.is_present("files"))
|
.skip_stdout(!self.is_present("files"))
|
||||||
.overrides(self.overrides()?)
|
.overrides(self.overrides()?)
|
||||||
@@ -880,7 +897,8 @@ impl ArgMatches {
|
|||||||
.ignore(!self.no_ignore_dot())
|
.ignore(!self.no_ignore_dot())
|
||||||
.git_global(!self.no_ignore_vcs() && !self.no_ignore_global())
|
.git_global(!self.no_ignore_vcs() && !self.no_ignore_global())
|
||||||
.git_ignore(!self.no_ignore_vcs())
|
.git_ignore(!self.no_ignore_vcs())
|
||||||
.git_exclude(!self.no_ignore_vcs())
|
.git_exclude(!self.no_ignore_vcs() && !self.no_ignore_exclude())
|
||||||
|
.require_git(!self.is_present("no-require-git"))
|
||||||
.ignore_case_insensitive(self.ignore_file_case_insensitive());
|
.ignore_case_insensitive(self.ignore_file_case_insensitive());
|
||||||
if !self.no_ignore() {
|
if !self.no_ignore() {
|
||||||
builder.add_custom_ignore_filename(".rgignore");
|
builder.add_custom_ignore_filename(".rgignore");
|
||||||
@@ -900,12 +918,9 @@ impl ArgMatches {
|
|||||||
/// Returns the form of binary detection to perform on files that are
|
/// Returns the form of binary detection to perform on files that are
|
||||||
/// implicitly searched via recursive directory traversal.
|
/// implicitly searched via recursive directory traversal.
|
||||||
fn binary_detection_implicit(&self) -> BinaryDetection {
|
fn binary_detection_implicit(&self) -> BinaryDetection {
|
||||||
let none =
|
let none = self.is_present("text") || self.is_present("null-data");
|
||||||
self.is_present("text")
|
|
||||||
|| self.is_present("null-data");
|
|
||||||
let convert =
|
let convert =
|
||||||
self.is_present("binary")
|
self.is_present("binary") || self.unrestricted_count() >= 3;
|
||||||
|| self.unrestricted_count() >= 3;
|
|
||||||
if none {
|
if none {
|
||||||
BinaryDetection::none()
|
BinaryDetection::none()
|
||||||
} else if convert {
|
} else if convert {
|
||||||
@@ -923,9 +938,7 @@ impl ArgMatches {
|
|||||||
/// as a filter (but quitting immediately once a NUL byte is seen), and we
|
/// as a filter (but quitting immediately once a NUL byte is seen), and we
|
||||||
/// should never filter out files that the user wants to explicitly search.
|
/// should never filter out files that the user wants to explicitly search.
|
||||||
fn binary_detection_explicit(&self) -> BinaryDetection {
|
fn binary_detection_explicit(&self) -> BinaryDetection {
|
||||||
let none =
|
let none = self.is_present("text") || self.is_present("null-data");
|
||||||
self.is_present("text")
|
|
||||||
|| self.is_present("null-data");
|
|
||||||
if none {
|
if none {
|
||||||
BinaryDetection::none()
|
BinaryDetection::none()
|
||||||
} else {
|
} else {
|
||||||
@@ -953,8 +966,8 @@ impl ArgMatches {
|
|||||||
/// case is disabled.
|
/// case is disabled.
|
||||||
fn case_smart(&self) -> bool {
|
fn case_smart(&self) -> bool {
|
||||||
self.is_present("smart-case")
|
self.is_present("smart-case")
|
||||||
&& !self.is_present("ignore-case")
|
&& !self.is_present("ignore-case")
|
||||||
&& !self.is_present("case-sensitive")
|
&& !self.is_present("case-sensitive")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the user's color choice based on command line parameters and
|
/// Returns the user's color choice based on command line parameters and
|
||||||
@@ -1010,20 +1023,20 @@ impl ArgMatches {
|
|||||||
let after = self.usize_of("after-context")?.unwrap_or(0);
|
let after = self.usize_of("after-context")?.unwrap_or(0);
|
||||||
let before = self.usize_of("before-context")?.unwrap_or(0);
|
let before = self.usize_of("before-context")?.unwrap_or(0);
|
||||||
let both = self.usize_of("context")?.unwrap_or(0);
|
let both = self.usize_of("context")?.unwrap_or(0);
|
||||||
Ok(if both > 0 {
|
Ok(if both > 0 { (both, both) } else { (before, after) })
|
||||||
(both, both)
|
|
||||||
} else {
|
|
||||||
(before, after)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the unescaped context separator in UTF-8 bytes.
|
/// Returns the unescaped context separator in UTF-8 bytes.
|
||||||
///
|
///
|
||||||
/// If one was not provided, the default `--` is returned.
|
/// If one was not provided, the default `--` is returned.
|
||||||
fn context_separator(&self) -> Vec<u8> {
|
/// If --no-context-separator is passed, None is returned.
|
||||||
match self.value_of_os("context-separator") {
|
fn context_separator(&self) -> Option<Vec<u8>> {
|
||||||
None => b"--".to_vec(),
|
let nosep = self.is_present("no-context-separator");
|
||||||
Some(sep) => cli::unescape_os(&sep),
|
let sep = self.value_of_os("context-separator");
|
||||||
|
match (nosep, sep) {
|
||||||
|
(true, _) => None,
|
||||||
|
(false, None) => Some(b"--".to_vec()),
|
||||||
|
(false, Some(sep)) => Some(cli::unescape_os(&sep)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1092,7 +1105,7 @@ impl ArgMatches {
|
|||||||
Ok(if self.heading() {
|
Ok(if self.heading() {
|
||||||
Some(b"".to_vec())
|
Some(b"".to_vec())
|
||||||
} else if ctx_before > 0 || ctx_after > 0 {
|
} else if ctx_before > 0 || ctx_after > 0 {
|
||||||
Some(self.context_separator().clone())
|
self.context_separator()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
})
|
})
|
||||||
@@ -1105,8 +1118,8 @@ impl ArgMatches {
|
|||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
cli::is_tty_stdout()
|
cli::is_tty_stdout()
|
||||||
|| self.is_present("heading")
|
|| self.is_present("heading")
|
||||||
|| self.is_present("pretty")
|
|| self.is_present("pretty")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1162,10 +1175,10 @@ impl ArgMatches {
|
|||||||
// tty for human consumption, except for one interesting case: when
|
// tty for human consumption, except for one interesting case: when
|
||||||
// we're only searching stdin. This makes pipelines work as expected.
|
// we're only searching stdin. This makes pipelines work as expected.
|
||||||
(cli::is_tty_stdout() && !self.is_only_stdin(paths))
|
(cli::is_tty_stdout() && !self.is_only_stdin(paths))
|
||||||
|| self.is_present("line-number")
|
|| self.is_present("line-number")
|
||||||
|| self.is_present("column")
|
|| self.is_present("column")
|
||||||
|| self.is_present("pretty")
|
|| self.is_present("pretty")
|
||||||
|| self.is_present("vimgrep")
|
|| self.is_present("vimgrep")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The maximum number of columns allowed on each line.
|
/// The maximum number of columns allowed on each line.
|
||||||
@@ -1226,6 +1239,19 @@ impl ArgMatches {
|
|||||||
self.is_present("no-ignore-dot") || self.no_ignore()
|
self.is_present("no-ignore-dot") || self.no_ignore()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if local exclude (ignore) files should be ignored.
|
||||||
|
fn no_ignore_exclude(&self) -> bool {
|
||||||
|
self.is_present("no-ignore-exclude") || self.no_ignore()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if explicitly given ignore files should be ignored.
|
||||||
|
fn no_ignore_files(&self) -> bool {
|
||||||
|
// We don't look at no-ignore here because --no-ignore is explicitly
|
||||||
|
// documented to not override --ignore-file. We could change this, but
|
||||||
|
// it would be a fairly severe breaking change.
|
||||||
|
self.is_present("no-ignore-files")
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if global ignore files should be ignored.
|
/// Returns true if global ignore files should be ignored.
|
||||||
fn no_ignore_global(&self) -> bool {
|
fn no_ignore_global(&self) -> bool {
|
||||||
self.is_present("no-ignore-global") || self.no_ignore()
|
self.is_present("no-ignore-global") || self.no_ignore()
|
||||||
@@ -1253,8 +1279,7 @@ impl ArgMatches {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let (count, count_matches) = self.counts();
|
let (count, count_matches) = self.counts();
|
||||||
let summary =
|
let summary = count
|
||||||
count
|
|
||||||
|| count_matches
|
|| count_matches
|
||||||
|| self.is_present("files-with-matches")
|
|| self.is_present("files-with-matches")
|
||||||
|| self.is_present("files-without-match");
|
|| self.is_present("files-without-match");
|
||||||
@@ -1267,13 +1292,23 @@ impl ArgMatches {
|
|||||||
|
|
||||||
/// Builds the set of glob overrides from the command line flags.
|
/// Builds the set of glob overrides from the command line flags.
|
||||||
fn overrides(&self) -> Result<Override> {
|
fn overrides(&self) -> Result<Override> {
|
||||||
let mut builder = OverrideBuilder::new(env::current_dir()?);
|
let globs = self.values_of_lossy_vec("glob");
|
||||||
for glob in self.values_of_lossy_vec("glob") {
|
let iglobs = self.values_of_lossy_vec("iglob");
|
||||||
|
if globs.is_empty() && iglobs.is_empty() {
|
||||||
|
return Ok(Override::empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut builder = OverrideBuilder::new(current_dir()?);
|
||||||
|
// Make all globs case insensitive with --glob-case-insensitive.
|
||||||
|
if self.is_present("glob-case-insensitive") {
|
||||||
|
builder.case_insensitive(true).unwrap();
|
||||||
|
}
|
||||||
|
for glob in globs {
|
||||||
builder.add(&glob)?;
|
builder.add(&glob)?;
|
||||||
}
|
}
|
||||||
// This only enables case insensitivity for subsequent globs.
|
// This only enables case insensitivity for subsequent globs.
|
||||||
builder.case_insensitive(true).unwrap();
|
builder.case_insensitive(true).unwrap();
|
||||||
for glob in self.values_of_lossy_vec("iglob") {
|
for glob in iglobs {
|
||||||
builder.add(&glob)?;
|
builder.add(&glob)?;
|
||||||
}
|
}
|
||||||
Ok(builder.build()?)
|
Ok(builder.build()?)
|
||||||
@@ -1304,10 +1339,10 @@ impl ArgMatches {
|
|||||||
/// be used when ripgrep is not otherwise given at least one file path
|
/// be used when ripgrep is not otherwise given at least one file path
|
||||||
/// as a positional argument.
|
/// as a positional argument.
|
||||||
fn path_default(&self) -> PathBuf {
|
fn path_default(&self) -> PathBuf {
|
||||||
let file_is_stdin = self.values_of_os("file")
|
let file_is_stdin = self
|
||||||
|
.values_of_os("file")
|
||||||
.map_or(false, |mut files| files.any(|f| f == "-"));
|
.map_or(false, |mut files| files.any(|f| f == "-"));
|
||||||
let search_cwd =
|
let search_cwd = !cli::is_readable_stdin()
|
||||||
!cli::is_readable_stdin()
|
|
||||||
|| (self.is_present("file") && file_is_stdin)
|
|| (self.is_present("file") && file_is_stdin)
|
||||||
|| self.is_present("files")
|
|| self.is_present("files")
|
||||||
|| self.is_present("type-list")
|
|| self.is_present("type-list")
|
||||||
@@ -1336,8 +1371,8 @@ impl ArgMatches {
|
|||||||
the given separator is {} bytes: {}\n\
|
the given separator is {} bytes: {}\n\
|
||||||
In some shells on Windows '/' is automatically \
|
In some shells on Windows '/' is automatically \
|
||||||
expanded. Use '//' instead.",
|
expanded. Use '//' instead.",
|
||||||
sep.len(),
|
sep.len(),
|
||||||
cli::escape(&sep),
|
cli::escape(&sep),
|
||||||
)))
|
)))
|
||||||
} else {
|
} else {
|
||||||
Ok(Some(sep[0]))
|
Ok(Some(sep[0]))
|
||||||
@@ -1356,6 +1391,24 @@ impl ArgMatches {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the unescaped field context separator. If one wasn't specified,
|
||||||
|
/// then '-' is used as the default.
|
||||||
|
fn field_context_separator(&self) -> Vec<u8> {
|
||||||
|
match self.value_of_os("field-context-separator") {
|
||||||
|
None => b"-".to_vec(),
|
||||||
|
Some(sep) => cli::unescape_os(&sep),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the unescaped field match separator. If one wasn't specified,
|
||||||
|
/// then ':' is used as the default.
|
||||||
|
fn field_match_separator(&self) -> Vec<u8> {
|
||||||
|
match self.value_of_os("field-match-separator") {
|
||||||
|
None => b":".to_vec(),
|
||||||
|
Some(sep) => cli::unescape_os(&sep),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a sequence of all available patterns from the command line.
|
/// Get a sequence of all available patterns from the command line.
|
||||||
/// This includes reading the -e/--regexp and -f/--file flags.
|
/// This includes reading the -e/--regexp and -f/--file flags.
|
||||||
///
|
///
|
||||||
@@ -1387,14 +1440,16 @@ impl ArgMatches {
|
|||||||
if let Some(paths) = self.values_of_os("file") {
|
if let Some(paths) = self.values_of_os("file") {
|
||||||
for path in paths {
|
for path in paths {
|
||||||
if path == "-" {
|
if path == "-" {
|
||||||
pats.extend(cli::patterns_from_stdin()?
|
pats.extend(
|
||||||
.into_iter()
|
cli::patterns_from_stdin()?
|
||||||
.map(|p| self.pattern_from_string(p))
|
.into_iter()
|
||||||
|
.map(|p| self.pattern_from_string(p)),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
pats.extend(cli::patterns_from_path(path)?
|
pats.extend(
|
||||||
.into_iter()
|
cli::patterns_from_path(path)?
|
||||||
.map(|p| self.pattern_from_string(p))
|
.into_iter()
|
||||||
|
.map(|p| self.pattern_from_string(p)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1475,8 +1530,12 @@ impl ArgMatches {
|
|||||||
/// flag. If no --pre-globs are available, then this always returns an
|
/// flag. If no --pre-globs are available, then this always returns an
|
||||||
/// empty set of globs.
|
/// empty set of globs.
|
||||||
fn preprocessor_globs(&self) -> Result<Override> {
|
fn preprocessor_globs(&self) -> Result<Override> {
|
||||||
let mut builder = OverrideBuilder::new(env::current_dir()?);
|
let globs = self.values_of_lossy_vec("pre-glob");
|
||||||
for glob in self.values_of_lossy_vec("pre-glob") {
|
if globs.is_empty() {
|
||||||
|
return Ok(Override::empty());
|
||||||
|
}
|
||||||
|
let mut builder = OverrideBuilder::new(current_dir()?);
|
||||||
|
for glob in globs {
|
||||||
builder.add(&glob)?;
|
builder.add(&glob)?;
|
||||||
}
|
}
|
||||||
Ok(builder.build()?)
|
Ok(builder.build()?)
|
||||||
@@ -1503,7 +1562,7 @@ impl ArgMatches {
|
|||||||
None => match self.value_of_lossy("sortr") {
|
None => match self.value_of_lossy("sortr") {
|
||||||
None => return Ok(SortBy::none()),
|
None => return Ok(SortBy::none()),
|
||||||
Some(choice) => SortBy::desc(SortByKind::new(&choice)),
|
Some(choice) => SortBy::desc(SortByKind::new(&choice)),
|
||||||
}
|
},
|
||||||
Some(choice) => SortBy::asc(SortByKind::new(&choice)),
|
Some(choice) => SortBy::asc(SortByKind::new(&choice)),
|
||||||
};
|
};
|
||||||
Ok(sortby)
|
Ok(sortby)
|
||||||
@@ -1514,7 +1573,7 @@ impl ArgMatches {
|
|||||||
///
|
///
|
||||||
/// Generally, this is only enabled when explicitly requested by in the
|
/// Generally, this is only enabled when explicitly requested by in the
|
||||||
/// command line arguments via the --stats flag, but this can also be
|
/// command line arguments via the --stats flag, but this can also be
|
||||||
/// enabled implicity via the output format, e.g., for JSON Lines.
|
/// enabled implicitly via the output format, e.g., for JSON Lines.
|
||||||
fn stats(&self) -> bool {
|
fn stats(&self) -> bool {
|
||||||
self.output_kind() == OutputKind::JSON || self.is_present("stats")
|
self.output_kind() == OutputKind::JSON || self.is_present("stats")
|
||||||
}
|
}
|
||||||
@@ -1546,11 +1605,9 @@ impl ArgMatches {
|
|||||||
return Ok(1);
|
return Ok(1);
|
||||||
}
|
}
|
||||||
let threads = self.usize_of("threads")?.unwrap_or(0);
|
let threads = self.usize_of("threads")?.unwrap_or(0);
|
||||||
Ok(if threads == 0 {
|
let available =
|
||||||
cmp::min(12, num_cpus::get())
|
std::thread::available_parallelism().map_or(1, |n| n.get());
|
||||||
} else {
|
Ok(if threads == 0 { cmp::min(12, available) } else { threads })
|
||||||
threads
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a file type matcher from the command line flags.
|
/// Builds a file type matcher from the command line flags.
|
||||||
@@ -1577,11 +1634,17 @@ impl ArgMatches {
|
|||||||
self.occurrences_of("unrestricted")
|
self.occurrences_of("unrestricted")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if and only if PCRE2's Unicode mode should be enabled.
|
/// Returns true if and only if Unicode mode should be enabled.
|
||||||
|
fn unicode(&self) -> bool {
|
||||||
|
// Unicode mode is enabled by default, so only disable it when
|
||||||
|
// --no-unicode is given explicitly.
|
||||||
|
!(self.is_present("no-unicode") || self.is_present("no-pcre2-unicode"))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if and only if PCRE2 is enabled and its Unicode mode is
|
||||||
|
/// enabled.
|
||||||
fn pcre2_unicode(&self) -> bool {
|
fn pcre2_unicode(&self) -> bool {
|
||||||
// PCRE2 Unicode is enabled by default, so only disable it when told
|
self.is_present("pcre2") && self.unicode()
|
||||||
// to do so explicitly.
|
|
||||||
self.is_present("pcre2") && !self.is_present("no-pcre2-unicode")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if and only if file names containing each match should
|
/// Returns true if and only if file names containing each match should
|
||||||
@@ -1590,10 +1653,13 @@ impl ArgMatches {
|
|||||||
if self.is_present("no-filename") {
|
if self.is_present("no-filename") {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
|
let path_stdin = Path::new("-");
|
||||||
self.is_present("with-filename")
|
self.is_present("with-filename")
|
||||||
|| self.is_present("vimgrep")
|
|| self.is_present("vimgrep")
|
||||||
|| paths.len() > 1
|
|| paths.len() > 1
|
||||||
|| paths.get(0).map_or(false, |p| p.is_dir())
|
|| paths
|
||||||
|
.get(0)
|
||||||
|
.map_or(false, |p| p != path_stdin && p.is_dir())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1616,11 +1682,7 @@ impl ArgMatches {
|
|||||||
None => return Ok(None),
|
None => return Ok(None),
|
||||||
Some(n) => n,
|
Some(n) => n,
|
||||||
};
|
};
|
||||||
Ok(if n == 0 {
|
Ok(if n == 0 { None } else { Some(n) })
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(n)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Safely reads an arg value with the given name, and if it's present,
|
/// Safely reads an arg value with the given name, and if it's present,
|
||||||
@@ -1673,32 +1735,57 @@ impl ArgMatches {
|
|||||||
self.0.value_of_os(name)
|
self.0.value_of_os(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn values_of_os(&self, name: &str) -> Option<clap::OsValues> {
|
fn values_of_os(&self, name: &str) -> Option<clap::OsValues<'_>> {
|
||||||
self.0.values_of_os(name)
|
self.0.values_of_os(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Inspect an error resulting from building a Rust regex matcher, and if it's
|
||||||
|
/// believed to correspond to a syntax error that another engine could handle,
|
||||||
|
/// then add a message to suggest the use of the engine flag.
|
||||||
|
fn suggest(msg: String) -> String {
|
||||||
|
if let Some(pcre_msg) = suggest_pcre2(&msg) {
|
||||||
|
return pcre_msg;
|
||||||
|
}
|
||||||
|
msg
|
||||||
|
}
|
||||||
|
|
||||||
/// Inspect an error resulting from building a Rust regex matcher, and if it's
|
/// Inspect an error resulting from building a Rust regex matcher, and if it's
|
||||||
/// believed to correspond to a syntax error that PCRE2 could handle, then
|
/// believed to correspond to a syntax error that PCRE2 could handle, then
|
||||||
/// add a message to suggest the use of -P/--pcre2.
|
/// add a message to suggest the use of -P/--pcre2.
|
||||||
#[cfg(feature = "pcre2")]
|
fn suggest_pcre2(msg: &str) -> Option<String> {
|
||||||
fn suggest_pcre2(msg: String) -> String {
|
#[cfg(feature = "pcre2")]
|
||||||
if !msg.contains("backreferences") && !msg.contains("look-around") {
|
fn suggest(msg: &str) -> Option<String> {
|
||||||
msg
|
if !msg.contains("backreferences") && !msg.contains("look-around") {
|
||||||
} else {
|
None
|
||||||
format!("{}
|
} else {
|
||||||
|
Some(format!(
|
||||||
|
"{}
|
||||||
|
|
||||||
Consider enabling PCRE2 with the --pcre2 flag, which can handle backreferences
|
Consider enabling PCRE2 with the --pcre2 flag, which can handle backreferences
|
||||||
and look-around.", msg)
|
and look-around.",
|
||||||
|
msg
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "pcre2"))]
|
||||||
|
fn suggest(_: &str) -> Option<String> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
suggest(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suggest_multiline(msg: String) -> String {
|
fn suggest_multiline(msg: String) -> String {
|
||||||
if msg.contains("the literal") && msg.contains("not allowed") {
|
if msg.contains("the literal") && msg.contains("not allowed") {
|
||||||
format!("{}
|
format!(
|
||||||
|
"{}
|
||||||
|
|
||||||
Consider enabling multiline mode with the --multiline flag (or -U for short).
|
Consider enabling multiline mode with the --multiline flag (or -U for short).
|
||||||
When multiline mode is enabled, new line characters can be matched.", msg)
|
When multiline mode is enabled, new line characters can be matched.",
|
||||||
|
msg
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
msg
|
msg
|
||||||
}
|
}
|
||||||
@@ -1706,10 +1793,7 @@ When multiline mode is enabled, new line characters can be matched.", msg)
|
|||||||
|
|
||||||
/// Convert the result of parsing a human readable file size to a `usize`,
|
/// Convert the result of parsing a human readable file size to a `usize`,
|
||||||
/// failing if the type does not fit.
|
/// failing if the type does not fit.
|
||||||
fn u64_to_usize(
|
fn u64_to_usize(arg_name: &str, value: Option<u64>) -> Result<Option<usize>> {
|
||||||
arg_name: &str,
|
|
||||||
value: Option<u64>,
|
|
||||||
) -> Result<Option<usize>> {
|
|
||||||
use std::usize;
|
use std::usize;
|
||||||
|
|
||||||
let value = match value {
|
let value = match value {
|
||||||
@@ -1734,7 +1818,8 @@ fn sort_by_metadata_time<G>(
|
|||||||
reverse: bool,
|
reverse: bool,
|
||||||
get_time: G,
|
get_time: G,
|
||||||
) -> cmp::Ordering
|
) -> cmp::Ordering
|
||||||
where G: Fn(&fs::Metadata) -> io::Result<SystemTime>
|
where
|
||||||
|
G: Fn(&fs::Metadata) -> io::Result<SystemTime>,
|
||||||
{
|
{
|
||||||
let t1 = match p1.metadata().and_then(|md| get_time(&md)) {
|
let t1 = match p1.metadata().and_then(|md| get_time(&md)) {
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
@@ -1757,11 +1842,10 @@ where G: Fn(&fs::Metadata) -> io::Result<SystemTime>
|
|||||||
/// corresponds to a `--help` or `--version` request. In which case, the
|
/// corresponds to a `--help` or `--version` request. In which case, the
|
||||||
/// corresponding output is printed and the current process is exited
|
/// corresponding output is printed and the current process is exited
|
||||||
/// successfully.
|
/// successfully.
|
||||||
fn clap_matches<I, T>(
|
fn clap_matches<I, T>(args: I) -> Result<clap::ArgMatches<'static>>
|
||||||
args: I,
|
where
|
||||||
) -> Result<clap::ArgMatches<'static>>
|
I: IntoIterator<Item = T>,
|
||||||
where I: IntoIterator<Item=T>,
|
T: Into<OsString> + Clone,
|
||||||
T: Into<OsString> + Clone
|
|
||||||
{
|
{
|
||||||
let err = match app::app().get_matches_from_safe(args) {
|
let err = match app::app().get_matches_from_safe(args) {
|
||||||
Ok(matches) => return Ok(matches),
|
Ok(matches) => return Ok(matches),
|
||||||
@@ -1779,3 +1863,26 @@ where I: IntoIterator<Item=T>,
|
|||||||
let _ = write!(io::stdout(), "{}", err);
|
let _ = write!(io::stdout(), "{}", err);
|
||||||
process::exit(0);
|
process::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attempts to discover the current working directory. This mostly just defers
|
||||||
|
/// to the standard library, however, such things will fail if ripgrep is in
|
||||||
|
/// a directory that no longer exists. We attempt some fallback mechanisms,
|
||||||
|
/// such as querying the PWD environment variable, but otherwise return an
|
||||||
|
/// error.
|
||||||
|
fn current_dir() -> Result<PathBuf> {
|
||||||
|
let err = match env::current_dir() {
|
||||||
|
Err(err) => err,
|
||||||
|
Ok(cwd) => return Ok(cwd),
|
||||||
|
};
|
||||||
|
if let Some(cwd) = env::var_os("PWD") {
|
||||||
|
if !cwd.is_empty() {
|
||||||
|
return Ok(PathBuf::from(cwd));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(format!(
|
||||||
|
"failed to get current working directory: {} \
|
||||||
|
--- did your CWD get deleted?",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
.into())
|
||||||
|
}
|
||||||
@@ -4,12 +4,12 @@
|
|||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use std::ffi::OsString;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::ffi::OsString;
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use bstr::io::BufReadExt;
|
use bstr::{io::BufReadExt, ByteSlice};
|
||||||
use log;
|
use log;
|
||||||
|
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
@@ -28,7 +28,10 @@ pub fn args() -> Vec<OsString> {
|
|||||||
let (args, errs) = match parse(&config_path) {
|
let (args, errs) = match parse(&config_path) {
|
||||||
Ok((args, errs)) => (args, errs),
|
Ok((args, errs)) => (args, errs),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
message!("{}", err);
|
message!(
|
||||||
|
"failed to read the file specified in RIPGREP_CONFIG_PATH: {}",
|
||||||
|
err
|
||||||
|
);
|
||||||
return vec![];
|
return vec![];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -55,7 +58,7 @@ pub fn args() -> Vec<OsString> {
|
|||||||
/// for each line in addition to successfully parsed arguments.
|
/// for each line in addition to successfully parsed arguments.
|
||||||
fn parse<P: AsRef<Path>>(
|
fn parse<P: AsRef<Path>>(
|
||||||
path: P,
|
path: P,
|
||||||
) -> Result<(Vec<OsString>, Vec<Box<Error>>)> {
|
) -> Result<(Vec<OsString>, Vec<Box<dyn Error>>)> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
match File::open(&path) {
|
match File::open(&path) {
|
||||||
Ok(file) => parse_reader(file),
|
Ok(file) => parse_reader(file),
|
||||||
@@ -76,8 +79,8 @@ fn parse<P: AsRef<Path>>(
|
|||||||
/// in addition to successfully parsed arguments.
|
/// in addition to successfully parsed arguments.
|
||||||
fn parse_reader<R: io::Read>(
|
fn parse_reader<R: io::Read>(
|
||||||
rdr: R,
|
rdr: R,
|
||||||
) -> Result<(Vec<OsString>, Vec<Box<Error>>)> {
|
) -> Result<(Vec<OsString>, Vec<Box<dyn Error>>)> {
|
||||||
let bufrdr = io::BufReader::new(rdr);
|
let mut bufrdr = io::BufReader::new(rdr);
|
||||||
let (mut args, mut errs) = (vec![], vec![]);
|
let (mut args, mut errs) = (vec![], vec![]);
|
||||||
let mut line_number = 0;
|
let mut line_number = 0;
|
||||||
bufrdr.for_byte_line_with_terminator(|line| {
|
bufrdr.for_byte_line_with_terminator(|line| {
|
||||||
@@ -102,12 +105,13 @@ fn parse_reader<R: io::Read>(
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::ffi::OsString;
|
|
||||||
use super::parse_reader;
|
use super::parse_reader;
|
||||||
|
use std::ffi::OsString;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn basic() {
|
fn basic() {
|
||||||
let (args, errs) = parse_reader(&b"\
|
let (args, errs) = parse_reader(
|
||||||
|
&b"\
|
||||||
# Test
|
# Test
|
||||||
--context=0
|
--context=0
|
||||||
--smart-case
|
--smart-case
|
||||||
@@ -116,13 +120,13 @@ mod tests {
|
|||||||
|
|
||||||
# --bar
|
# --bar
|
||||||
--foo
|
--foo
|
||||||
"[..]).unwrap();
|
"[..],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert!(errs.is_empty());
|
assert!(errs.is_empty());
|
||||||
let args: Vec<String> =
|
let args: Vec<String> =
|
||||||
args.into_iter().map(|s| s.into_string().unwrap()).collect();
|
args.into_iter().map(|s| s.into_string().unwrap()).collect();
|
||||||
assert_eq!(args, vec![
|
assert_eq!(args, vec!["--context=0", "--smart-case", "-u", "--foo",]);
|
||||||
"--context=0", "--smart-case", "-u", "--foo",
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We test that we can handle invalid UTF-8 on Unix-like systems.
|
// We test that we can handle invalid UTF-8 on Unix-like systems.
|
||||||
@@ -131,32 +135,38 @@ mod tests {
|
|||||||
fn error() {
|
fn error() {
|
||||||
use std::os::unix::ffi::OsStringExt;
|
use std::os::unix::ffi::OsStringExt;
|
||||||
|
|
||||||
let (args, errs) = parse_reader(&b"\
|
let (args, errs) = parse_reader(
|
||||||
|
&b"\
|
||||||
quux
|
quux
|
||||||
foo\xFFbar
|
foo\xFFbar
|
||||||
baz
|
baz
|
||||||
"[..]).unwrap();
|
"[..],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert!(errs.is_empty());
|
assert!(errs.is_empty());
|
||||||
assert_eq!(args, vec![
|
assert_eq!(
|
||||||
OsString::from("quux"),
|
args,
|
||||||
OsString::from_vec(b"foo\xFFbar".to_vec()),
|
vec![
|
||||||
OsString::from("baz"),
|
OsString::from("quux"),
|
||||||
]);
|
OsString::from_vec(b"foo\xFFbar".to_vec()),
|
||||||
|
OsString::from("baz"),
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ... but test that invalid UTF-8 fails on Windows.
|
// ... but test that invalid UTF-8 fails on Windows.
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
fn error() {
|
fn error() {
|
||||||
let (args, errs) = parse_reader(&b"\
|
let (args, errs) = parse_reader(
|
||||||
|
&b"\
|
||||||
quux
|
quux
|
||||||
foo\xFFbar
|
foo\xFFbar
|
||||||
baz
|
baz
|
||||||
"[..]).unwrap();
|
"[..],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(errs.len(), 1);
|
assert_eq!(errs.len(), 1);
|
||||||
assert_eq!(args, vec![
|
assert_eq!(args, vec![OsString::from("quux"), OsString::from("baz"),]);
|
||||||
OsString::from("quux"),
|
|
||||||
OsString::from("baz"),
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -24,13 +24,13 @@ impl Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Log for Logger {
|
impl Log for Logger {
|
||||||
fn enabled(&self, _: &log::Metadata) -> bool {
|
fn enabled(&self, _: &log::Metadata<'_>) -> bool {
|
||||||
// We set the log level via log::set_max_level, so we don't need to
|
// We set the log level via log::set_max_level, so we don't need to
|
||||||
// implement filtering here.
|
// implement filtering here.
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn log(&self, record: &log::Record) {
|
fn log(&self, record: &log::Record<'_>) {
|
||||||
match (record.file(), record.line()) {
|
match (record.file(), record.line()) {
|
||||||
(Some(file), Some(line)) => {
|
(Some(file), Some(line)) => {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
|
use std::error;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::process;
|
use std::process;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::Mutex;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use ignore::WalkState;
|
use ignore::WalkState;
|
||||||
@@ -19,7 +20,30 @@ mod path_printer;
|
|||||||
mod search;
|
mod search;
|
||||||
mod subject;
|
mod subject;
|
||||||
|
|
||||||
type Result<T> = ::std::result::Result<T, Box<::std::error::Error>>;
|
// Since Rust no longer uses jemalloc by default, ripgrep will, by default,
|
||||||
|
// use the system allocator. On Linux, this would normally be glibc's
|
||||||
|
// allocator, which is pretty good. In particular, ripgrep does not have a
|
||||||
|
// particularly allocation heavy workload, so there really isn't much
|
||||||
|
// difference (for ripgrep's purposes) between glibc's allocator and jemalloc.
|
||||||
|
//
|
||||||
|
// However, when ripgrep is built with musl, this means ripgrep will use musl's
|
||||||
|
// allocator, which appears to be substantially worse. (musl's goal is not to
|
||||||
|
// have the fastest version of everything. Its goal is to be small and amenable
|
||||||
|
// to static compilation.) Even though ripgrep isn't particularly allocation
|
||||||
|
// heavy, musl's allocator appears to slow down ripgrep quite a bit. Therefore,
|
||||||
|
// when building with musl, we use jemalloc.
|
||||||
|
//
|
||||||
|
// We don't unconditionally use jemalloc because it can be nice to use the
|
||||||
|
// system's default allocator by default. Moreover, jemalloc seems to increase
|
||||||
|
// compilation times by a bit.
|
||||||
|
//
|
||||||
|
// Moreover, we only do this on 64-bit systems since jemalloc doesn't support
|
||||||
|
// i686.
|
||||||
|
#[cfg(all(target_env = "musl", target_pointer_width = "64"))]
|
||||||
|
#[global_allocator]
|
||||||
|
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
|
|
||||||
|
type Result<T> = ::std::result::Result<T, Box<dyn error::Error>>;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
if let Err(err) = Args::parse().and_then(try_main) {
|
if let Err(err) = Args::parse().and_then(try_main) {
|
||||||
@@ -31,16 +55,15 @@ fn main() {
|
|||||||
fn try_main(args: Args) -> Result<()> {
|
fn try_main(args: Args) -> Result<()> {
|
||||||
use args::Command::*;
|
use args::Command::*;
|
||||||
|
|
||||||
let matched =
|
let matched = match args.command() {
|
||||||
match args.command()? {
|
Search => search(&args),
|
||||||
Search => search(&args),
|
SearchParallel => search_parallel(&args),
|
||||||
SearchParallel => search_parallel(&args),
|
SearchNever => Ok(false),
|
||||||
SearchNever => Ok(false),
|
Files => files(&args),
|
||||||
Files => files(&args),
|
FilesParallel => files_parallel(&args),
|
||||||
FilesParallel => files_parallel(&args),
|
Types => types(&args),
|
||||||
Types => types(&args),
|
PCRE2Version => pcre2_version(&args),
|
||||||
PCRE2Version => pcre2_version(&args),
|
}?;
|
||||||
}?;
|
|
||||||
if matched && (args.quiet() || !messages::errored()) {
|
if matched && (args.quiet() || !messages::errored()) {
|
||||||
process::exit(0)
|
process::exit(0)
|
||||||
} else if messages::errored() {
|
} else if messages::errored() {
|
||||||
@@ -60,12 +83,14 @@ fn search(args: &Args) -> Result<bool> {
|
|||||||
let mut stats = args.stats()?;
|
let mut stats = args.stats()?;
|
||||||
let mut searcher = args.search_worker(args.stdout())?;
|
let mut searcher = args.search_worker(args.stdout())?;
|
||||||
let mut matched = false;
|
let mut matched = false;
|
||||||
|
let mut searched = false;
|
||||||
|
|
||||||
for result in args.walker()? {
|
for result in args.walker()? {
|
||||||
let subject = match subject_builder.build_from_result(result) {
|
let subject = match subject_builder.build_from_result(result) {
|
||||||
Some(subject) => subject,
|
Some(subject) => subject,
|
||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
|
searched = true;
|
||||||
let search_result = match searcher.search(&subject) {
|
let search_result = match searcher.search(&subject) {
|
||||||
Ok(search_result) => search_result,
|
Ok(search_result) => search_result,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -85,6 +110,9 @@ fn search(args: &Args) -> Result<bool> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if args.using_default_path() && !searched {
|
||||||
|
eprint_nothing_searched();
|
||||||
|
}
|
||||||
if let Some(ref stats) = stats {
|
if let Some(ref stats) = stats {
|
||||||
let elapsed = Instant::now().duration_since(started_at);
|
let elapsed = Instant::now().duration_since(started_at);
|
||||||
// We don't care if we couldn't print this successfully.
|
// We don't care if we couldn't print this successfully.
|
||||||
@@ -102,24 +130,23 @@ fn search_parallel(args: &Args) -> Result<bool> {
|
|||||||
|
|
||||||
let quit_after_match = args.quit_after_match()?;
|
let quit_after_match = args.quit_after_match()?;
|
||||||
let started_at = Instant::now();
|
let started_at = Instant::now();
|
||||||
let subject_builder = Arc::new(args.subject_builder());
|
let subject_builder = args.subject_builder();
|
||||||
let bufwtr = Arc::new(args.buffer_writer()?);
|
let bufwtr = args.buffer_writer()?;
|
||||||
let stats = Arc::new(args.stats()?.map(Mutex::new));
|
let stats = args.stats()?.map(Mutex::new);
|
||||||
let matched = Arc::new(AtomicBool::new(false));
|
let matched = AtomicBool::new(false);
|
||||||
|
let searched = AtomicBool::new(false);
|
||||||
let mut searcher_err = None;
|
let mut searcher_err = None;
|
||||||
args.walker_parallel()?.run(|| {
|
args.walker_parallel()?.run(|| {
|
||||||
let args = args.clone();
|
let bufwtr = &bufwtr;
|
||||||
let bufwtr = Arc::clone(&bufwtr);
|
let stats = &stats;
|
||||||
let stats = Arc::clone(&stats);
|
let matched = &matched;
|
||||||
let matched = Arc::clone(&matched);
|
let searched = &searched;
|
||||||
let subject_builder = Arc::clone(&subject_builder);
|
let subject_builder = &subject_builder;
|
||||||
let mut searcher = match args.search_worker(bufwtr.buffer()) {
|
let mut searcher = match args.search_worker(bufwtr.buffer()) {
|
||||||
Ok(searcher) => searcher,
|
Ok(searcher) => searcher,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
searcher_err = Some(err);
|
searcher_err = Some(err);
|
||||||
return Box::new(move |_| {
|
return Box::new(move |_| WalkState::Quit);
|
||||||
WalkState::Quit
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -128,6 +155,7 @@ fn search_parallel(args: &Args) -> Result<bool> {
|
|||||||
Some(subject) => subject,
|
Some(subject) => subject,
|
||||||
None => return WalkState::Continue,
|
None => return WalkState::Continue,
|
||||||
};
|
};
|
||||||
|
searched.store(true, SeqCst);
|
||||||
searcher.printer().get_mut().clear();
|
searcher.printer().get_mut().clear();
|
||||||
let search_result = match searcher.search(&subject) {
|
let search_result = match searcher.search(&subject) {
|
||||||
Ok(search_result) => search_result,
|
Ok(search_result) => search_result,
|
||||||
@@ -161,7 +189,10 @@ fn search_parallel(args: &Args) -> Result<bool> {
|
|||||||
if let Some(err) = searcher_err.take() {
|
if let Some(err) = searcher_err.take() {
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
if let Some(ref locked_stats) = *stats {
|
if args.using_default_path() && !searched.load(SeqCst) {
|
||||||
|
eprint_nothing_searched();
|
||||||
|
}
|
||||||
|
if let Some(ref locked_stats) = stats {
|
||||||
let elapsed = Instant::now().duration_since(started_at);
|
let elapsed = Instant::now().duration_since(started_at);
|
||||||
let stats = locked_stats.lock().unwrap();
|
let stats = locked_stats.lock().unwrap();
|
||||||
let mut searcher = args.search_worker(args.stdout())?;
|
let mut searcher = args.search_worker(args.stdout())?;
|
||||||
@@ -171,6 +202,14 @@ fn search_parallel(args: &Args) -> Result<bool> {
|
|||||||
Ok(matched.load(SeqCst))
|
Ok(matched.load(SeqCst))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn eprint_nothing_searched() {
|
||||||
|
err_message!(
|
||||||
|
"No files were searched, which means ripgrep probably \
|
||||||
|
applied a filter you didn't expect.\n\
|
||||||
|
Running with --debug will show why files are being skipped."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// The top-level entry point for listing files without searching them. This
|
/// The top-level entry point for listing files without searching them. This
|
||||||
/// recursively steps through the file list (current directory by default) and
|
/// recursively steps through the file list (current directory by default) and
|
||||||
/// prints each path sequentially using a single thread.
|
/// prints each path sequentially using a single thread.
|
||||||
@@ -211,9 +250,9 @@ fn files_parallel(args: &Args) -> Result<bool> {
|
|||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
let quit_after_match = args.quit_after_match()?;
|
let quit_after_match = args.quit_after_match()?;
|
||||||
let subject_builder = Arc::new(args.subject_builder());
|
let subject_builder = args.subject_builder();
|
||||||
let mut path_printer = args.path_printer(args.stdout())?;
|
let mut path_printer = args.path_printer(args.stdout())?;
|
||||||
let matched = Arc::new(AtomicBool::new(false));
|
let matched = AtomicBool::new(false);
|
||||||
let (tx, rx) = mpsc::channel::<Subject>();
|
let (tx, rx) = mpsc::channel::<Subject>();
|
||||||
|
|
||||||
let print_thread = thread::spawn(move || -> io::Result<()> {
|
let print_thread = thread::spawn(move || -> io::Result<()> {
|
||||||
@@ -223,8 +262,8 @@ fn files_parallel(args: &Args) -> Result<bool> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
args.walker_parallel()?.run(|| {
|
args.walker_parallel()?.run(|| {
|
||||||
let subject_builder = Arc::clone(&subject_builder);
|
let subject_builder = &subject_builder;
|
||||||
let matched = Arc::clone(&matched);
|
let matched = &matched;
|
||||||
let tx = tx.clone();
|
let tx = tx.clone();
|
||||||
|
|
||||||
Box::new(move |result| {
|
Box::new(move |result| {
|
||||||
@@ -37,10 +37,7 @@ impl PathPrinterBuilder {
|
|||||||
/// Create a new path printer with the current configuration that writes
|
/// Create a new path printer with the current configuration that writes
|
||||||
/// paths to the given writer.
|
/// paths to the given writer.
|
||||||
pub fn build<W: WriteColor>(&self, wtr: W) -> PathPrinter<W> {
|
pub fn build<W: WriteColor>(&self, wtr: W) -> PathPrinter<W> {
|
||||||
PathPrinter {
|
PathPrinter { config: self.config.clone(), wtr }
|
||||||
config: self.config.clone(),
|
|
||||||
wtr: wtr,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the color specification for this printer.
|
/// Set the color specification for this printer.
|
||||||
@@ -7,9 +7,9 @@ use std::time::Duration;
|
|||||||
use grep::cli;
|
use grep::cli;
|
||||||
use grep::matcher::Matcher;
|
use grep::matcher::Matcher;
|
||||||
#[cfg(feature = "pcre2")]
|
#[cfg(feature = "pcre2")]
|
||||||
use grep::pcre2::{RegexMatcher as PCRE2RegexMatcher};
|
use grep::pcre2::RegexMatcher as PCRE2RegexMatcher;
|
||||||
use grep::printer::{JSON, Standard, Summary, Stats};
|
use grep::printer::{Standard, Stats, Summary, JSON};
|
||||||
use grep::regex::{RegexMatcher as RustRegexMatcher};
|
use grep::regex::RegexMatcher as RustRegexMatcher;
|
||||||
use grep::searcher::{BinaryDetection, Searcher};
|
use grep::searcher::{BinaryDetection, Searcher};
|
||||||
use ignore::overrides::Override;
|
use ignore::overrides::Override;
|
||||||
use serde_json as json;
|
use serde_json as json;
|
||||||
@@ -70,7 +70,7 @@ impl SearchWorkerBuilder {
|
|||||||
SearchWorkerBuilder {
|
SearchWorkerBuilder {
|
||||||
config: Config::default(),
|
config: Config::default(),
|
||||||
command_builder: cmd_builder,
|
command_builder: cmd_builder,
|
||||||
decomp_builder: decomp_builder,
|
decomp_builder,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,8 +86,12 @@ impl SearchWorkerBuilder {
|
|||||||
let command_builder = self.command_builder.clone();
|
let command_builder = self.command_builder.clone();
|
||||||
let decomp_builder = self.decomp_builder.clone();
|
let decomp_builder = self.decomp_builder.clone();
|
||||||
SearchWorker {
|
SearchWorker {
|
||||||
config, command_builder, decomp_builder,
|
config,
|
||||||
matcher, searcher, printer,
|
command_builder,
|
||||||
|
decomp_builder,
|
||||||
|
matcher,
|
||||||
|
searcher,
|
||||||
|
printer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,9 +115,14 @@ impl SearchWorkerBuilder {
|
|||||||
pub fn preprocessor(
|
pub fn preprocessor(
|
||||||
&mut self,
|
&mut self,
|
||||||
cmd: Option<PathBuf>,
|
cmd: Option<PathBuf>,
|
||||||
) -> &mut SearchWorkerBuilder {
|
) -> crate::Result<&mut SearchWorkerBuilder> {
|
||||||
self.config.preprocessor = cmd;
|
if let Some(ref prog) = cmd {
|
||||||
self
|
let bin = cli::resolve_binary(prog)?;
|
||||||
|
self.config.preprocessor = Some(bin);
|
||||||
|
} else {
|
||||||
|
self.config.preprocessor = None;
|
||||||
|
}
|
||||||
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the globs for determining which files should be run through the
|
/// Set the globs for determining which files should be run through the
|
||||||
@@ -227,9 +236,7 @@ impl<W: WriteColor> Printer<W> {
|
|||||||
stats: &Stats,
|
stats: &Stats,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
match *self {
|
match *self {
|
||||||
Printer::JSON(_) => {
|
Printer::JSON(_) => self.print_stats_json(total_duration, stats),
|
||||||
self.print_stats_json(total_duration, stats)
|
|
||||||
}
|
|
||||||
Printer::Standard(_) | Printer::Summary(_) => {
|
Printer::Standard(_) | Printer::Summary(_) => {
|
||||||
self.print_stats_human(total_duration, stats)
|
self.print_stats_human(total_duration, stats)
|
||||||
}
|
}
|
||||||
@@ -273,17 +280,20 @@ impl<W: WriteColor> Printer<W> {
|
|||||||
// the grep-printer crate. We simply "extend" it with the 'summary'
|
// the grep-printer crate. We simply "extend" it with the 'summary'
|
||||||
// message type.
|
// message type.
|
||||||
let fractional = fractional_seconds(total_duration);
|
let fractional = fractional_seconds(total_duration);
|
||||||
json::to_writer(self.get_mut(), &json!({
|
json::to_writer(
|
||||||
"type": "summary",
|
self.get_mut(),
|
||||||
"data": {
|
&json!({
|
||||||
"stats": stats,
|
"type": "summary",
|
||||||
"elapsed_total": {
|
"data": {
|
||||||
"secs": total_duration.as_secs(),
|
"stats": stats,
|
||||||
"nanos": total_duration.subsec_nanos(),
|
"elapsed_total": {
|
||||||
"human": format!("{:0.6}s", fractional),
|
"secs": total_duration.as_secs(),
|
||||||
},
|
"nanos": total_duration.subsec_nanos(),
|
||||||
}
|
"human": format!("{:0.6}s", fractional),
|
||||||
}))?;
|
},
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
write!(self.get_mut(), "\n")
|
write!(self.get_mut(), "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,7 +325,24 @@ pub struct SearchWorker<W> {
|
|||||||
impl<W: WriteColor> SearchWorker<W> {
|
impl<W: WriteColor> SearchWorker<W> {
|
||||||
/// Execute a search over the given subject.
|
/// Execute a search over the given subject.
|
||||||
pub fn search(&mut self, subject: &Subject) -> io::Result<SearchResult> {
|
pub fn search(&mut self, subject: &Subject) -> io::Result<SearchResult> {
|
||||||
self.search_impl(subject)
|
let bin = if subject.is_explicit() {
|
||||||
|
self.config.binary_explicit.clone()
|
||||||
|
} else {
|
||||||
|
self.config.binary_implicit.clone()
|
||||||
|
};
|
||||||
|
let path = subject.path();
|
||||||
|
log::trace!("{}: binary detection: {:?}", path.display(), bin);
|
||||||
|
|
||||||
|
self.searcher.set_binary_detection(bin);
|
||||||
|
if subject.is_stdin() {
|
||||||
|
self.search_reader(path, &mut io::stdin().lock())
|
||||||
|
} else if self.should_preprocess(path) {
|
||||||
|
self.search_preprocessor(path)
|
||||||
|
} else if self.should_decompress(path) {
|
||||||
|
self.search_decompress(path)
|
||||||
|
} else {
|
||||||
|
self.search_path(path)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a mutable reference to the underlying printer.
|
/// Return a mutable reference to the underlying printer.
|
||||||
@@ -341,30 +368,6 @@ impl<W: WriteColor> SearchWorker<W> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Search the given subject using the appropriate strategy.
|
|
||||||
fn search_impl(&mut self, subject: &Subject) -> io::Result<SearchResult> {
|
|
||||||
let bin =
|
|
||||||
if subject.is_explicit() {
|
|
||||||
self.config.binary_explicit.clone()
|
|
||||||
} else {
|
|
||||||
self.config.binary_implicit.clone()
|
|
||||||
};
|
|
||||||
self.searcher.set_binary_detection(bin);
|
|
||||||
|
|
||||||
let path = subject.path();
|
|
||||||
if subject.is_stdin() {
|
|
||||||
let stdin = io::stdin();
|
|
||||||
// A `return` here appeases the borrow checker. NLL will fix this.
|
|
||||||
return self.search_reader(path, stdin.lock());
|
|
||||||
} else if self.should_preprocess(path) {
|
|
||||||
self.search_preprocessor(path)
|
|
||||||
} else if self.should_decompress(path) {
|
|
||||||
self.search_decompress(path)
|
|
||||||
} else {
|
|
||||||
self.search_path(path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if and only if the given file path should be
|
/// Returns true if and only if the given file path should be
|
||||||
/// decompressed before searching.
|
/// decompressed before searching.
|
||||||
fn should_decompress(&self, path: &Path) -> bool {
|
fn should_decompress(&self, path: &Path) -> bool {
|
||||||
@@ -392,28 +395,41 @@ impl<W: WriteColor> SearchWorker<W> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
) -> io::Result<SearchResult> {
|
) -> io::Result<SearchResult> {
|
||||||
let bin = self.config.preprocessor.clone().unwrap();
|
let bin = self.config.preprocessor.as_ref().unwrap();
|
||||||
let mut cmd = Command::new(&bin);
|
let mut cmd = Command::new(bin);
|
||||||
cmd.arg(path).stdin(Stdio::from(File::open(path)?));
|
cmd.arg(path).stdin(Stdio::from(File::open(path)?));
|
||||||
|
|
||||||
let rdr = self.command_builder.build(&mut cmd)?;
|
let mut rdr = self.command_builder.build(&mut cmd).map_err(|err| {
|
||||||
self.search_reader(path, rdr).map_err(|err| {
|
io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!(
|
||||||
|
"preprocessor command could not start: '{:?}': {}",
|
||||||
|
cmd, err,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
let result = self.search_reader(path, &mut rdr).map_err(|err| {
|
||||||
io::Error::new(
|
io::Error::new(
|
||||||
io::ErrorKind::Other,
|
io::ErrorKind::Other,
|
||||||
format!("preprocessor command failed: '{:?}': {}", cmd, err),
|
format!("preprocessor command failed: '{:?}': {}", cmd, err),
|
||||||
)
|
)
|
||||||
})
|
});
|
||||||
|
let close_result = rdr.close();
|
||||||
|
let search_result = result?;
|
||||||
|
close_result?;
|
||||||
|
Ok(search_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to decompress the data at the given file path and search the
|
/// Attempt to decompress the data at the given file path and search the
|
||||||
/// result. If the given file path isn't recognized as a compressed file,
|
/// result. If the given file path isn't recognized as a compressed file,
|
||||||
/// then search it without doing any decompression.
|
/// then search it without doing any decompression.
|
||||||
fn search_decompress(
|
fn search_decompress(&mut self, path: &Path) -> io::Result<SearchResult> {
|
||||||
&mut self,
|
let mut rdr = self.decomp_builder.build(path)?;
|
||||||
path: &Path,
|
let result = self.search_reader(path, &mut rdr);
|
||||||
) -> io::Result<SearchResult> {
|
let close_result = rdr.close();
|
||||||
let rdr = self.decomp_builder.build(path)?;
|
let search_result = result?;
|
||||||
self.search_reader(path, rdr)
|
close_result?;
|
||||||
|
Ok(search_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Search the contents of the given file path.
|
/// Search the contents of the given file path.
|
||||||
@@ -440,7 +456,7 @@ impl<W: WriteColor> SearchWorker<W> {
|
|||||||
fn search_reader<R: io::Read>(
|
fn search_reader<R: io::Read>(
|
||||||
&mut self,
|
&mut self,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
rdr: R,
|
rdr: &mut R,
|
||||||
) -> io::Result<SearchResult> {
|
) -> io::Result<SearchResult> {
|
||||||
use self::PatternMatcher::*;
|
use self::PatternMatcher::*;
|
||||||
|
|
||||||
@@ -496,12 +512,12 @@ fn search_reader<M: Matcher, R: io::Read, W: WriteColor>(
|
|||||||
searcher: &mut Searcher,
|
searcher: &mut Searcher,
|
||||||
printer: &mut Printer<W>,
|
printer: &mut Printer<W>,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
rdr: R,
|
mut rdr: R,
|
||||||
) -> io::Result<SearchResult> {
|
) -> io::Result<SearchResult> {
|
||||||
match *printer {
|
match *printer {
|
||||||
Printer::Standard(ref mut p) => {
|
Printer::Standard(ref mut p) => {
|
||||||
let mut sink = p.sink_with_path(&matcher, path);
|
let mut sink = p.sink_with_path(&matcher, path);
|
||||||
searcher.search_reader(&matcher, rdr, &mut sink)?;
|
searcher.search_reader(&matcher, &mut rdr, &mut sink)?;
|
||||||
Ok(SearchResult {
|
Ok(SearchResult {
|
||||||
has_match: sink.has_match(),
|
has_match: sink.has_match(),
|
||||||
stats: sink.stats().map(|s| s.clone()),
|
stats: sink.stats().map(|s| s.clone()),
|
||||||
@@ -509,7 +525,7 @@ fn search_reader<M: Matcher, R: io::Read, W: WriteColor>(
|
|||||||
}
|
}
|
||||||
Printer::Summary(ref mut p) => {
|
Printer::Summary(ref mut p) => {
|
||||||
let mut sink = p.sink_with_path(&matcher, path);
|
let mut sink = p.sink_with_path(&matcher, path);
|
||||||
searcher.search_reader(&matcher, rdr, &mut sink)?;
|
searcher.search_reader(&matcher, &mut rdr, &mut sink)?;
|
||||||
Ok(SearchResult {
|
Ok(SearchResult {
|
||||||
has_match: sink.has_match(),
|
has_match: sink.has_match(),
|
||||||
stats: sink.stats().map(|s| s.clone()),
|
stats: sink.stats().map(|s| s.clone()),
|
||||||
@@ -517,7 +533,7 @@ fn search_reader<M: Matcher, R: io::Read, W: WriteColor>(
|
|||||||
}
|
}
|
||||||
Printer::JSON(ref mut p) => {
|
Printer::JSON(ref mut p) => {
|
||||||
let mut sink = p.sink_with_path(&matcher, path);
|
let mut sink = p.sink_with_path(&matcher, path);
|
||||||
searcher.search_reader(&matcher, rdr, &mut sink)?;
|
searcher.search_reader(&matcher, &mut rdr, &mut sink)?;
|
||||||
Ok(SearchResult {
|
Ok(SearchResult {
|
||||||
has_match: sink.has_match(),
|
has_match: sink.has_match(),
|
||||||
stats: Some(sink.stats().clone()),
|
stats: Some(sink.stats().clone()),
|
||||||
@@ -11,9 +11,7 @@ struct Config {
|
|||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
fn default() -> Config {
|
fn default() -> Config {
|
||||||
Config {
|
Config { strip_dot_prefix: false }
|
||||||
strip_dot_prefix: false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,10 +50,8 @@ impl SubjectBuilder {
|
|||||||
/// If a subject could not be created or should otherwise not be searched,
|
/// If a subject could not be created or should otherwise not be searched,
|
||||||
/// then this returns `None` after emitting any relevant log messages.
|
/// then this returns `None` after emitting any relevant log messages.
|
||||||
pub fn build(&self, dent: DirEntry) -> Option<Subject> {
|
pub fn build(&self, dent: DirEntry) -> Option<Subject> {
|
||||||
let subj = Subject {
|
let subj =
|
||||||
dent: dent,
|
Subject { dent, strip_dot_prefix: self.config.strip_dot_prefix };
|
||||||
strip_dot_prefix: self.config.strip_dot_prefix,
|
|
||||||
};
|
|
||||||
if let Some(ignore_err) = subj.dent.error() {
|
if let Some(ignore_err) = subj.dent.error() {
|
||||||
ignore_message!("{}", ignore_err);
|
ignore_message!("{}", ignore_err);
|
||||||
}
|
}
|
||||||
@@ -71,16 +67,16 @@ impl SubjectBuilder {
|
|||||||
if subj.is_file() {
|
if subj.is_file() {
|
||||||
return Some(subj);
|
return Some(subj);
|
||||||
}
|
}
|
||||||
// We got nothin. Emit a debug message, but only if this isn't a
|
// We got nothing. Emit a debug message, but only if this isn't a
|
||||||
// directory. Otherwise, emitting messages for directories is just
|
// directory. Otherwise, emitting messages for directories is just
|
||||||
// noisy.
|
// noisy.
|
||||||
if !subj.is_dir() {
|
if !subj.is_dir() {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"ignoring {}: failed to pass subject filter: \
|
"ignoring {}: failed to pass subject filter: \
|
||||||
file type: {:?}, metadata: {:?}",
|
file type: {:?}, metadata: {:?}",
|
||||||
subj.dent.path().display(),
|
subj.dent.path().display(),
|
||||||
subj.dent.file_type(),
|
subj.dent.file_type(),
|
||||||
subj.dent.metadata()
|
subj.dent.metadata()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "globset"
|
name = "globset"
|
||||||
version = "0.4.3" #:version
|
version = "0.4.10" #:version
|
||||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||||
description = """
|
description = """
|
||||||
Cross platform single glob and glob set matching. Glob set matching is the
|
Cross platform single glob and glob set matching. Glob set matching is the
|
||||||
@@ -8,11 +8,12 @@ process of matching one or more glob patterns against a single candidate path
|
|||||||
simultaneously, and returning all of the globs that matched.
|
simultaneously, and returning all of the globs that matched.
|
||||||
"""
|
"""
|
||||||
documentation = "https://docs.rs/globset"
|
documentation = "https://docs.rs/globset"
|
||||||
homepage = "https://github.com/BurntSushi/ripgrep/tree/master/globset"
|
homepage = "https://github.com/BurntSushi/ripgrep/tree/master/crates/globset"
|
||||||
repository = "https://github.com/BurntSushi/ripgrep/tree/master/globset"
|
repository = "https://github.com/BurntSushi/ripgrep/tree/master/crates/globset"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
keywords = ["regex", "glob", "multiple", "set", "pattern"]
|
keywords = ["regex", "glob", "multiple", "set", "pattern"]
|
||||||
license = "Unlicense/MIT"
|
license = "Unlicense OR MIT"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "globset"
|
name = "globset"
|
||||||
@@ -20,13 +21,18 @@ bench = false
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
aho-corasick = "0.7.3"
|
aho-corasick = "0.7.3"
|
||||||
bstr = { version = "0.1.2", default-features = false, features = ["std"] }
|
bstr = { version = "1.1.0", default-features = false, features = ["std"] }
|
||||||
fnv = "1.0.6"
|
fnv = "1.0.6"
|
||||||
log = "0.4.5"
|
log = { version = "0.4.5", optional = true }
|
||||||
regex = "1.1.5"
|
regex = { version = "1.1.5", default-features = false, features = ["perf", "std"] }
|
||||||
|
serde = { version = "1.0.104", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
glob = "0.3.0"
|
glob = "0.3.0"
|
||||||
|
lazy_static = "1"
|
||||||
|
serde_json = "1.0.45"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
default = ["log"]
|
||||||
simd-accel = []
|
simd-accel = []
|
||||||
|
serde1 = ["serde"]
|
||||||
@@ -4,11 +4,10 @@ Cross platform single glob and glob set matching. Glob set matching is the
|
|||||||
process of matching one or more glob patterns against a single candidate path
|
process of matching one or more glob patterns against a single candidate path
|
||||||
simultaneously, and returning all of the globs that matched.
|
simultaneously, and returning all of the globs that matched.
|
||||||
|
|
||||||
[](https://travis-ci.org/BurntSushi/ripgrep)
|
[](https://github.com/BurntSushi/ripgrep/actions)
|
||||||
[](https://ci.appveyor.com/project/BurntSushi/ripgrep)
|
|
||||||
[](https://crates.io/crates/globset)
|
[](https://crates.io/crates/globset)
|
||||||
|
|
||||||
Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org).
|
Dual-licensed under MIT or the [UNLICENSE](https://unlicense.org/).
|
||||||
|
|
||||||
### Documentation
|
### Documentation
|
||||||
|
|
||||||
@@ -20,14 +19,12 @@ Add this to your `Cargo.toml`:
|
|||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
globset = "0.3"
|
globset = "0.4"
|
||||||
```
|
```
|
||||||
|
|
||||||
and this to your crate root:
|
### Features
|
||||||
|
|
||||||
```rust
|
* `serde1`: Enables implementing Serde traits on the `Glob` type.
|
||||||
extern crate globset;
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example: one glob
|
### Example: one glob
|
||||||
|
|
||||||
@@ -81,12 +78,12 @@ assert_eq!(set.matches("src/bar/baz/foo.rs"), vec![0, 2]);
|
|||||||
|
|
||||||
This crate implements globs by converting them to regular expressions, and
|
This crate implements globs by converting them to regular expressions, and
|
||||||
executing them with the
|
executing them with the
|
||||||
[`regex`](https://github.com/rust-lang-nursery/regex)
|
[`regex`](https://github.com/rust-lang/regex)
|
||||||
crate.
|
crate.
|
||||||
|
|
||||||
For single glob matching, performance of this crate should be roughly on par
|
For single glob matching, performance of this crate should be roughly on par
|
||||||
with the performance of the
|
with the performance of the
|
||||||
[`glob`](https://github.com/rust-lang-nursery/glob)
|
[`glob`](https://github.com/rust-lang/glob)
|
||||||
crate. (`*_regex` correspond to benchmarks for this library while `*_glob`
|
crate. (`*_regex` correspond to benchmarks for this library while `*_glob`
|
||||||
correspond to benchmarks for the `glob` library.)
|
correspond to benchmarks for the `glob` library.)
|
||||||
Optimizations in the `regex` crate may propel this library past `glob`,
|
Optimizations in the `regex` crate may propel this library past `glob`,
|
||||||
@@ -111,7 +108,7 @@ test many_short_glob ... bench: 1,063 ns/iter (+/- 47)
|
|||||||
test many_short_regex_set ... bench: 186 ns/iter (+/- 11)
|
test many_short_regex_set ... bench: 186 ns/iter (+/- 11)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Comparison with the [`glob`](https://github.com/rust-lang-nursery/glob) crate
|
### Comparison with the [`glob`](https://github.com/rust-lang/glob) crate
|
||||||
|
|
||||||
* Supports alternate "or" globs, e.g., `*.{foo,bar}`.
|
* Supports alternate "or" globs, e.g., `*.{foo,bar}`.
|
||||||
* Can match non-UTF-8 file paths correctly.
|
* Can match non-UTF-8 file paths correctly.
|
||||||
@@ -4,16 +4,8 @@ tool itself, see the benchsuite directory.
|
|||||||
*/
|
*/
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
|
|
||||||
extern crate glob;
|
|
||||||
extern crate globset;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate lazy_static;
|
|
||||||
extern crate regex;
|
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
use std::ffi::OsStr;
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use globset::{Candidate, Glob, GlobMatcher, GlobSet, GlobSetBuilder};
|
use globset::{Candidate, Glob, GlobMatcher, GlobSet, GlobSetBuilder};
|
||||||
|
|
||||||
const EXT: &'static str = "some/a/bigger/path/to/the/crazy/needle.txt";
|
const EXT: &'static str = "some/a/bigger/path/to/the/crazy/needle.txt";
|
||||||
@@ -2,13 +2,13 @@ use std::fmt;
|
|||||||
use std::hash;
|
use std::hash;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::path::{Path, is_separator};
|
use std::path::{is_separator, Path};
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use regex;
|
use regex;
|
||||||
use regex::bytes::Regex;
|
use regex::bytes::Regex;
|
||||||
|
|
||||||
use {Candidate, Error, ErrorKind, new_regex};
|
use crate::{new_regex, Candidate, Error, ErrorKind};
|
||||||
|
|
||||||
/// Describes a matching strategy for a particular pattern.
|
/// Describes a matching strategy for a particular pattern.
|
||||||
///
|
///
|
||||||
@@ -85,24 +85,32 @@ pub struct Glob {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Glob {
|
impl PartialEq for Glob {
|
||||||
fn eq(&self, other: &Glob) -> bool {
|
fn eq(&self, other: &Glob) -> bool {
|
||||||
self.glob == other.glob && self.opts == other.opts
|
self.glob == other.glob && self.opts == other.opts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl hash::Hash for Glob {
|
impl hash::Hash for Glob {
|
||||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||||
self.glob.hash(state);
|
self.glob.hash(state);
|
||||||
self.opts.hash(state);
|
self.opts.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Glob {
|
impl fmt::Display for Glob {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
self.glob.fmt(f)
|
self.glob.fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl str::FromStr for Glob {
|
||||||
|
type Err = Error;
|
||||||
|
|
||||||
|
fn from_str(glob: &str) -> Result<Self, Self::Err> {
|
||||||
|
Self::new(glob)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A matcher for a single pattern.
|
/// A matcher for a single pattern.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct GlobMatcher {
|
pub struct GlobMatcher {
|
||||||
@@ -119,8 +127,13 @@ impl GlobMatcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Tests whether the given path matches this pattern or not.
|
/// Tests whether the given path matches this pattern or not.
|
||||||
pub fn is_match_candidate(&self, path: &Candidate) -> bool {
|
pub fn is_match_candidate(&self, path: &Candidate<'_>) -> bool {
|
||||||
self.re.is_match(path.path.as_bytes())
|
self.re.is_match(&path.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the `Glob` used to compile this matcher.
|
||||||
|
pub fn glob(&self) -> &Glob {
|
||||||
|
&self.pat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,8 +143,6 @@ impl GlobMatcher {
|
|||||||
struct GlobStrategic {
|
struct GlobStrategic {
|
||||||
/// The match strategy to use.
|
/// The match strategy to use.
|
||||||
strategy: MatchStrategy,
|
strategy: MatchStrategy,
|
||||||
/// The underlying pattern.
|
|
||||||
pat: Glob,
|
|
||||||
/// The pattern, as a compiled regex.
|
/// The pattern, as a compiled regex.
|
||||||
re: Regex,
|
re: Regex,
|
||||||
}
|
}
|
||||||
@@ -144,8 +155,8 @@ impl GlobStrategic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Tests whether the given path matches this pattern or not.
|
/// Tests whether the given path matches this pattern or not.
|
||||||
fn is_match_candidate(&self, candidate: &Candidate) -> bool {
|
fn is_match_candidate(&self, candidate: &Candidate<'_>) -> bool {
|
||||||
let byte_path = candidate.path.as_bytes();
|
let byte_path = &*candidate.path;
|
||||||
|
|
||||||
match self.strategy {
|
match self.strategy {
|
||||||
MatchStrategy::Literal(ref lit) => lit.as_bytes() == byte_path,
|
MatchStrategy::Literal(ref lit) => lit.as_bytes() == byte_path,
|
||||||
@@ -214,11 +225,15 @@ struct Tokens(Vec<Token>);
|
|||||||
|
|
||||||
impl Deref for Tokens {
|
impl Deref for Tokens {
|
||||||
type Target = Vec<Token>;
|
type Target = Vec<Token>;
|
||||||
fn deref(&self) -> &Vec<Token> { &self.0 }
|
fn deref(&self) -> &Vec<Token> {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DerefMut for Tokens {
|
impl DerefMut for Tokens {
|
||||||
fn deref_mut(&mut self) -> &mut Vec<Token> { &mut self.0 }
|
fn deref_mut(&mut self) -> &mut Vec<Token> {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
@@ -229,10 +244,7 @@ enum Token {
|
|||||||
RecursivePrefix,
|
RecursivePrefix,
|
||||||
RecursiveSuffix,
|
RecursiveSuffix,
|
||||||
RecursiveZeroOrMore,
|
RecursiveZeroOrMore,
|
||||||
Class {
|
Class { negated: bool, ranges: Vec<(char, char)> },
|
||||||
negated: bool,
|
|
||||||
ranges: Vec<(char, char)>,
|
|
||||||
},
|
|
||||||
Alternates(Vec<Tokens>),
|
Alternates(Vec<Tokens>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,12 +256,9 @@ impl Glob {
|
|||||||
|
|
||||||
/// Returns a matcher for this pattern.
|
/// Returns a matcher for this pattern.
|
||||||
pub fn compile_matcher(&self) -> GlobMatcher {
|
pub fn compile_matcher(&self) -> GlobMatcher {
|
||||||
let re = new_regex(&self.re)
|
let re =
|
||||||
.expect("regex compilation shouldn't fail");
|
new_regex(&self.re).expect("regex compilation shouldn't fail");
|
||||||
GlobMatcher {
|
GlobMatcher { pat: self.clone(), re: re }
|
||||||
pat: self.clone(),
|
|
||||||
re: re,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a strategic matcher.
|
/// Returns a strategic matcher.
|
||||||
@@ -260,13 +269,9 @@ impl Glob {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn compile_strategic_matcher(&self) -> GlobStrategic {
|
fn compile_strategic_matcher(&self) -> GlobStrategic {
|
||||||
let strategy = MatchStrategy::new(self);
|
let strategy = MatchStrategy::new(self);
|
||||||
let re = new_regex(&self.re)
|
let re =
|
||||||
.expect("regex compilation shouldn't fail");
|
new_regex(&self.re).expect("regex compilation shouldn't fail");
|
||||||
GlobStrategic {
|
GlobStrategic { strategy: strategy, re: re }
|
||||||
strategy: strategy,
|
|
||||||
pat: self.clone(),
|
|
||||||
re: re,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the original glob pattern used to build this pattern.
|
/// Returns the original glob pattern used to build this pattern.
|
||||||
@@ -360,7 +365,7 @@ impl Glob {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is like `ext`, but returns an extension even if it isn't sufficent
|
/// This is like `ext`, but returns an extension even if it isn't sufficient
|
||||||
/// to imply a match. Namely, if an extension is returned, then it is
|
/// to imply a match. Namely, if an extension is returned, then it is
|
||||||
/// necessary but not sufficient for a match.
|
/// necessary but not sufficient for a match.
|
||||||
fn required_ext(&self) -> Option<String> {
|
fn required_ext(&self) -> Option<String> {
|
||||||
@@ -396,7 +401,7 @@ impl Glob {
|
|||||||
if self.opts.case_insensitive {
|
if self.opts.case_insensitive {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let end = match self.tokens.last() {
|
let (end, need_sep) = match self.tokens.last() {
|
||||||
Some(&Token::ZeroOrMore) => {
|
Some(&Token::ZeroOrMore) => {
|
||||||
if self.opts.literal_separator {
|
if self.opts.literal_separator {
|
||||||
// If a trailing `*` can't match a `/`, then we can't
|
// If a trailing `*` can't match a `/`, then we can't
|
||||||
@@ -407,9 +412,10 @@ impl Glob {
|
|||||||
// literal prefix.
|
// literal prefix.
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
self.tokens.len() - 1
|
(self.tokens.len() - 1, false)
|
||||||
}
|
}
|
||||||
_ => self.tokens.len(),
|
Some(&Token::RecursiveSuffix) => (self.tokens.len() - 1, true),
|
||||||
|
_ => (self.tokens.len(), false),
|
||||||
};
|
};
|
||||||
let mut lit = String::new();
|
let mut lit = String::new();
|
||||||
for t in &self.tokens[0..end] {
|
for t in &self.tokens[0..end] {
|
||||||
@@ -418,6 +424,9 @@ impl Glob {
|
|||||||
_ => return None,
|
_ => return None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if need_sep {
|
||||||
|
lit.push('/');
|
||||||
|
}
|
||||||
if lit.is_empty() {
|
if lit.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
@@ -524,7 +533,7 @@ impl Glob {
|
|||||||
| Token::RecursiveZeroOrMore => {
|
| Token::RecursiveZeroOrMore => {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Token::Class{..} | Token::Alternates(..) => {
|
Token::Class { .. } | Token::Alternates(..) => {
|
||||||
// We *could* be a little smarter here, but either one
|
// We *could* be a little smarter here, but either one
|
||||||
// of these is going to prevent our literal optimizations
|
// of these is going to prevent our literal optimizations
|
||||||
// anyway, so give up.
|
// anyway, so give up.
|
||||||
@@ -561,10 +570,7 @@ impl<'a> GlobBuilder<'a> {
|
|||||||
///
|
///
|
||||||
/// The pattern is not compiled until `build` is called.
|
/// The pattern is not compiled until `build` is called.
|
||||||
pub fn new(glob: &'a str) -> GlobBuilder<'a> {
|
pub fn new(glob: &'a str) -> GlobBuilder<'a> {
|
||||||
GlobBuilder {
|
GlobBuilder { glob: glob, opts: GlobOptions::default() }
|
||||||
glob: glob,
|
|
||||||
opts: GlobOptions::default(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses and builds the pattern.
|
/// Parses and builds the pattern.
|
||||||
@@ -608,6 +614,8 @@ impl<'a> GlobBuilder<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Toggle whether a literal `/` is required to match a path separator.
|
/// Toggle whether a literal `/` is required to match a path separator.
|
||||||
|
///
|
||||||
|
/// By default this is false: `*` and `?` will match `/`.
|
||||||
pub fn literal_separator(&mut self, yes: bool) -> &mut GlobBuilder<'a> {
|
pub fn literal_separator(&mut self, yes: bool) -> &mut GlobBuilder<'a> {
|
||||||
self.opts.literal_separator = yes;
|
self.opts.literal_separator = yes;
|
||||||
self
|
self
|
||||||
@@ -679,7 +687,7 @@ impl Tokens {
|
|||||||
re.push_str("(?:/?|.*/)");
|
re.push_str("(?:/?|.*/)");
|
||||||
}
|
}
|
||||||
Token::RecursiveSuffix => {
|
Token::RecursiveSuffix => {
|
||||||
re.push_str("(?:/?|/.*)");
|
re.push_str("/.*");
|
||||||
}
|
}
|
||||||
Token::RecursiveZeroOrMore => {
|
Token::RecursiveZeroOrMore => {
|
||||||
re.push_str("(?:/|/.*/)");
|
re.push_str("(?:/|/.*/)");
|
||||||
@@ -862,25 +870,22 @@ impl<'a> Parser<'a> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let is_suffix =
|
let is_suffix = match self.peek() {
|
||||||
match self.peek() {
|
None => {
|
||||||
None => {
|
assert!(self.bump().is_none());
|
||||||
assert!(self.bump().is_none());
|
true
|
||||||
true
|
}
|
||||||
}
|
Some(',') | Some('}') if self.stack.len() >= 2 => true,
|
||||||
Some(',') | Some('}') if self.stack.len() >= 2 => {
|
Some(c) if is_separator(c) => {
|
||||||
true
|
assert!(self.bump().map(is_separator).unwrap_or(false));
|
||||||
}
|
false
|
||||||
Some(c) if is_separator(c) => {
|
}
|
||||||
assert!(self.bump().map(is_separator).unwrap_or(false));
|
_ => {
|
||||||
false
|
self.push_token(Token::ZeroOrMore)?;
|
||||||
}
|
self.push_token(Token::ZeroOrMore)?;
|
||||||
_ => {
|
return Ok(());
|
||||||
self.push_token(Token::ZeroOrMore)?;
|
}
|
||||||
self.push_token(Token::ZeroOrMore)?;
|
};
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match self.pop_token()? {
|
match self.pop_token()? {
|
||||||
Token::RecursivePrefix => {
|
Token::RecursivePrefix => {
|
||||||
self.push_token(Token::RecursivePrefix)?;
|
self.push_token(Token::RecursivePrefix)?;
|
||||||
@@ -960,7 +965,10 @@ impl<'a> Parser<'a> {
|
|||||||
// invariant: in_range is only set when there is
|
// invariant: in_range is only set when there is
|
||||||
// already at least one character seen.
|
// already at least one character seen.
|
||||||
add_to_last_range(
|
add_to_last_range(
|
||||||
&self.glob, ranges.last_mut().unwrap(), c)?;
|
&self.glob,
|
||||||
|
ranges.last_mut().unwrap(),
|
||||||
|
c,
|
||||||
|
)?;
|
||||||
} else {
|
} else {
|
||||||
ranges.push((c, c));
|
ranges.push((c, c));
|
||||||
}
|
}
|
||||||
@@ -974,10 +982,7 @@ impl<'a> Parser<'a> {
|
|||||||
// it as a literal.
|
// it as a literal.
|
||||||
ranges.push(('-', '-'));
|
ranges.push(('-', '-'));
|
||||||
}
|
}
|
||||||
self.push_token(Token::Class {
|
self.push_token(Token::Class { negated: negated, ranges: ranges })
|
||||||
negated: negated,
|
|
||||||
ranges: ranges,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bump(&mut self) -> Option<char> {
|
fn bump(&mut self) -> Option<char> {
|
||||||
@@ -1006,9 +1011,9 @@ fn ends_with(needle: &[u8], haystack: &[u8]) -> bool {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use {GlobSetBuilder, ErrorKind};
|
|
||||||
use super::{Glob, GlobBuilder, Token};
|
|
||||||
use super::Token::*;
|
use super::Token::*;
|
||||||
|
use super::{Glob, GlobBuilder, Token};
|
||||||
|
use crate::{ErrorKind, GlobSetBuilder};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
struct Options {
|
struct Options {
|
||||||
@@ -1024,7 +1029,7 @@ mod tests {
|
|||||||
let pat = Glob::new($pat).unwrap();
|
let pat = Glob::new($pat).unwrap();
|
||||||
assert_eq!($tokens, pat.tokens.0);
|
assert_eq!($tokens, pat.tokens.0);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! syntaxerr {
|
macro_rules! syntaxerr {
|
||||||
@@ -1034,7 +1039,7 @@ mod tests {
|
|||||||
let err = Glob::new($pat).unwrap_err();
|
let err = Glob::new($pat).unwrap_err();
|
||||||
assert_eq!(&$err, err.kind());
|
assert_eq!(&$err, err.kind());
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! toregex {
|
macro_rules! toregex {
|
||||||
@@ -1116,7 +1121,9 @@ mod tests {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn s(string: &str) -> String { string.to_string() }
|
fn s(string: &str) -> String {
|
||||||
|
string.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
fn class(s: char, e: char) -> Token {
|
fn class(s: char, e: char) -> Token {
|
||||||
Class { negated: false, ranges: vec![(s, e)] }
|
Class { negated: false, ranges: vec![(s, e)] }
|
||||||
@@ -1140,16 +1147,20 @@ mod tests {
|
|||||||
syntax!(any2, "a?b", vec![Literal('a'), Any, Literal('b')]);
|
syntax!(any2, "a?b", vec![Literal('a'), Any, Literal('b')]);
|
||||||
syntax!(seq1, "*", vec![ZeroOrMore]);
|
syntax!(seq1, "*", vec![ZeroOrMore]);
|
||||||
syntax!(seq2, "a*b", vec![Literal('a'), ZeroOrMore, Literal('b')]);
|
syntax!(seq2, "a*b", vec![Literal('a'), ZeroOrMore, Literal('b')]);
|
||||||
syntax!(seq3, "*a*b*", vec![
|
syntax!(
|
||||||
ZeroOrMore, Literal('a'), ZeroOrMore, Literal('b'), ZeroOrMore,
|
seq3,
|
||||||
]);
|
"*a*b*",
|
||||||
|
vec![ZeroOrMore, Literal('a'), ZeroOrMore, Literal('b'), ZeroOrMore,]
|
||||||
|
);
|
||||||
syntax!(rseq1, "**", vec![RecursivePrefix]);
|
syntax!(rseq1, "**", vec![RecursivePrefix]);
|
||||||
syntax!(rseq2, "**/", vec![RecursivePrefix]);
|
syntax!(rseq2, "**/", vec![RecursivePrefix]);
|
||||||
syntax!(rseq3, "/**", vec![RecursiveSuffix]);
|
syntax!(rseq3, "/**", vec![RecursiveSuffix]);
|
||||||
syntax!(rseq4, "/**/", vec![RecursiveZeroOrMore]);
|
syntax!(rseq4, "/**/", vec![RecursiveZeroOrMore]);
|
||||||
syntax!(rseq5, "a/**/b", vec![
|
syntax!(
|
||||||
Literal('a'), RecursiveZeroOrMore, Literal('b'),
|
rseq5,
|
||||||
]);
|
"a/**/b",
|
||||||
|
vec![Literal('a'), RecursiveZeroOrMore, Literal('b'),]
|
||||||
|
);
|
||||||
syntax!(cls1, "[a]", vec![class('a', 'a')]);
|
syntax!(cls1, "[a]", vec![class('a', 'a')]);
|
||||||
syntax!(cls2, "[!a]", vec![classn('a', 'a')]);
|
syntax!(cls2, "[!a]", vec![classn('a', 'a')]);
|
||||||
syntax!(cls3, "[a-z]", vec![class('a', 'z')]);
|
syntax!(cls3, "[a-z]", vec![class('a', 'z')]);
|
||||||
@@ -1161,9 +1172,11 @@ mod tests {
|
|||||||
syntax!(cls9, "[a-]", vec![rclass(&[('a', 'a'), ('-', '-')])]);
|
syntax!(cls9, "[a-]", vec![rclass(&[('a', 'a'), ('-', '-')])]);
|
||||||
syntax!(cls10, "[-a-z]", vec![rclass(&[('-', '-'), ('a', 'z')])]);
|
syntax!(cls10, "[-a-z]", vec![rclass(&[('-', '-'), ('a', 'z')])]);
|
||||||
syntax!(cls11, "[a-z-]", vec![rclass(&[('a', 'z'), ('-', '-')])]);
|
syntax!(cls11, "[a-z-]", vec![rclass(&[('a', 'z'), ('-', '-')])]);
|
||||||
syntax!(cls12, "[-a-z-]", vec![
|
syntax!(
|
||||||
rclass(&[('-', '-'), ('a', 'z'), ('-', '-')]),
|
cls12,
|
||||||
]);
|
"[-a-z-]",
|
||||||
|
vec![rclass(&[('-', '-'), ('a', 'z'), ('-', '-')]),]
|
||||||
|
);
|
||||||
syntax!(cls13, "[]-z]", vec![class(']', 'z')]);
|
syntax!(cls13, "[]-z]", vec![class(']', 'z')]);
|
||||||
syntax!(cls14, "[--z]", vec![class('-', 'z')]);
|
syntax!(cls14, "[--z]", vec![class('-', 'z')]);
|
||||||
syntax!(cls15, "[ --]", vec![class(' ', '-')]);
|
syntax!(cls15, "[ --]", vec![class(' ', '-')]);
|
||||||
@@ -1181,26 +1194,14 @@ mod tests {
|
|||||||
syntaxerr!(err_range1, "[z-a]", ErrorKind::InvalidRange('z', 'a'));
|
syntaxerr!(err_range1, "[z-a]", ErrorKind::InvalidRange('z', 'a'));
|
||||||
syntaxerr!(err_range2, "[z--]", ErrorKind::InvalidRange('z', '-'));
|
syntaxerr!(err_range2, "[z--]", ErrorKind::InvalidRange('z', '-'));
|
||||||
|
|
||||||
const CASEI: Options = Options {
|
const CASEI: Options =
|
||||||
casei: Some(true),
|
Options { casei: Some(true), litsep: None, bsesc: None };
|
||||||
litsep: None,
|
const SLASHLIT: Options =
|
||||||
bsesc: None,
|
Options { casei: None, litsep: Some(true), bsesc: None };
|
||||||
};
|
const NOBSESC: Options =
|
||||||
const SLASHLIT: Options = Options {
|
Options { casei: None, litsep: None, bsesc: Some(false) };
|
||||||
casei: None,
|
const BSESC: Options =
|
||||||
litsep: Some(true),
|
Options { casei: None, litsep: None, bsesc: Some(true) };
|
||||||
bsesc: None,
|
|
||||||
};
|
|
||||||
const NOBSESC: Options = Options {
|
|
||||||
casei: None,
|
|
||||||
litsep: None,
|
|
||||||
bsesc: Some(false),
|
|
||||||
};
|
|
||||||
const BSESC: Options = Options {
|
|
||||||
casei: None,
|
|
||||||
litsep: None,
|
|
||||||
bsesc: Some(true),
|
|
||||||
};
|
|
||||||
|
|
||||||
toregex!(re_casei, "a", "(?i)^a$", &CASEI);
|
toregex!(re_casei, "a", "(?i)^a$", &CASEI);
|
||||||
|
|
||||||
@@ -1225,9 +1226,9 @@ mod tests {
|
|||||||
toregex!(re16, "**/**/*", r"^(?:/?|.*/).*$");
|
toregex!(re16, "**/**/*", r"^(?:/?|.*/).*$");
|
||||||
toregex!(re17, "**/**/**", r"^.*$");
|
toregex!(re17, "**/**/**", r"^.*$");
|
||||||
toregex!(re18, "**/**/**/*", r"^(?:/?|.*/).*$");
|
toregex!(re18, "**/**/**/*", r"^(?:/?|.*/).*$");
|
||||||
toregex!(re19, "a/**", r"^a(?:/?|/.*)$");
|
toregex!(re19, "a/**", r"^a/.*$");
|
||||||
toregex!(re20, "a/**/**", r"^a(?:/?|/.*)$");
|
toregex!(re20, "a/**/**", r"^a/.*$");
|
||||||
toregex!(re21, "a/**/**/**", r"^a(?:/?|/.*)$");
|
toregex!(re21, "a/**/**/**", r"^a/.*$");
|
||||||
toregex!(re22, "a/**/b", r"^a(?:/|/.*/)b$");
|
toregex!(re22, "a/**/b", r"^a(?:/|/.*/)b$");
|
||||||
toregex!(re23, "a/**/**/b", r"^a(?:/|/.*/)b$");
|
toregex!(re23, "a/**/**/b", r"^a(?:/|/.*/)b$");
|
||||||
toregex!(re24, "a/**/**/**/b", r"^a(?:/|/.*/)b$");
|
toregex!(re24, "a/**/**/**/b", r"^a(?:/|/.*/)b$");
|
||||||
@@ -1273,11 +1274,12 @@ mod tests {
|
|||||||
matches!(matchrec18, "/**/test", "/test");
|
matches!(matchrec18, "/**/test", "/test");
|
||||||
matches!(matchrec19, "**/.*", ".abc");
|
matches!(matchrec19, "**/.*", ".abc");
|
||||||
matches!(matchrec20, "**/.*", "abc/.abc");
|
matches!(matchrec20, "**/.*", "abc/.abc");
|
||||||
matches!(matchrec21, ".*/**", ".abc");
|
matches!(matchrec21, "**/foo/bar", "foo/bar");
|
||||||
matches!(matchrec22, ".*/**", ".abc/abc");
|
matches!(matchrec22, ".*/**", ".abc/abc");
|
||||||
matches!(matchrec23, "foo/**", "foo");
|
matches!(matchrec23, "test/**", "test/");
|
||||||
matches!(matchrec24, "**/foo/bar", "foo/bar");
|
matches!(matchrec24, "test/**", "test/one");
|
||||||
matches!(matchrec25, "some/*/needle.txt", "some/one/needle.txt");
|
matches!(matchrec25, "test/**", "test/one/two");
|
||||||
|
matches!(matchrec26, "some/*/needle.txt", "some/one/needle.txt");
|
||||||
|
|
||||||
matches!(matchrange1, "a[0-9]b", "a0b");
|
matches!(matchrange1, "a[0-9]b", "a0b");
|
||||||
matches!(matchrange2, "a[0-9]b", "a9b");
|
matches!(matchrange2, "a[0-9]b", "a9b");
|
||||||
@@ -1298,8 +1300,11 @@ mod tests {
|
|||||||
matches!(matchpat4, "*hello.txt", "some\\path\\to\\hello.txt");
|
matches!(matchpat4, "*hello.txt", "some\\path\\to\\hello.txt");
|
||||||
matches!(matchpat5, "*hello.txt", "/an/absolute/path/to/hello.txt");
|
matches!(matchpat5, "*hello.txt", "/an/absolute/path/to/hello.txt");
|
||||||
matches!(matchpat6, "*some/path/to/hello.txt", "some/path/to/hello.txt");
|
matches!(matchpat6, "*some/path/to/hello.txt", "some/path/to/hello.txt");
|
||||||
matches!(matchpat7, "*some/path/to/hello.txt",
|
matches!(
|
||||||
"a/bigger/some/path/to/hello.txt");
|
matchpat7,
|
||||||
|
"*some/path/to/hello.txt",
|
||||||
|
"a/bigger/some/path/to/hello.txt"
|
||||||
|
);
|
||||||
|
|
||||||
matches!(matchescape, "_[[]_[]]_[?]_[*]_!_", "_[_]_?_*_!_");
|
matches!(matchescape, "_[[]_[]]_[?]_[*]_!_", "_[_]_?_*_!_");
|
||||||
|
|
||||||
@@ -1362,28 +1367,46 @@ mod tests {
|
|||||||
nmatches!(matchnot15, "[!-]", "-");
|
nmatches!(matchnot15, "[!-]", "-");
|
||||||
nmatches!(matchnot16, "*hello.txt", "hello.txt-and-then-some");
|
nmatches!(matchnot16, "*hello.txt", "hello.txt-and-then-some");
|
||||||
nmatches!(matchnot17, "*hello.txt", "goodbye.txt");
|
nmatches!(matchnot17, "*hello.txt", "goodbye.txt");
|
||||||
nmatches!(matchnot18, "*some/path/to/hello.txt",
|
nmatches!(
|
||||||
"some/path/to/hello.txt-and-then-some");
|
matchnot18,
|
||||||
nmatches!(matchnot19, "*some/path/to/hello.txt",
|
"*some/path/to/hello.txt",
|
||||||
"some/other/path/to/hello.txt");
|
"some/path/to/hello.txt-and-then-some"
|
||||||
|
);
|
||||||
|
nmatches!(
|
||||||
|
matchnot19,
|
||||||
|
"*some/path/to/hello.txt",
|
||||||
|
"some/other/path/to/hello.txt"
|
||||||
|
);
|
||||||
nmatches!(matchnot20, "a", "foo/a");
|
nmatches!(matchnot20, "a", "foo/a");
|
||||||
nmatches!(matchnot21, "./foo", "foo");
|
nmatches!(matchnot21, "./foo", "foo");
|
||||||
nmatches!(matchnot22, "**/foo", "foofoo");
|
nmatches!(matchnot22, "**/foo", "foofoo");
|
||||||
nmatches!(matchnot23, "**/foo/bar", "foofoo/bar");
|
nmatches!(matchnot23, "**/foo/bar", "foofoo/bar");
|
||||||
nmatches!(matchnot24, "/*.c", "mozilla-sha1/sha1.c");
|
nmatches!(matchnot24, "/*.c", "mozilla-sha1/sha1.c");
|
||||||
nmatches!(matchnot25, "*.c", "mozilla-sha1/sha1.c", SLASHLIT);
|
nmatches!(matchnot25, "*.c", "mozilla-sha1/sha1.c", SLASHLIT);
|
||||||
nmatches!(matchnot26, "**/m4/ltoptions.m4",
|
nmatches!(
|
||||||
"csharp/src/packages/repositories.config", SLASHLIT);
|
matchnot26,
|
||||||
|
"**/m4/ltoptions.m4",
|
||||||
|
"csharp/src/packages/repositories.config",
|
||||||
|
SLASHLIT
|
||||||
|
);
|
||||||
nmatches!(matchnot27, "a[^0-9]b", "a0b");
|
nmatches!(matchnot27, "a[^0-9]b", "a0b");
|
||||||
nmatches!(matchnot28, "a[^0-9]b", "a9b");
|
nmatches!(matchnot28, "a[^0-9]b", "a9b");
|
||||||
nmatches!(matchnot29, "[^-]", "-");
|
nmatches!(matchnot29, "[^-]", "-");
|
||||||
nmatches!(matchnot30, "some/*/needle.txt", "some/needle.txt");
|
nmatches!(matchnot30, "some/*/needle.txt", "some/needle.txt");
|
||||||
nmatches!(
|
nmatches!(
|
||||||
matchrec31,
|
matchrec31,
|
||||||
"some/*/needle.txt", "some/one/two/needle.txt", SLASHLIT);
|
"some/*/needle.txt",
|
||||||
|
"some/one/two/needle.txt",
|
||||||
|
SLASHLIT
|
||||||
|
);
|
||||||
nmatches!(
|
nmatches!(
|
||||||
matchrec32,
|
matchrec32,
|
||||||
"some/*/needle.txt", "some/one/two/three/needle.txt", SLASHLIT);
|
"some/*/needle.txt",
|
||||||
|
"some/one/two/three/needle.txt",
|
||||||
|
SLASHLIT
|
||||||
|
);
|
||||||
|
nmatches!(matchrec33, ".*/**", ".abc");
|
||||||
|
nmatches!(matchrec34, "foo/**", "foo");
|
||||||
|
|
||||||
macro_rules! extract {
|
macro_rules! extract {
|
||||||
($which:ident, $name:ident, $pat:expr, $expect:expr) => {
|
($which:ident, $name:ident, $pat:expr, $expect:expr) => {
|
||||||
@@ -1445,19 +1468,27 @@ mod tests {
|
|||||||
literal!(extract_lit7, "foo/bar", Some(s("foo/bar")));
|
literal!(extract_lit7, "foo/bar", Some(s("foo/bar")));
|
||||||
literal!(extract_lit8, "**/foo/bar", None);
|
literal!(extract_lit8, "**/foo/bar", None);
|
||||||
|
|
||||||
basetokens!(extract_basetoks1, "**/foo", Some(&*vec![
|
basetokens!(
|
||||||
Literal('f'), Literal('o'), Literal('o'),
|
extract_basetoks1,
|
||||||
]));
|
"**/foo",
|
||||||
|
Some(&*vec![Literal('f'), Literal('o'), Literal('o'),])
|
||||||
|
);
|
||||||
basetokens!(extract_basetoks2, "**/foo", None, CASEI);
|
basetokens!(extract_basetoks2, "**/foo", None, CASEI);
|
||||||
basetokens!(extract_basetoks3, "**/foo", Some(&*vec![
|
basetokens!(
|
||||||
Literal('f'), Literal('o'), Literal('o'),
|
extract_basetoks3,
|
||||||
]), SLASHLIT);
|
"**/foo",
|
||||||
|
Some(&*vec![Literal('f'), Literal('o'), Literal('o'),]),
|
||||||
|
SLASHLIT
|
||||||
|
);
|
||||||
basetokens!(extract_basetoks4, "*foo", None, SLASHLIT);
|
basetokens!(extract_basetoks4, "*foo", None, SLASHLIT);
|
||||||
basetokens!(extract_basetoks5, "*foo", None);
|
basetokens!(extract_basetoks5, "*foo", None);
|
||||||
basetokens!(extract_basetoks6, "**/fo*o", None);
|
basetokens!(extract_basetoks6, "**/fo*o", None);
|
||||||
basetokens!(extract_basetoks7, "**/fo*o", Some(&*vec![
|
basetokens!(
|
||||||
Literal('f'), Literal('o'), ZeroOrMore, Literal('o'),
|
extract_basetoks7,
|
||||||
]), SLASHLIT);
|
"**/fo*o",
|
||||||
|
Some(&*vec![Literal('f'), Literal('o'), ZeroOrMore, Literal('o'),]),
|
||||||
|
SLASHLIT
|
||||||
|
);
|
||||||
|
|
||||||
ext!(extract_ext1, "**/*.rs", Some(s(".rs")));
|
ext!(extract_ext1, "**/*.rs", Some(s(".rs")));
|
||||||
ext!(extract_ext2, "**/*.rs.bak", None);
|
ext!(extract_ext2, "**/*.rs.bak", None);
|
||||||
@@ -1480,7 +1511,7 @@ mod tests {
|
|||||||
prefix!(extract_prefix1, "/foo", Some(s("/foo")));
|
prefix!(extract_prefix1, "/foo", Some(s("/foo")));
|
||||||
prefix!(extract_prefix2, "/foo/*", Some(s("/foo/")));
|
prefix!(extract_prefix2, "/foo/*", Some(s("/foo/")));
|
||||||
prefix!(extract_prefix3, "**/foo", None);
|
prefix!(extract_prefix3, "**/foo", None);
|
||||||
prefix!(extract_prefix4, "foo/**", None);
|
prefix!(extract_prefix4, "foo/**", Some(s("foo/")));
|
||||||
|
|
||||||
suffix!(extract_suffix1, "**/foo/bar", Some((s("/foo/bar"), true)));
|
suffix!(extract_suffix1, "**/foo/bar", Some((s("/foo/bar"), true)));
|
||||||
suffix!(extract_suffix2, "*/foo/bar", Some((s("/foo/bar"), false)));
|
suffix!(extract_suffix2, "*/foo/bar", Some((s("/foo/bar"), false)));
|
||||||
@@ -103,13 +103,6 @@ or to enable case insensitive matching.
|
|||||||
|
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
extern crate aho_corasick;
|
|
||||||
extern crate bstr;
|
|
||||||
extern crate fnv;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate log;
|
|
||||||
extern crate regex;
|
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
use std::error::Error as StdError;
|
use std::error::Error as StdError;
|
||||||
@@ -119,16 +112,29 @@ use std::path::Path;
|
|||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use aho_corasick::AhoCorasick;
|
use aho_corasick::AhoCorasick;
|
||||||
use bstr::{B, BStr, BString};
|
use bstr::{ByteSlice, ByteVec, B};
|
||||||
use regex::bytes::{Regex, RegexBuilder, RegexSet};
|
use regex::bytes::{Regex, RegexBuilder, RegexSet};
|
||||||
|
|
||||||
use pathutil::{file_name, file_name_ext, normalize_path};
|
use crate::glob::MatchStrategy;
|
||||||
use glob::MatchStrategy;
|
pub use crate::glob::{Glob, GlobBuilder, GlobMatcher};
|
||||||
pub use glob::{Glob, GlobBuilder, GlobMatcher};
|
use crate::pathutil::{file_name, file_name_ext, normalize_path};
|
||||||
|
|
||||||
mod glob;
|
mod glob;
|
||||||
mod pathutil;
|
mod pathutil;
|
||||||
|
|
||||||
|
#[cfg(feature = "serde1")]
|
||||||
|
mod serde_impl;
|
||||||
|
|
||||||
|
#[cfg(feature = "log")]
|
||||||
|
macro_rules! debug {
|
||||||
|
($($token:tt)*) => (::log::debug!($($token)*);)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "log"))]
|
||||||
|
macro_rules! debug {
|
||||||
|
($($token:tt)*) => {};
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents an error that can occur when parsing a glob pattern.
|
/// Represents an error that can occur when parsing a glob pattern.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
@@ -202,9 +208,7 @@ impl ErrorKind {
|
|||||||
ErrorKind::UnclosedClass => {
|
ErrorKind::UnclosedClass => {
|
||||||
"unclosed character class; missing ']'"
|
"unclosed character class; missing ']'"
|
||||||
}
|
}
|
||||||
ErrorKind::InvalidRange(_, _) => {
|
ErrorKind::InvalidRange(_, _) => "invalid character range",
|
||||||
"invalid character range"
|
|
||||||
}
|
|
||||||
ErrorKind::UnopenedAlternates => {
|
ErrorKind::UnopenedAlternates => {
|
||||||
"unopened alternate group; missing '{' \
|
"unopened alternate group; missing '{' \
|
||||||
(maybe escape '}' with '[}]'?)"
|
(maybe escape '}' with '[}]'?)"
|
||||||
@@ -216,9 +220,7 @@ impl ErrorKind {
|
|||||||
ErrorKind::NestedAlternates => {
|
ErrorKind::NestedAlternates => {
|
||||||
"nested alternate groups are not allowed"
|
"nested alternate groups are not allowed"
|
||||||
}
|
}
|
||||||
ErrorKind::DanglingEscape => {
|
ErrorKind::DanglingEscape => "dangling '\\'",
|
||||||
"dangling '\\'"
|
|
||||||
}
|
|
||||||
ErrorKind::Regex(ref err) => err,
|
ErrorKind::Regex(ref err) => err,
|
||||||
ErrorKind::__Nonexhaustive => unreachable!(),
|
ErrorKind::__Nonexhaustive => unreachable!(),
|
||||||
}
|
}
|
||||||
@@ -226,7 +228,7 @@ impl ErrorKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self.glob {
|
match self.glob {
|
||||||
None => self.kind.fmt(f),
|
None => self.kind.fmt(f),
|
||||||
Some(ref glob) => {
|
Some(ref glob) => {
|
||||||
@@ -237,7 +239,7 @@ impl fmt::Display for Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ErrorKind {
|
impl fmt::Display for ErrorKind {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
ErrorKind::InvalidRecursive
|
ErrorKind::InvalidRecursive
|
||||||
| ErrorKind::UnclosedClass
|
| ErrorKind::UnclosedClass
|
||||||
@@ -245,9 +247,7 @@ impl fmt::Display for ErrorKind {
|
|||||||
| ErrorKind::UnclosedAlternates
|
| ErrorKind::UnclosedAlternates
|
||||||
| ErrorKind::NestedAlternates
|
| ErrorKind::NestedAlternates
|
||||||
| ErrorKind::DanglingEscape
|
| ErrorKind::DanglingEscape
|
||||||
| ErrorKind::Regex(_) => {
|
| ErrorKind::Regex(_) => write!(f, "{}", self.description()),
|
||||||
write!(f, "{}", self.description())
|
|
||||||
}
|
|
||||||
ErrorKind::InvalidRange(s, e) => {
|
ErrorKind::InvalidRange(s, e) => {
|
||||||
write!(f, "invalid range; '{}' > '{}'", s, e)
|
write!(f, "invalid range; '{}' > '{}'", s, e)
|
||||||
}
|
}
|
||||||
@@ -262,21 +262,20 @@ fn new_regex(pat: &str) -> Result<Regex, Error> {
|
|||||||
.size_limit(10 * (1 << 20))
|
.size_limit(10 * (1 << 20))
|
||||||
.dfa_size_limit(10 * (1 << 20))
|
.dfa_size_limit(10 * (1 << 20))
|
||||||
.build()
|
.build()
|
||||||
.map_err(|err| {
|
.map_err(|err| Error {
|
||||||
Error {
|
glob: Some(pat.to_string()),
|
||||||
glob: Some(pat.to_string()),
|
kind: ErrorKind::Regex(err.to_string()),
|
||||||
kind: ErrorKind::Regex(err.to_string()),
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_regex_set<I, S>(pats: I) -> Result<RegexSet, Error>
|
fn new_regex_set<I, S>(pats: I) -> Result<RegexSet, Error>
|
||||||
where S: AsRef<str>, I: IntoIterator<Item=S> {
|
where
|
||||||
RegexSet::new(pats).map_err(|err| {
|
S: AsRef<str>,
|
||||||
Error {
|
I: IntoIterator<Item = S>,
|
||||||
glob: None,
|
{
|
||||||
kind: ErrorKind::Regex(err.to_string()),
|
RegexSet::new(pats).map_err(|err| Error {
|
||||||
}
|
glob: None,
|
||||||
|
kind: ErrorKind::Regex(err.to_string()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,10 +293,7 @@ impl GlobSet {
|
|||||||
/// Create an empty `GlobSet`. An empty set matches nothing.
|
/// Create an empty `GlobSet`. An empty set matches nothing.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn empty() -> GlobSet {
|
pub fn empty() -> GlobSet {
|
||||||
GlobSet {
|
GlobSet { len: 0, strats: vec![] }
|
||||||
len: 0,
|
|
||||||
strats: vec![],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this set is empty, and therefore matches nothing.
|
/// Returns true if this set is empty, and therefore matches nothing.
|
||||||
@@ -321,7 +317,7 @@ impl GlobSet {
|
|||||||
///
|
///
|
||||||
/// This takes a Candidate as input, which can be used to amortize the
|
/// This takes a Candidate as input, which can be used to amortize the
|
||||||
/// cost of preparing a path for matching.
|
/// cost of preparing a path for matching.
|
||||||
pub fn is_match_candidate(&self, path: &Candidate) -> bool {
|
pub fn is_match_candidate(&self, path: &Candidate<'_>) -> bool {
|
||||||
if self.is_empty() {
|
if self.is_empty() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -344,7 +340,7 @@ impl GlobSet {
|
|||||||
///
|
///
|
||||||
/// This takes a Candidate as input, which can be used to amortize the
|
/// This takes a Candidate as input, which can be used to amortize the
|
||||||
/// cost of preparing a path for matching.
|
/// cost of preparing a path for matching.
|
||||||
pub fn matches_candidate(&self, path: &Candidate) -> Vec<usize> {
|
pub fn matches_candidate(&self, path: &Candidate<'_>) -> Vec<usize> {
|
||||||
let mut into = vec![];
|
let mut into = vec![];
|
||||||
if self.is_empty() {
|
if self.is_empty() {
|
||||||
return into;
|
return into;
|
||||||
@@ -356,7 +352,7 @@ impl GlobSet {
|
|||||||
/// Adds the sequence number of every glob pattern that matches the given
|
/// Adds the sequence number of every glob pattern that matches the given
|
||||||
/// path to the vec given.
|
/// path to the vec given.
|
||||||
///
|
///
|
||||||
/// `into` is is cleared before matching begins, and contains the set of
|
/// `into` is cleared before matching begins, and contains the set of
|
||||||
/// sequence numbers (in ascending order) after matching ends. If no globs
|
/// sequence numbers (in ascending order) after matching ends. If no globs
|
||||||
/// were matched, then `into` will be empty.
|
/// were matched, then `into` will be empty.
|
||||||
pub fn matches_into<P: AsRef<Path>>(
|
pub fn matches_into<P: AsRef<Path>>(
|
||||||
@@ -370,7 +366,7 @@ impl GlobSet {
|
|||||||
/// Adds the sequence number of every glob pattern that matches the given
|
/// Adds the sequence number of every glob pattern that matches the given
|
||||||
/// path to the vec given.
|
/// path to the vec given.
|
||||||
///
|
///
|
||||||
/// `into` is is cleared before matching begins, and contains the set of
|
/// `into` is cleared before matching begins, and contains the set of
|
||||||
/// sequence numbers (in ascending order) after matching ends. If no globs
|
/// sequence numbers (in ascending order) after matching ends. If no globs
|
||||||
/// were matched, then `into` will be empty.
|
/// were matched, then `into` will be empty.
|
||||||
///
|
///
|
||||||
@@ -378,7 +374,7 @@ impl GlobSet {
|
|||||||
/// cost of preparing a path for matching.
|
/// cost of preparing a path for matching.
|
||||||
pub fn matches_candidate_into(
|
pub fn matches_candidate_into(
|
||||||
&self,
|
&self,
|
||||||
path: &Candidate,
|
path: &Candidate<'_>,
|
||||||
into: &mut Vec<usize>,
|
into: &mut Vec<usize>,
|
||||||
) {
|
) {
|
||||||
into.clear();
|
into.clear();
|
||||||
@@ -432,11 +428,17 @@ impl GlobSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debug!("built glob set; {} literals, {} basenames, {} extensions, \
|
debug!(
|
||||||
|
"built glob set; {} literals, {} basenames, {} extensions, \
|
||||||
{} prefixes, {} suffixes, {} required extensions, {} regexes",
|
{} prefixes, {} suffixes, {} required extensions, {} regexes",
|
||||||
lits.0.len(), base_lits.0.len(), exts.0.len(),
|
lits.0.len(),
|
||||||
prefixes.literals.len(), suffixes.literals.len(),
|
base_lits.0.len(),
|
||||||
required_exts.0.len(), regexes.literals.len());
|
exts.0.len(),
|
||||||
|
prefixes.literals.len(),
|
||||||
|
suffixes.literals.len(),
|
||||||
|
required_exts.0.len(),
|
||||||
|
regexes.literals.len()
|
||||||
|
);
|
||||||
Ok(GlobSet {
|
Ok(GlobSet {
|
||||||
len: pats.len(),
|
len: pats.len(),
|
||||||
strats: vec![
|
strats: vec![
|
||||||
@@ -446,13 +448,21 @@ impl GlobSet {
|
|||||||
GlobSetMatchStrategy::Suffix(suffixes.suffix()),
|
GlobSetMatchStrategy::Suffix(suffixes.suffix()),
|
||||||
GlobSetMatchStrategy::Prefix(prefixes.prefix()),
|
GlobSetMatchStrategy::Prefix(prefixes.prefix()),
|
||||||
GlobSetMatchStrategy::RequiredExtension(
|
GlobSetMatchStrategy::RequiredExtension(
|
||||||
required_exts.build()?),
|
required_exts.build()?,
|
||||||
|
),
|
||||||
GlobSetMatchStrategy::Regex(regexes.regex_set()?),
|
GlobSetMatchStrategy::Regex(regexes.regex_set()?),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for GlobSet {
|
||||||
|
/// Create a default empty GlobSet.
|
||||||
|
fn default() -> Self {
|
||||||
|
GlobSet::empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// GlobSetBuilder builds a group of patterns that can be used to
|
/// GlobSetBuilder builds a group of patterns that can be used to
|
||||||
/// simultaneously match a file path.
|
/// simultaneously match a file path.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@@ -490,25 +500,21 @@ impl GlobSetBuilder {
|
|||||||
/// path against multiple globs or sets of globs.
|
/// path against multiple globs or sets of globs.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Candidate<'a> {
|
pub struct Candidate<'a> {
|
||||||
path: Cow<'a, BStr>,
|
path: Cow<'a, [u8]>,
|
||||||
basename: Cow<'a, BStr>,
|
basename: Cow<'a, [u8]>,
|
||||||
ext: Cow<'a, BStr>,
|
ext: Cow<'a, [u8]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Candidate<'a> {
|
impl<'a> Candidate<'a> {
|
||||||
/// Create a new candidate for matching from the given path.
|
/// Create a new candidate for matching from the given path.
|
||||||
pub fn new<P: AsRef<Path> + ?Sized>(path: &'a P) -> Candidate<'a> {
|
pub fn new<P: AsRef<Path> + ?Sized>(path: &'a P) -> Candidate<'a> {
|
||||||
let path = normalize_path(BString::from_path_lossy(path.as_ref()));
|
let path = normalize_path(Vec::from_path_lossy(path.as_ref()));
|
||||||
let basename = file_name(&path).unwrap_or(Cow::Borrowed(B("")));
|
let basename = file_name(&path).unwrap_or(Cow::Borrowed(B("")));
|
||||||
let ext = file_name_ext(&basename).unwrap_or(Cow::Borrowed(B("")));
|
let ext = file_name_ext(&basename).unwrap_or(Cow::Borrowed(B("")));
|
||||||
Candidate {
|
Candidate { path: path, basename: basename, ext: ext }
|
||||||
path: path,
|
|
||||||
basename: basename,
|
|
||||||
ext: ext,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn path_prefix(&self, max: usize) -> &BStr {
|
fn path_prefix(&self, max: usize) -> &[u8] {
|
||||||
if self.path.len() <= max {
|
if self.path.len() <= max {
|
||||||
&*self.path
|
&*self.path
|
||||||
} else {
|
} else {
|
||||||
@@ -516,7 +522,7 @@ impl<'a> Candidate<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn path_suffix(&self, max: usize) -> &BStr {
|
fn path_suffix(&self, max: usize) -> &[u8] {
|
||||||
if self.path.len() <= max {
|
if self.path.len() <= max {
|
||||||
&*self.path
|
&*self.path
|
||||||
} else {
|
} else {
|
||||||
@@ -537,7 +543,7 @@ enum GlobSetMatchStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl GlobSetMatchStrategy {
|
impl GlobSetMatchStrategy {
|
||||||
fn is_match(&self, candidate: &Candidate) -> bool {
|
fn is_match(&self, candidate: &Candidate<'_>) -> bool {
|
||||||
use self::GlobSetMatchStrategy::*;
|
use self::GlobSetMatchStrategy::*;
|
||||||
match *self {
|
match *self {
|
||||||
Literal(ref s) => s.is_match(candidate),
|
Literal(ref s) => s.is_match(candidate),
|
||||||
@@ -550,7 +556,11 @@ impl GlobSetMatchStrategy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn matches_into(&self, candidate: &Candidate, matches: &mut Vec<usize>) {
|
fn matches_into(
|
||||||
|
&self,
|
||||||
|
candidate: &Candidate<'_>,
|
||||||
|
matches: &mut Vec<usize>,
|
||||||
|
) {
|
||||||
use self::GlobSetMatchStrategy::*;
|
use self::GlobSetMatchStrategy::*;
|
||||||
match *self {
|
match *self {
|
||||||
Literal(ref s) => s.matches_into(candidate, matches),
|
Literal(ref s) => s.matches_into(candidate, matches),
|
||||||
@@ -576,12 +586,16 @@ impl LiteralStrategy {
|
|||||||
self.0.entry(lit.into_bytes()).or_insert(vec![]).push(global_index);
|
self.0.entry(lit.into_bytes()).or_insert(vec![]).push(global_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_match(&self, candidate: &Candidate) -> bool {
|
fn is_match(&self, candidate: &Candidate<'_>) -> bool {
|
||||||
self.0.contains_key(candidate.path.as_bytes())
|
self.0.contains_key(candidate.path.as_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn matches_into(&self, candidate: &Candidate, matches: &mut Vec<usize>) {
|
fn matches_into(
|
||||||
|
&self,
|
||||||
|
candidate: &Candidate<'_>,
|
||||||
|
matches: &mut Vec<usize>,
|
||||||
|
) {
|
||||||
if let Some(hits) = self.0.get(candidate.path.as_bytes()) {
|
if let Some(hits) = self.0.get(candidate.path.as_bytes()) {
|
||||||
matches.extend(hits);
|
matches.extend(hits);
|
||||||
}
|
}
|
||||||
@@ -600,7 +614,7 @@ impl BasenameLiteralStrategy {
|
|||||||
self.0.entry(lit.into_bytes()).or_insert(vec![]).push(global_index);
|
self.0.entry(lit.into_bytes()).or_insert(vec![]).push(global_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_match(&self, candidate: &Candidate) -> bool {
|
fn is_match(&self, candidate: &Candidate<'_>) -> bool {
|
||||||
if candidate.basename.is_empty() {
|
if candidate.basename.is_empty() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -608,7 +622,11 @@ impl BasenameLiteralStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn matches_into(&self, candidate: &Candidate, matches: &mut Vec<usize>) {
|
fn matches_into(
|
||||||
|
&self,
|
||||||
|
candidate: &Candidate<'_>,
|
||||||
|
matches: &mut Vec<usize>,
|
||||||
|
) {
|
||||||
if candidate.basename.is_empty() {
|
if candidate.basename.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -630,7 +648,7 @@ impl ExtensionStrategy {
|
|||||||
self.0.entry(ext.into_bytes()).or_insert(vec![]).push(global_index);
|
self.0.entry(ext.into_bytes()).or_insert(vec![]).push(global_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_match(&self, candidate: &Candidate) -> bool {
|
fn is_match(&self, candidate: &Candidate<'_>) -> bool {
|
||||||
if candidate.ext.is_empty() {
|
if candidate.ext.is_empty() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -638,7 +656,11 @@ impl ExtensionStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn matches_into(&self, candidate: &Candidate, matches: &mut Vec<usize>) {
|
fn matches_into(
|
||||||
|
&self,
|
||||||
|
candidate: &Candidate<'_>,
|
||||||
|
matches: &mut Vec<usize>,
|
||||||
|
) {
|
||||||
if candidate.ext.is_empty() {
|
if candidate.ext.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -656,7 +678,7 @@ struct PrefixStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PrefixStrategy {
|
impl PrefixStrategy {
|
||||||
fn is_match(&self, candidate: &Candidate) -> bool {
|
fn is_match(&self, candidate: &Candidate<'_>) -> bool {
|
||||||
let path = candidate.path_prefix(self.longest);
|
let path = candidate.path_prefix(self.longest);
|
||||||
for m in self.matcher.find_overlapping_iter(path) {
|
for m in self.matcher.find_overlapping_iter(path) {
|
||||||
if m.start() == 0 {
|
if m.start() == 0 {
|
||||||
@@ -666,7 +688,11 @@ impl PrefixStrategy {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn matches_into(&self, candidate: &Candidate, matches: &mut Vec<usize>) {
|
fn matches_into(
|
||||||
|
&self,
|
||||||
|
candidate: &Candidate<'_>,
|
||||||
|
matches: &mut Vec<usize>,
|
||||||
|
) {
|
||||||
let path = candidate.path_prefix(self.longest);
|
let path = candidate.path_prefix(self.longest);
|
||||||
for m in self.matcher.find_overlapping_iter(path) {
|
for m in self.matcher.find_overlapping_iter(path) {
|
||||||
if m.start() == 0 {
|
if m.start() == 0 {
|
||||||
@@ -684,7 +710,7 @@ struct SuffixStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SuffixStrategy {
|
impl SuffixStrategy {
|
||||||
fn is_match(&self, candidate: &Candidate) -> bool {
|
fn is_match(&self, candidate: &Candidate<'_>) -> bool {
|
||||||
let path = candidate.path_suffix(self.longest);
|
let path = candidate.path_suffix(self.longest);
|
||||||
for m in self.matcher.find_overlapping_iter(path) {
|
for m in self.matcher.find_overlapping_iter(path) {
|
||||||
if m.end() == path.len() {
|
if m.end() == path.len() {
|
||||||
@@ -694,7 +720,11 @@ impl SuffixStrategy {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn matches_into(&self, candidate: &Candidate, matches: &mut Vec<usize>) {
|
fn matches_into(
|
||||||
|
&self,
|
||||||
|
candidate: &Candidate<'_>,
|
||||||
|
matches: &mut Vec<usize>,
|
||||||
|
) {
|
||||||
let path = candidate.path_suffix(self.longest);
|
let path = candidate.path_suffix(self.longest);
|
||||||
for m in self.matcher.find_overlapping_iter(path) {
|
for m in self.matcher.find_overlapping_iter(path) {
|
||||||
if m.end() == path.len() {
|
if m.end() == path.len() {
|
||||||
@@ -708,7 +738,7 @@ impl SuffixStrategy {
|
|||||||
struct RequiredExtensionStrategy(HashMap<Vec<u8>, Vec<(usize, Regex)>, Fnv>);
|
struct RequiredExtensionStrategy(HashMap<Vec<u8>, Vec<(usize, Regex)>, Fnv>);
|
||||||
|
|
||||||
impl RequiredExtensionStrategy {
|
impl RequiredExtensionStrategy {
|
||||||
fn is_match(&self, candidate: &Candidate) -> bool {
|
fn is_match(&self, candidate: &Candidate<'_>) -> bool {
|
||||||
if candidate.ext.is_empty() {
|
if candidate.ext.is_empty() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -726,7 +756,11 @@ impl RequiredExtensionStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn matches_into(&self, candidate: &Candidate, matches: &mut Vec<usize>) {
|
fn matches_into(
|
||||||
|
&self,
|
||||||
|
candidate: &Candidate<'_>,
|
||||||
|
matches: &mut Vec<usize>,
|
||||||
|
) {
|
||||||
if candidate.ext.is_empty() {
|
if candidate.ext.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -747,11 +781,15 @@ struct RegexSetStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RegexSetStrategy {
|
impl RegexSetStrategy {
|
||||||
fn is_match(&self, candidate: &Candidate) -> bool {
|
fn is_match(&self, candidate: &Candidate<'_>) -> bool {
|
||||||
self.matcher.is_match(candidate.path.as_bytes())
|
self.matcher.is_match(candidate.path.as_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn matches_into(&self, candidate: &Candidate, matches: &mut Vec<usize>) {
|
fn matches_into(
|
||||||
|
&self,
|
||||||
|
candidate: &Candidate<'_>,
|
||||||
|
matches: &mut Vec<usize>,
|
||||||
|
) {
|
||||||
for i in self.matcher.matches(candidate.path.as_bytes()) {
|
for i in self.matcher.matches(candidate.path.as_bytes()) {
|
||||||
matches.push(self.map[i]);
|
matches.push(self.map[i]);
|
||||||
}
|
}
|
||||||
@@ -767,11 +805,7 @@ struct MultiStrategyBuilder {
|
|||||||
|
|
||||||
impl MultiStrategyBuilder {
|
impl MultiStrategyBuilder {
|
||||||
fn new() -> MultiStrategyBuilder {
|
fn new() -> MultiStrategyBuilder {
|
||||||
MultiStrategyBuilder {
|
MultiStrategyBuilder { literals: vec![], map: vec![], longest: 0 }
|
||||||
literals: vec![],
|
|
||||||
map: vec![],
|
|
||||||
longest: 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add(&mut self, global_index: usize, literal: String) {
|
fn add(&mut self, global_index: usize, literal: String) {
|
||||||
@@ -838,8 +872,8 @@ impl RequiredExtensionStrategyBuilder {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::GlobSetBuilder;
|
use super::{GlobSet, GlobSetBuilder};
|
||||||
use glob::Glob;
|
use crate::glob::Glob;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn set_works() {
|
fn set_works() {
|
||||||
@@ -868,4 +902,11 @@ mod tests {
|
|||||||
assert!(!set.is_match(""));
|
assert!(!set.is_match(""));
|
||||||
assert!(!set.is_match("a"));
|
assert!(!set.is_match("a"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default_set_is_empty_works() {
|
||||||
|
let set: GlobSet = Default::default();
|
||||||
|
assert!(!set.is_match(""));
|
||||||
|
assert!(!set.is_match("a"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use bstr::BStr;
|
use bstr::{ByteSlice, ByteVec};
|
||||||
|
|
||||||
/// The final component of the path, if it is a normal file.
|
/// The final component of the path, if it is a normal file.
|
||||||
///
|
///
|
||||||
/// If the path terminates in ., .., or consists solely of a root of prefix,
|
/// If the path terminates in ., .., or consists solely of a root of prefix,
|
||||||
/// file_name will return None.
|
/// file_name will return None.
|
||||||
pub fn file_name<'a>(path: &Cow<'a, BStr>) -> Option<Cow<'a, BStr>> {
|
pub fn file_name<'a>(path: &Cow<'a, [u8]>) -> Option<Cow<'a, [u8]>> {
|
||||||
if path.is_empty() {
|
if path.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
} else if path.last() == Some(b'.') {
|
} else if path.last_byte() == Some(b'.') {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let last_slash = path.rfind_byte(b'/').map(|i| i + 1).unwrap_or(0);
|
let last_slash = path.rfind_byte(b'/').map(|i| i + 1).unwrap_or(0);
|
||||||
@@ -39,7 +39,7 @@ pub fn file_name<'a>(path: &Cow<'a, BStr>) -> Option<Cow<'a, BStr>> {
|
|||||||
/// a pattern like `*.rs` is obviously trying to match files with a `rs`
|
/// a pattern like `*.rs` is obviously trying to match files with a `rs`
|
||||||
/// extension, but it also matches files like `.rs`, which doesn't have an
|
/// extension, but it also matches files like `.rs`, which doesn't have an
|
||||||
/// extension according to std::path::Path::extension.
|
/// extension according to std::path::Path::extension.
|
||||||
pub fn file_name_ext<'a>(name: &Cow<'a, BStr>) -> Option<Cow<'a, BStr>> {
|
pub fn file_name_ext<'a>(name: &Cow<'a, [u8]>) -> Option<Cow<'a, [u8]>> {
|
||||||
if name.is_empty() {
|
if name.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@@ -60,7 +60,7 @@ pub fn file_name_ext<'a>(name: &Cow<'a, BStr>) -> Option<Cow<'a, BStr>> {
|
|||||||
/// Normalizes a path to use `/` as a separator everywhere, even on platforms
|
/// Normalizes a path to use `/` as a separator everywhere, even on platforms
|
||||||
/// that recognize other characters as separators.
|
/// that recognize other characters as separators.
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub fn normalize_path(path: Cow<BStr>) -> Cow<BStr> {
|
pub fn normalize_path(path: Cow<'_, [u8]>) -> Cow<'_, [u8]> {
|
||||||
// UNIX only uses /, so we're good.
|
// UNIX only uses /, so we're good.
|
||||||
path
|
path
|
||||||
}
|
}
|
||||||
@@ -68,7 +68,7 @@ pub fn normalize_path(path: Cow<BStr>) -> Cow<BStr> {
|
|||||||
/// Normalizes a path to use `/` as a separator everywhere, even on platforms
|
/// Normalizes a path to use `/` as a separator everywhere, even on platforms
|
||||||
/// that recognize other characters as separators.
|
/// that recognize other characters as separators.
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
pub fn normalize_path(mut path: Cow<BStr>) -> Cow<BStr> {
|
pub fn normalize_path(mut path: Cow<[u8]>) -> Cow<[u8]> {
|
||||||
use std::path::is_separator;
|
use std::path::is_separator;
|
||||||
|
|
||||||
for i in 0..path.len() {
|
for i in 0..path.len() {
|
||||||
@@ -84,7 +84,7 @@ pub fn normalize_path(mut path: Cow<BStr>) -> Cow<BStr> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use bstr::{B, BString};
|
use bstr::{ByteVec, B};
|
||||||
|
|
||||||
use super::{file_name_ext, normalize_path};
|
use super::{file_name_ext, normalize_path};
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ mod tests {
|
|||||||
($name:ident, $file_name:expr, $ext:expr) => {
|
($name:ident, $file_name:expr, $ext:expr) => {
|
||||||
#[test]
|
#[test]
|
||||||
fn $name() {
|
fn $name() {
|
||||||
let bs = BString::from($file_name);
|
let bs = Vec::from($file_name);
|
||||||
let got = file_name_ext(&Cow::Owned(bs));
|
let got = file_name_ext(&Cow::Owned(bs));
|
||||||
assert_eq!($ext.map(|s| Cow::Borrowed(B(s))), got);
|
assert_eq!($ext.map(|s| Cow::Borrowed(B(s))), got);
|
||||||
}
|
}
|
||||||
@@ -109,7 +109,7 @@ mod tests {
|
|||||||
($name:ident, $path:expr, $expected:expr) => {
|
($name:ident, $path:expr, $expected:expr) => {
|
||||||
#[test]
|
#[test]
|
||||||
fn $name() {
|
fn $name() {
|
||||||
let bs = BString::from_slice($path);
|
let bs = Vec::from_slice($path);
|
||||||
let got = normalize_path(Cow::Owned(bs));
|
let got = normalize_path(Cow::Owned(bs));
|
||||||
assert_eq!($expected.to_vec(), got.into_owned());
|
assert_eq!($expected.to_vec(), got.into_owned());
|
||||||
}
|
}
|
||||||
38
crates/globset/src/serde_impl.rs
Normal file
38
crates/globset/src/serde_impl.rs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
use serde::de::Error;
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
|
||||||
|
use crate::Glob;
|
||||||
|
|
||||||
|
impl Serialize for Glob {
|
||||||
|
fn serialize<S: Serializer>(
|
||||||
|
&self,
|
||||||
|
serializer: S,
|
||||||
|
) -> Result<S::Ok, S::Error> {
|
||||||
|
serializer.serialize_str(self.glob())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Glob {
|
||||||
|
fn deserialize<D: Deserializer<'de>>(
|
||||||
|
deserializer: D,
|
||||||
|
) -> Result<Self, D::Error> {
|
||||||
|
let glob = <&str as Deserialize>::deserialize(deserializer)?;
|
||||||
|
Glob::new(glob).map_err(D::Error::custom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use Glob;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn glob_json_works() {
|
||||||
|
let test_glob = Glob::new("src/**/*.rs").unwrap();
|
||||||
|
|
||||||
|
let ser = serde_json::to_string(&test_glob).unwrap();
|
||||||
|
assert_eq!(ser, "\"src/**/*.rs\"");
|
||||||
|
|
||||||
|
let de: Glob = serde_json::from_str(&ser).unwrap();
|
||||||
|
assert_eq!(test_glob, de);
|
||||||
|
}
|
||||||
|
}
|
||||||
33
crates/grep/Cargo.toml
Normal file
33
crates/grep/Cargo.toml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
[package]
|
||||||
|
name = "grep"
|
||||||
|
version = "0.2.10" #:version
|
||||||
|
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||||
|
description = """
|
||||||
|
Fast line oriented regex searching as a library.
|
||||||
|
"""
|
||||||
|
documentation = "https://docs.rs/grep"
|
||||||
|
homepage = "https://github.com/BurntSushi/ripgrep/tree/master/crates/grep"
|
||||||
|
repository = "https://github.com/BurntSushi/ripgrep/tree/master/crates/grep"
|
||||||
|
readme = "README.md"
|
||||||
|
keywords = ["regex", "grep", "egrep", "search", "pattern"]
|
||||||
|
license = "Unlicense OR MIT"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
grep-cli = { version = "0.1.7", path = "../cli" }
|
||||||
|
grep-matcher = { version = "0.1.6", path = "../matcher" }
|
||||||
|
grep-pcre2 = { version = "0.1.6", path = "../pcre2", optional = true }
|
||||||
|
grep-printer = { version = "0.1.6", path = "../printer" }
|
||||||
|
grep-regex = { version = "0.1.11", path = "../regex" }
|
||||||
|
grep-searcher = { version = "0.1.10", path = "../searcher" }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
termcolor = "1.0.4"
|
||||||
|
walkdir = "2.2.7"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
simd-accel = ["grep-searcher/simd-accel"]
|
||||||
|
pcre2 = ["grep-pcre2"]
|
||||||
|
|
||||||
|
# This feature is DEPRECATED. Runtime dispatch is used for SIMD now.
|
||||||
|
avx-accel = []
|
||||||
@@ -2,11 +2,10 @@ grep
|
|||||||
----
|
----
|
||||||
ripgrep, as a library.
|
ripgrep, as a library.
|
||||||
|
|
||||||
[](https://travis-ci.org/BurntSushi/ripgrep)
|
[](https://github.com/BurntSushi/ripgrep/actions)
|
||||||
[](https://ci.appveyor.com/project/BurntSushi/ripgrep)
|
|
||||||
[](https://crates.io/crates/grep)
|
[](https://crates.io/crates/grep)
|
||||||
|
|
||||||
Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org).
|
Dual-licensed under MIT or the [UNLICENSE](https://unlicense.org/).
|
||||||
|
|
||||||
|
|
||||||
### Documentation
|
### Documentation
|
||||||
@@ -27,12 +26,6 @@ Add this to your `Cargo.toml`:
|
|||||||
grep = "0.2"
|
grep = "0.2"
|
||||||
```
|
```
|
||||||
|
|
||||||
and this to your crate root:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
extern crate grep;
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
@@ -1,7 +1,3 @@
|
|||||||
extern crate grep;
|
|
||||||
extern crate termcolor;
|
|
||||||
extern crate walkdir;
|
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
@@ -21,7 +17,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_main() -> Result<(), Box<Error>> {
|
fn try_main() -> Result<(), Box<dyn Error>> {
|
||||||
let mut args: Vec<OsString> = env::args_os().collect();
|
let mut args: Vec<OsString> = env::args_os().collect();
|
||||||
if args.len() < 2 {
|
if args.len() < 2 {
|
||||||
return Err("Usage: simplegrep <pattern> [<path> ...]".into());
|
return Err("Usage: simplegrep <pattern> [<path> ...]".into());
|
||||||
@@ -32,7 +28,7 @@ fn try_main() -> Result<(), Box<Error>> {
|
|||||||
search(cli::pattern_from_os(&args[1])?, &args[2..])
|
search(cli::pattern_from_os(&args[1])?, &args[2..])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search(pattern: &str, paths: &[OsString]) -> Result<(), Box<Error>> {
|
fn search(pattern: &str, paths: &[OsString]) -> Result<(), Box<dyn Error>> {
|
||||||
let matcher = RegexMatcher::new_line_matcher(&pattern)?;
|
let matcher = RegexMatcher::new_line_matcher(&pattern)?;
|
||||||
let mut searcher = SearcherBuilder::new()
|
let mut searcher = SearcherBuilder::new()
|
||||||
.binary_detection(BinaryDetection::quit(b'\x00'))
|
.binary_detection(BinaryDetection::quit(b'\x00'))
|
||||||
@@ -40,13 +36,11 @@ fn search(pattern: &str, paths: &[OsString]) -> Result<(), Box<Error>> {
|
|||||||
.build();
|
.build();
|
||||||
let mut printer = StandardBuilder::new()
|
let mut printer = StandardBuilder::new()
|
||||||
.color_specs(ColorSpecs::default_with_color())
|
.color_specs(ColorSpecs::default_with_color())
|
||||||
.build(cli::stdout(
|
.build(cli::stdout(if cli::is_tty_stdout() {
|
||||||
if cli::is_tty_stdout() {
|
ColorChoice::Auto
|
||||||
ColorChoice::Auto
|
} else {
|
||||||
} else {
|
ColorChoice::Never
|
||||||
ColorChoice::Never
|
}));
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
for path in paths {
|
for path in paths {
|
||||||
for result in WalkDir::new(path) {
|
for result in WalkDir::new(path) {
|
||||||
@@ -1,38 +1,38 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ignore"
|
name = "ignore"
|
||||||
version = "0.4.7" #:version
|
version = "0.4.19" #: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`
|
||||||
against file paths.
|
against file paths.
|
||||||
"""
|
"""
|
||||||
documentation = "https://docs.rs/ignore"
|
documentation = "https://docs.rs/ignore"
|
||||||
homepage = "https://github.com/BurntSushi/ripgrep/tree/master/ignore"
|
homepage = "https://github.com/BurntSushi/ripgrep/tree/master/crates/ignore"
|
||||||
repository = "https://github.com/BurntSushi/ripgrep/tree/master/ignore"
|
repository = "https://github.com/BurntSushi/ripgrep/tree/master/crates/ignore"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
keywords = ["glob", "ignore", "gitignore", "pattern", "file"]
|
keywords = ["glob", "ignore", "gitignore", "pattern", "file"]
|
||||||
license = "Unlicense/MIT"
|
license = "Unlicense OR MIT"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "ignore"
|
name = "ignore"
|
||||||
bench = false
|
bench = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
crossbeam-channel = "0.3.6"
|
globset = { version = "0.4.10", path = "../globset" }
|
||||||
globset = { version = "0.4.3", path = "../globset" }
|
|
||||||
lazy_static = "1.1"
|
lazy_static = "1.1"
|
||||||
log = "0.4.5"
|
log = "0.4.5"
|
||||||
memchr = "2.1"
|
memchr = "2.1"
|
||||||
regex = "1.1"
|
regex = "1.1"
|
||||||
same-file = "1.0.4"
|
same-file = "1.0.4"
|
||||||
thread_local = "0.3.6"
|
thread_local = "1"
|
||||||
walkdir = "2.2.7"
|
walkdir = "2.2.7"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies.winapi-util]
|
[target.'cfg(windows)'.dependencies.winapi-util]
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3.0.5"
|
crossbeam-channel = "0.5.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
simd-accel = ["globset/simd-accel"]
|
simd-accel = ["globset/simd-accel"]
|
||||||
@@ -4,11 +4,10 @@ The ignore crate provides a fast recursive directory iterator that respects
|
|||||||
various filters such as globs, file types and `.gitignore` files. This crate
|
various filters such as globs, file types and `.gitignore` files. This crate
|
||||||
also provides lower level direct access to gitignore and file type matchers.
|
also provides lower level direct access to gitignore and file type matchers.
|
||||||
|
|
||||||
[](https://travis-ci.org/BurntSushi/ripgrep)
|
[](https://github.com/BurntSushi/ripgrep/actions)
|
||||||
[](https://ci.appveyor.com/project/BurntSushi/ripgrep)
|
|
||||||
[](https://crates.io/crates/ignore)
|
[](https://crates.io/crates/ignore)
|
||||||
|
|
||||||
Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org).
|
Dual-licensed under MIT or the [UNLICENSE](https://unlicense.org/).
|
||||||
|
|
||||||
### Documentation
|
### Documentation
|
||||||
|
|
||||||
@@ -23,12 +22,6 @@ Add this to your `Cargo.toml`:
|
|||||||
ignore = "0.4"
|
ignore = "0.4"
|
||||||
```
|
```
|
||||||
|
|
||||||
and this to your crate root:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
extern crate ignore;
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
This example shows the most basic usage of this crate. This code will
|
This example shows the most basic usage of this crate. This code will
|
||||||
@@ -1,7 +1,3 @@
|
|||||||
extern crate crossbeam_channel as channel;
|
|
||||||
extern crate ignore;
|
|
||||||
extern crate walkdir;
|
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
@@ -14,7 +10,7 @@ fn main() {
|
|||||||
let mut path = env::args().nth(1).unwrap();
|
let mut path = env::args().nth(1).unwrap();
|
||||||
let mut parallel = false;
|
let mut parallel = false;
|
||||||
let mut simple = false;
|
let mut simple = false;
|
||||||
let (tx, rx) = channel::bounded::<DirEntry>(100);
|
let (tx, rx) = crossbeam_channel::bounded::<DirEntry>(100);
|
||||||
if path == "parallel" {
|
if path == "parallel" {
|
||||||
path = env::args().nth(2).unwrap();
|
path = env::args().nth(2).unwrap();
|
||||||
parallel = true;
|
parallel = true;
|
||||||
316
crates/ignore/src/default_types.rs
Normal file
316
crates/ignore/src/default_types.rs
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
/// This list represents the default file types that ripgrep ships with. In
|
||||||
|
/// general, any file format is fair game, although it should generally be
|
||||||
|
/// limited to reasonably popular open formats. For other cases, you can add
|
||||||
|
/// types to each invocation of ripgrep with the '--type-add' flag.
|
||||||
|
///
|
||||||
|
/// If you would like to add or improve this list, please file a PR:
|
||||||
|
/// <https://github.com/BurntSushi/ripgrep>.
|
||||||
|
///
|
||||||
|
/// Please try to keep this list sorted lexicographically and wrapped to 79
|
||||||
|
/// columns (inclusive).
|
||||||
|
#[rustfmt::skip]
|
||||||
|
pub const DEFAULT_TYPES: &[(&str, &[&str])] = &[
|
||||||
|
("agda", &["*.agda", "*.lagda"]),
|
||||||
|
("aidl", &["*.aidl"]),
|
||||||
|
("amake", &["*.mk", "*.bp"]),
|
||||||
|
("asciidoc", &["*.adoc", "*.asc", "*.asciidoc"]),
|
||||||
|
("asm", &["*.asm", "*.s", "*.S"]),
|
||||||
|
("asp", &[
|
||||||
|
"*.aspx", "*.aspx.cs", "*.aspx.vb", "*.ascx", "*.ascx.cs",
|
||||||
|
"*.ascx.vb", "*.asp"
|
||||||
|
]),
|
||||||
|
("ats", &["*.ats", "*.dats", "*.sats", "*.hats"]),
|
||||||
|
("avro", &["*.avdl", "*.avpr", "*.avsc"]),
|
||||||
|
("awk", &["*.awk"]),
|
||||||
|
("bazel", &[
|
||||||
|
"*.bazel", "*.bzl", "*.BUILD", "*.bazelrc", "BUILD", "MODULE.bazel",
|
||||||
|
"WORKSPACE", "WORKSPACE.bazel",
|
||||||
|
]),
|
||||||
|
("bitbake", &["*.bb", "*.bbappend", "*.bbclass", "*.conf", "*.inc"]),
|
||||||
|
("brotli", &["*.br"]),
|
||||||
|
("buildstream", &["*.bst"]),
|
||||||
|
("bzip2", &["*.bz2", "*.tbz2"]),
|
||||||
|
("c", &["*.[chH]", "*.[chH].in", "*.cats"]),
|
||||||
|
("cabal", &["*.cabal"]),
|
||||||
|
("candid", &["*.did"]),
|
||||||
|
("carp", &["*.carp"]),
|
||||||
|
("cbor", &["*.cbor"]),
|
||||||
|
("ceylon", &["*.ceylon"]),
|
||||||
|
("clojure", &["*.clj", "*.cljc", "*.cljs", "*.cljx"]),
|
||||||
|
("cmake", &["*.cmake", "CMakeLists.txt"]),
|
||||||
|
("coffeescript", &["*.coffee"]),
|
||||||
|
("config", &["*.cfg", "*.conf", "*.config", "*.ini"]),
|
||||||
|
("coq", &["*.v"]),
|
||||||
|
("cpp", &[
|
||||||
|
"*.[ChH]", "*.cc", "*.[ch]pp", "*.[ch]xx", "*.hh", "*.inl",
|
||||||
|
"*.[ChH].in", "*.cc.in", "*.[ch]pp.in", "*.[ch]xx.in", "*.hh.in",
|
||||||
|
]),
|
||||||
|
("creole", &["*.creole"]),
|
||||||
|
("crystal", &["Projectfile", "*.cr", "*.ecr", "shard.yml"]),
|
||||||
|
("cs", &["*.cs"]),
|
||||||
|
("csharp", &["*.cs"]),
|
||||||
|
("cshtml", &["*.cshtml"]),
|
||||||
|
("css", &["*.css", "*.scss"]),
|
||||||
|
("csv", &["*.csv"]),
|
||||||
|
("cuda", &["*.cu", "*.cuh"]),
|
||||||
|
("cython", &["*.pyx", "*.pxi", "*.pxd"]),
|
||||||
|
("d", &["*.d"]),
|
||||||
|
("dart", &["*.dart"]),
|
||||||
|
("devicetree", &["*.dts", "*.dtsi"]),
|
||||||
|
("dhall", &["*.dhall"]),
|
||||||
|
("diff", &["*.patch", "*.diff"]),
|
||||||
|
("docker", &["*Dockerfile*"]),
|
||||||
|
("dts", &["*.dts", "*.dtsi"]),
|
||||||
|
("dvc", &["Dvcfile", "*.dvc"]),
|
||||||
|
("ebuild", &["*.ebuild"]),
|
||||||
|
("edn", &["*.edn"]),
|
||||||
|
("elisp", &["*.el"]),
|
||||||
|
("elixir", &["*.ex", "*.eex", "*.exs"]),
|
||||||
|
("elm", &["*.elm"]),
|
||||||
|
("erb", &["*.erb"]),
|
||||||
|
("erlang", &["*.erl", "*.hrl"]),
|
||||||
|
("fennel", &["*.fnl"]),
|
||||||
|
("fidl", &["*.fidl"]),
|
||||||
|
("fish", &["*.fish"]),
|
||||||
|
("flatbuffers", &["*.fbs"]),
|
||||||
|
("fortran", &[
|
||||||
|
"*.f", "*.F", "*.f77", "*.F77", "*.pfo",
|
||||||
|
"*.f90", "*.F90", "*.f95", "*.F95",
|
||||||
|
]),
|
||||||
|
("fsharp", &["*.fs", "*.fsx", "*.fsi"]),
|
||||||
|
("fut", &["*.fut"]),
|
||||||
|
("gap", &["*.g", "*.gap", "*.gi", "*.gd", "*.tst"]),
|
||||||
|
("gn", &["*.gn", "*.gni"]),
|
||||||
|
("go", &["*.go"]),
|
||||||
|
("gradle", &["*.gradle"]),
|
||||||
|
("groovy", &["*.groovy", "*.gradle"]),
|
||||||
|
("gzip", &["*.gz", "*.tgz"]),
|
||||||
|
("h", &["*.h", "*.hh", "*.hpp"]),
|
||||||
|
("haml", &["*.haml"]),
|
||||||
|
("hare", &["*.ha"]),
|
||||||
|
("haskell", &["*.hs", "*.lhs", "*.cpphs", "*.c2hs", "*.hsc"]),
|
||||||
|
("hbs", &["*.hbs"]),
|
||||||
|
("hs", &["*.hs", "*.lhs"]),
|
||||||
|
("html", &["*.htm", "*.html", "*.ejs"]),
|
||||||
|
("hy", &["*.hy"]),
|
||||||
|
("idris", &["*.idr", "*.lidr"]),
|
||||||
|
("janet", &["*.janet"]),
|
||||||
|
("java", &["*.java", "*.jsp", "*.jspx", "*.properties"]),
|
||||||
|
("jinja", &["*.j2", "*.jinja", "*.jinja2"]),
|
||||||
|
("jl", &["*.jl"]),
|
||||||
|
("js", &["*.js", "*.jsx", "*.vue", "*.cjs", "*.mjs"]),
|
||||||
|
("json", &["*.json", "composer.lock"]),
|
||||||
|
("jsonl", &["*.jsonl"]),
|
||||||
|
("julia", &["*.jl"]),
|
||||||
|
("jupyter", &["*.ipynb", "*.jpynb"]),
|
||||||
|
("k", &["*.k"]),
|
||||||
|
("kotlin", &["*.kt", "*.kts"]),
|
||||||
|
("less", &["*.less"]),
|
||||||
|
("license", &[
|
||||||
|
// General
|
||||||
|
"COPYING", "COPYING[.-]*",
|
||||||
|
"COPYRIGHT", "COPYRIGHT[.-]*",
|
||||||
|
"EULA", "EULA[.-]*",
|
||||||
|
"licen[cs]e", "licen[cs]e.*",
|
||||||
|
"LICEN[CS]E", "LICEN[CS]E[.-]*", "*[.-]LICEN[CS]E*",
|
||||||
|
"NOTICE", "NOTICE[.-]*",
|
||||||
|
"PATENTS", "PATENTS[.-]*",
|
||||||
|
"UNLICEN[CS]E", "UNLICEN[CS]E[.-]*",
|
||||||
|
// GPL (gpl.txt, etc.)
|
||||||
|
"agpl[.-]*",
|
||||||
|
"gpl[.-]*",
|
||||||
|
"lgpl[.-]*",
|
||||||
|
// Other license-specific (APACHE-2.0.txt, etc.)
|
||||||
|
"AGPL-*[0-9]*",
|
||||||
|
"APACHE-*[0-9]*",
|
||||||
|
"BSD-*[0-9]*",
|
||||||
|
"CC-BY-*",
|
||||||
|
"GFDL-*[0-9]*",
|
||||||
|
"GNU-*[0-9]*",
|
||||||
|
"GPL-*[0-9]*",
|
||||||
|
"LGPL-*[0-9]*",
|
||||||
|
"MIT-*[0-9]*",
|
||||||
|
"MPL-*[0-9]*",
|
||||||
|
"OFL-*[0-9]*",
|
||||||
|
]),
|
||||||
|
("lilypond", &["*.ly", "*.ily"]),
|
||||||
|
("lisp", &["*.el", "*.jl", "*.lisp", "*.lsp", "*.sc", "*.scm"]),
|
||||||
|
("lock", &["*.lock", "package-lock.json"]),
|
||||||
|
("log", &["*.log"]),
|
||||||
|
("lua", &["*.lua"]),
|
||||||
|
("lz4", &["*.lz4"]),
|
||||||
|
("lzma", &["*.lzma"]),
|
||||||
|
("m4", &["*.ac", "*.m4"]),
|
||||||
|
("make", &[
|
||||||
|
"[Gg][Nn][Uu]makefile", "[Mm]akefile",
|
||||||
|
"[Gg][Nn][Uu]makefile.am", "[Mm]akefile.am",
|
||||||
|
"[Gg][Nn][Uu]makefile.in", "[Mm]akefile.in",
|
||||||
|
"*.mk", "*.mak"
|
||||||
|
]),
|
||||||
|
("mako", &["*.mako", "*.mao"]),
|
||||||
|
("man", &["*.[0-9lnpx]", "*.[0-9][cEFMmpSx]"]),
|
||||||
|
("markdown", &["*.markdown", "*.md", "*.mdown", "*.mkd", "*.mkdn"]),
|
||||||
|
("matlab", &["*.m"]),
|
||||||
|
("md", &["*.markdown", "*.md", "*.mdown", "*.mkd", "*.mkdn"]),
|
||||||
|
("meson", &["meson.build", "meson_options.txt"]),
|
||||||
|
("minified", &["*.min.html", "*.min.css", "*.min.js"]),
|
||||||
|
("mint", &["*.mint"]),
|
||||||
|
("mk", &["mkfile"]),
|
||||||
|
("ml", &["*.ml"]),
|
||||||
|
("motoko", &["*.mo"]),
|
||||||
|
("msbuild", &[
|
||||||
|
"*.csproj", "*.fsproj", "*.vcxproj", "*.proj", "*.props", "*.targets",
|
||||||
|
]),
|
||||||
|
("nim", &["*.nim", "*.nimf", "*.nimble", "*.nims"]),
|
||||||
|
("nix", &["*.nix"]),
|
||||||
|
("objc", &["*.h", "*.m"]),
|
||||||
|
("objcpp", &["*.h", "*.mm"]),
|
||||||
|
("ocaml", &["*.ml", "*.mli", "*.mll", "*.mly"]),
|
||||||
|
("org", &["*.org", "*.org_archive"]),
|
||||||
|
("pants", &["BUILD"]),
|
||||||
|
("pascal", &["*.pas", "*.dpr", "*.lpr", "*.pp", "*.inc"]),
|
||||||
|
("pdf", &["*.pdf"]),
|
||||||
|
("perl", &["*.perl", "*.pl", "*.PL", "*.plh", "*.plx", "*.pm", "*.t"]),
|
||||||
|
("php", &[
|
||||||
|
// note that PHP 6 doesn't exist
|
||||||
|
// See: https://wiki.php.net/rfc/php6
|
||||||
|
"*.php", "*.php3", "*.php4", "*.php5", "*.php7", "*.php8",
|
||||||
|
"*.pht", "*.phtml"
|
||||||
|
]),
|
||||||
|
("po", &["*.po"]),
|
||||||
|
("pod", &["*.pod"]),
|
||||||
|
("postscript", &["*.eps", "*.ps"]),
|
||||||
|
("protobuf", &["*.proto"]),
|
||||||
|
("ps", &["*.cdxml", "*.ps1", "*.ps1xml", "*.psd1", "*.psm1"]),
|
||||||
|
("puppet", &["*.epp", "*.erb", "*.pp", "*.rb"]),
|
||||||
|
("purs", &["*.purs"]),
|
||||||
|
("py", &["*.py"]),
|
||||||
|
("qmake", &["*.pro", "*.pri", "*.prf"]),
|
||||||
|
("qml", &["*.qml"]),
|
||||||
|
("r", &["*.R", "*.r", "*.Rmd", "*.Rnw"]),
|
||||||
|
("racket", &["*.rkt"]),
|
||||||
|
("rdoc", &["*.rdoc"]),
|
||||||
|
("readme", &["README*", "*README"]),
|
||||||
|
("reasonml", &["*.re", "*.rei"]),
|
||||||
|
("red", &["*.r", "*.red", "*.reds"]),
|
||||||
|
("rescript", &["*.res", "*.resi"]),
|
||||||
|
("robot", &["*.robot"]),
|
||||||
|
("rst", &["*.rst"]),
|
||||||
|
("ruby", &[
|
||||||
|
// Idiomatic files
|
||||||
|
"config.ru", "Gemfile", ".irbrc", "Rakefile",
|
||||||
|
// Extensions
|
||||||
|
"*.gemspec", "*.rb", "*.rbw"
|
||||||
|
]),
|
||||||
|
("rust", &["*.rs"]),
|
||||||
|
("sass", &["*.sass", "*.scss"]),
|
||||||
|
("scala", &["*.scala", "*.sbt"]),
|
||||||
|
("sh", &[
|
||||||
|
// Portable/misc. init files
|
||||||
|
".login", ".logout", ".profile", "profile",
|
||||||
|
// bash-specific init files
|
||||||
|
".bash_login", "bash_login",
|
||||||
|
".bash_logout", "bash_logout",
|
||||||
|
".bash_profile", "bash_profile",
|
||||||
|
".bashrc", "bashrc", "*.bashrc",
|
||||||
|
// csh-specific init files
|
||||||
|
".cshrc", "*.cshrc",
|
||||||
|
// ksh-specific init files
|
||||||
|
".kshrc", "*.kshrc",
|
||||||
|
// tcsh-specific init files
|
||||||
|
".tcshrc",
|
||||||
|
// zsh-specific init files
|
||||||
|
".zshenv", "zshenv",
|
||||||
|
".zlogin", "zlogin",
|
||||||
|
".zlogout", "zlogout",
|
||||||
|
".zprofile", "zprofile",
|
||||||
|
".zshrc", "zshrc",
|
||||||
|
// Extensions
|
||||||
|
"*.bash", "*.csh", "*.ksh", "*.sh", "*.tcsh", "*.zsh",
|
||||||
|
]),
|
||||||
|
("slim", &["*.skim", "*.slim", "*.slime"]),
|
||||||
|
("smarty", &["*.tpl"]),
|
||||||
|
("sml", &["*.sml", "*.sig"]),
|
||||||
|
("solidity", &["*.sol"]),
|
||||||
|
("soy", &["*.soy"]),
|
||||||
|
("spark", &["*.spark"]),
|
||||||
|
("spec", &["*.spec"]),
|
||||||
|
("sql", &["*.sql", "*.psql"]),
|
||||||
|
("stylus", &["*.styl"]),
|
||||||
|
("sv", &["*.v", "*.vg", "*.sv", "*.svh", "*.h"]),
|
||||||
|
("svg", &["*.svg"]),
|
||||||
|
("swift", &["*.swift"]),
|
||||||
|
("swig", &["*.def", "*.i"]),
|
||||||
|
("systemd", &[
|
||||||
|
"*.automount", "*.conf", "*.device", "*.link", "*.mount", "*.path",
|
||||||
|
"*.scope", "*.service", "*.slice", "*.socket", "*.swap", "*.target",
|
||||||
|
"*.timer",
|
||||||
|
]),
|
||||||
|
("taskpaper", &["*.taskpaper"]),
|
||||||
|
("tcl", &["*.tcl"]),
|
||||||
|
("tex", &["*.tex", "*.ltx", "*.cls", "*.sty", "*.bib", "*.dtx", "*.ins"]),
|
||||||
|
("texinfo", &["*.texi"]),
|
||||||
|
("textile", &["*.textile"]),
|
||||||
|
("tf", &["*.tf"]),
|
||||||
|
("thrift", &["*.thrift"]),
|
||||||
|
("toml", &["*.toml", "Cargo.lock"]),
|
||||||
|
("ts", &["*.ts", "*.tsx", "*.cts", "*.mts"]),
|
||||||
|
("twig", &["*.twig"]),
|
||||||
|
("txt", &["*.txt"]),
|
||||||
|
("typoscript", &["*.typoscript", "*.ts"]),
|
||||||
|
("vala", &["*.vala"]),
|
||||||
|
("vb", &["*.vb"]),
|
||||||
|
("vcl", &["*.vcl"]),
|
||||||
|
("verilog", &["*.v", "*.vh", "*.sv", "*.svh"]),
|
||||||
|
("vhdl", &["*.vhd", "*.vhdl"]),
|
||||||
|
("vim", &[
|
||||||
|
"*.vim", ".vimrc", ".gvimrc", "vimrc", "gvimrc", "_vimrc", "_gvimrc",
|
||||||
|
]),
|
||||||
|
("vimscript", &[
|
||||||
|
"*.vim", ".vimrc", ".gvimrc", "vimrc", "gvimrc", "_vimrc", "_gvimrc",
|
||||||
|
]),
|
||||||
|
("webidl", &["*.idl", "*.webidl", "*.widl"]),
|
||||||
|
("wiki", &["*.mediawiki", "*.wiki"]),
|
||||||
|
("xml", &[
|
||||||
|
"*.xml", "*.xml.dist", "*.dtd", "*.xsl", "*.xslt", "*.xsd", "*.xjb",
|
||||||
|
"*.rng", "*.sch", "*.xhtml",
|
||||||
|
]),
|
||||||
|
("xz", &["*.xz", "*.txz"]),
|
||||||
|
("yacc", &["*.y"]),
|
||||||
|
("yaml", &["*.yaml", "*.yml"]),
|
||||||
|
("yang", &["*.yang"]),
|
||||||
|
("z", &["*.Z"]),
|
||||||
|
("zig", &["*.zig"]),
|
||||||
|
("zsh", &[
|
||||||
|
".zshenv", "zshenv",
|
||||||
|
".zlogin", "zlogin",
|
||||||
|
".zlogout", "zlogout",
|
||||||
|
".zprofile", "zprofile",
|
||||||
|
".zshrc", "zshrc",
|
||||||
|
"*.zsh",
|
||||||
|
]),
|
||||||
|
("zstd", &["*.zst", "*.zstd"]),
|
||||||
|
];
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::DEFAULT_TYPES;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default_types_are_sorted() {
|
||||||
|
let mut names = DEFAULT_TYPES.iter().map(|(name, _exts)| name);
|
||||||
|
|
||||||
|
let Some(mut previous_name) = names.next() else { return; };
|
||||||
|
|
||||||
|
for name in names {
|
||||||
|
assert!(
|
||||||
|
name > previous_name,
|
||||||
|
r#""{}" should be sorted before "{}" in `DEFAULT_TYPES`"#,
|
||||||
|
name,
|
||||||
|
previous_name
|
||||||
|
);
|
||||||
|
|
||||||
|
previous_name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,16 +14,18 @@
|
|||||||
// well.
|
// well.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ffi::{OsString, OsStr};
|
use std::ffi::{OsStr, OsString};
|
||||||
|
use std::fs::{File, FileType};
|
||||||
|
use std::io::{self, BufRead};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use gitignore::{self, Gitignore, GitignoreBuilder};
|
use crate::gitignore::{self, Gitignore, GitignoreBuilder};
|
||||||
use pathutil::{is_hidden, strip_prefix};
|
use crate::overrides::{self, Override};
|
||||||
use overrides::{self, Override};
|
use crate::pathutil::{is_hidden, strip_prefix};
|
||||||
use types::{self, Types};
|
use crate::types::{self, Types};
|
||||||
use walk::DirEntry;
|
use crate::walk::DirEntry;
|
||||||
use {Error, Match, PartialErrorBuilder};
|
use crate::{Error, Match, PartialErrorBuilder};
|
||||||
|
|
||||||
/// IgnoreMatch represents information about where a match came from when using
|
/// IgnoreMatch represents information about where a match came from when using
|
||||||
/// the `Ignore` matcher.
|
/// the `Ignore` matcher.
|
||||||
@@ -76,6 +78,9 @@ struct IgnoreOptions {
|
|||||||
git_exclude: bool,
|
git_exclude: bool,
|
||||||
/// Whether to ignore files case insensitively
|
/// Whether to ignore files case insensitively
|
||||||
ignore_case_insensitive: bool,
|
ignore_case_insensitive: bool,
|
||||||
|
/// Whether a git repository must be present in order to apply any
|
||||||
|
/// git-related ignore rules.
|
||||||
|
require_git: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ignore is a matcher useful for recursively walking one or more directories.
|
/// Ignore is a matcher useful for recursively walking one or more directories.
|
||||||
@@ -197,7 +202,12 @@ impl Ignore {
|
|||||||
errs.maybe_push(err);
|
errs.maybe_push(err);
|
||||||
igtmp.is_absolute_parent = true;
|
igtmp.is_absolute_parent = true;
|
||||||
igtmp.absolute_base = Some(absolute_base.clone());
|
igtmp.absolute_base = Some(absolute_base.clone());
|
||||||
igtmp.has_git = parent.join(".git").exists();
|
igtmp.has_git =
|
||||||
|
if self.0.opts.require_git && self.0.opts.git_ignore {
|
||||||
|
parent.join(".git").exists()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
ig = Ignore(Arc::new(igtmp));
|
ig = Ignore(Arc::new(igtmp));
|
||||||
compiled.insert(parent.as_os_str().to_os_string(), ig.clone());
|
compiled.insert(parent.as_os_str().to_os_string(), ig.clone());
|
||||||
}
|
}
|
||||||
@@ -222,59 +232,72 @@ impl Ignore {
|
|||||||
|
|
||||||
/// Like add_child, but takes a full path and returns an IgnoreInner.
|
/// Like add_child, but takes a full path and returns an IgnoreInner.
|
||||||
fn add_child_path(&self, dir: &Path) -> (IgnoreInner, Option<Error>) {
|
fn add_child_path(&self, dir: &Path) -> (IgnoreInner, Option<Error>) {
|
||||||
|
let git_type = if self.0.opts.require_git
|
||||||
|
&& (self.0.opts.git_ignore || self.0.opts.git_exclude)
|
||||||
|
{
|
||||||
|
dir.join(".git").metadata().ok().map(|md| md.file_type())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let has_git = git_type.map(|_| true).unwrap_or(false);
|
||||||
|
|
||||||
let mut errs = PartialErrorBuilder::default();
|
let mut errs = PartialErrorBuilder::default();
|
||||||
let custom_ig_matcher =
|
let custom_ig_matcher = if self.0.custom_ignore_filenames.is_empty() {
|
||||||
if self.0.custom_ignore_filenames.is_empty() {
|
Gitignore::empty()
|
||||||
Gitignore::empty()
|
} else {
|
||||||
} else {
|
let (m, err) = create_gitignore(
|
||||||
let (m, err) =
|
&dir,
|
||||||
create_gitignore(
|
&dir,
|
||||||
|
&self.0.custom_ignore_filenames,
|
||||||
|
self.0.opts.ignore_case_insensitive,
|
||||||
|
);
|
||||||
|
errs.maybe_push(err);
|
||||||
|
m
|
||||||
|
};
|
||||||
|
let ig_matcher = if !self.0.opts.ignore {
|
||||||
|
Gitignore::empty()
|
||||||
|
} else {
|
||||||
|
let (m, err) = create_gitignore(
|
||||||
|
&dir,
|
||||||
|
&dir,
|
||||||
|
&[".ignore"],
|
||||||
|
self.0.opts.ignore_case_insensitive,
|
||||||
|
);
|
||||||
|
errs.maybe_push(err);
|
||||||
|
m
|
||||||
|
};
|
||||||
|
let gi_matcher = if !self.0.opts.git_ignore {
|
||||||
|
Gitignore::empty()
|
||||||
|
} else {
|
||||||
|
let (m, err) = create_gitignore(
|
||||||
|
&dir,
|
||||||
|
&dir,
|
||||||
|
&[".gitignore"],
|
||||||
|
self.0.opts.ignore_case_insensitive,
|
||||||
|
);
|
||||||
|
errs.maybe_push(err);
|
||||||
|
m
|
||||||
|
};
|
||||||
|
let gi_exclude_matcher = if !self.0.opts.git_exclude {
|
||||||
|
Gitignore::empty()
|
||||||
|
} else {
|
||||||
|
match resolve_git_commondir(dir, git_type) {
|
||||||
|
Ok(git_dir) => {
|
||||||
|
let (m, err) = create_gitignore(
|
||||||
&dir,
|
&dir,
|
||||||
&self.0.custom_ignore_filenames,
|
&git_dir,
|
||||||
|
&["info/exclude"],
|
||||||
self.0.opts.ignore_case_insensitive,
|
self.0.opts.ignore_case_insensitive,
|
||||||
);
|
);
|
||||||
errs.maybe_push(err);
|
errs.maybe_push(err);
|
||||||
m
|
m
|
||||||
};
|
}
|
||||||
let ig_matcher =
|
Err(err) => {
|
||||||
if !self.0.opts.ignore {
|
errs.maybe_push(err);
|
||||||
Gitignore::empty()
|
Gitignore::empty()
|
||||||
} else {
|
}
|
||||||
let (m, err) =
|
}
|
||||||
create_gitignore(
|
};
|
||||||
&dir,
|
|
||||||
&[".ignore"],
|
|
||||||
self.0.opts.ignore_case_insensitive,
|
|
||||||
);
|
|
||||||
errs.maybe_push(err);
|
|
||||||
m
|
|
||||||
};
|
|
||||||
let gi_matcher =
|
|
||||||
if !self.0.opts.git_ignore {
|
|
||||||
Gitignore::empty()
|
|
||||||
} else {
|
|
||||||
let (m, err) =
|
|
||||||
create_gitignore(
|
|
||||||
&dir,
|
|
||||||
&[".gitignore"],
|
|
||||||
self.0.opts.ignore_case_insensitive,
|
|
||||||
);
|
|
||||||
errs.maybe_push(err);
|
|
||||||
m
|
|
||||||
};
|
|
||||||
let gi_exclude_matcher =
|
|
||||||
if !self.0.opts.git_exclude {
|
|
||||||
Gitignore::empty()
|
|
||||||
} else {
|
|
||||||
let (m, err) =
|
|
||||||
create_gitignore(
|
|
||||||
&dir,
|
|
||||||
&[".git/info/exclude"],
|
|
||||||
self.0.opts.ignore_case_insensitive,
|
|
||||||
);
|
|
||||||
errs.maybe_push(err);
|
|
||||||
m
|
|
||||||
};
|
|
||||||
let ig = IgnoreInner {
|
let ig = IgnoreInner {
|
||||||
compiled: self.0.compiled.clone(),
|
compiled: self.0.compiled.clone(),
|
||||||
dir: dir.to_path_buf(),
|
dir: dir.to_path_buf(),
|
||||||
@@ -290,7 +313,7 @@ impl Ignore {
|
|||||||
git_global_matcher: self.0.git_global_matcher.clone(),
|
git_global_matcher: self.0.git_global_matcher.clone(),
|
||||||
git_ignore_matcher: gi_matcher,
|
git_ignore_matcher: gi_matcher,
|
||||||
git_exclude_matcher: gi_exclude_matcher,
|
git_exclude_matcher: gi_exclude_matcher,
|
||||||
has_git: dir.join(".git").exists(),
|
has_git,
|
||||||
opts: self.0.opts,
|
opts: self.0.opts,
|
||||||
};
|
};
|
||||||
(ig, errs.into_error_option())
|
(ig, errs.into_error_option())
|
||||||
@@ -299,12 +322,16 @@ impl Ignore {
|
|||||||
/// Returns true if at least one type of ignore rule should be matched.
|
/// Returns true if at least one type of ignore rule should be matched.
|
||||||
fn has_any_ignore_rules(&self) -> bool {
|
fn has_any_ignore_rules(&self) -> bool {
|
||||||
let opts = self.0.opts;
|
let opts = self.0.opts;
|
||||||
let has_custom_ignore_files = !self.0.custom_ignore_filenames.is_empty();
|
let has_custom_ignore_files =
|
||||||
|
!self.0.custom_ignore_filenames.is_empty();
|
||||||
let has_explicit_ignores = !self.0.explicit_ignores.is_empty();
|
let has_explicit_ignores = !self.0.explicit_ignores.is_empty();
|
||||||
|
|
||||||
opts.ignore || opts.git_global || opts.git_ignore
|
opts.ignore
|
||||||
|| opts.git_exclude || has_custom_ignore_files
|
|| opts.git_global
|
||||||
|| has_explicit_ignores
|
|| opts.git_ignore
|
||||||
|
|| opts.git_exclude
|
||||||
|
|| has_custom_ignore_files
|
||||||
|
|| has_explicit_ignores
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like `matched`, but works with a directory entry instead.
|
/// Like `matched`, but works with a directory entry instead.
|
||||||
@@ -339,9 +366,11 @@ impl Ignore {
|
|||||||
// return that result immediately. Overrides have the highest
|
// return that result immediately. Overrides have the highest
|
||||||
// precedence.
|
// precedence.
|
||||||
if !self.0.overrides.is_empty() {
|
if !self.0.overrides.is_empty() {
|
||||||
let mat =
|
let mat = self
|
||||||
self.0.overrides.matched(path, is_dir)
|
.0
|
||||||
.map(IgnoreMatch::overrides);
|
.overrides
|
||||||
|
.matched(path, is_dir)
|
||||||
|
.map(IgnoreMatch::overrides);
|
||||||
if !mat.is_none() {
|
if !mat.is_none() {
|
||||||
return mat;
|
return mat;
|
||||||
}
|
}
|
||||||
@@ -374,56 +403,72 @@ impl Ignore {
|
|||||||
path: &Path,
|
path: &Path,
|
||||||
is_dir: bool,
|
is_dir: bool,
|
||||||
) -> Match<IgnoreMatch<'a>> {
|
) -> Match<IgnoreMatch<'a>> {
|
||||||
let (mut m_custom_ignore, mut m_ignore, mut m_gi, mut m_gi_exclude, mut m_explicit) =
|
let (
|
||||||
(Match::None, Match::None, Match::None, Match::None, Match::None);
|
mut m_custom_ignore,
|
||||||
let any_git = self.parents().any(|ig| ig.0.has_git);
|
mut m_ignore,
|
||||||
|
mut m_gi,
|
||||||
|
mut m_gi_exclude,
|
||||||
|
mut m_explicit,
|
||||||
|
) = (Match::None, Match::None, Match::None, Match::None, Match::None);
|
||||||
|
let any_git =
|
||||||
|
!self.0.opts.require_git || self.parents().any(|ig| ig.0.has_git);
|
||||||
let mut saw_git = false;
|
let mut saw_git = false;
|
||||||
for ig in self.parents().take_while(|ig| !ig.0.is_absolute_parent) {
|
for ig in self.parents().take_while(|ig| !ig.0.is_absolute_parent) {
|
||||||
if m_custom_ignore.is_none() {
|
if m_custom_ignore.is_none() {
|
||||||
m_custom_ignore =
|
m_custom_ignore =
|
||||||
ig.0.custom_ignore_matcher.matched(path, is_dir)
|
ig.0.custom_ignore_matcher
|
||||||
.map(IgnoreMatch::gitignore);
|
.matched(path, is_dir)
|
||||||
|
.map(IgnoreMatch::gitignore);
|
||||||
}
|
}
|
||||||
if m_ignore.is_none() {
|
if m_ignore.is_none() {
|
||||||
m_ignore =
|
m_ignore =
|
||||||
ig.0.ignore_matcher.matched(path, is_dir)
|
ig.0.ignore_matcher
|
||||||
.map(IgnoreMatch::gitignore);
|
.matched(path, is_dir)
|
||||||
|
.map(IgnoreMatch::gitignore);
|
||||||
}
|
}
|
||||||
if any_git && !saw_git && m_gi.is_none() {
|
if any_git && !saw_git && m_gi.is_none() {
|
||||||
m_gi =
|
m_gi =
|
||||||
ig.0.git_ignore_matcher.matched(path, is_dir)
|
ig.0.git_ignore_matcher
|
||||||
.map(IgnoreMatch::gitignore);
|
.matched(path, is_dir)
|
||||||
|
.map(IgnoreMatch::gitignore);
|
||||||
}
|
}
|
||||||
if any_git && !saw_git && m_gi_exclude.is_none() {
|
if any_git && !saw_git && m_gi_exclude.is_none() {
|
||||||
m_gi_exclude =
|
m_gi_exclude =
|
||||||
ig.0.git_exclude_matcher.matched(path, is_dir)
|
ig.0.git_exclude_matcher
|
||||||
.map(IgnoreMatch::gitignore);
|
.matched(path, is_dir)
|
||||||
|
.map(IgnoreMatch::gitignore);
|
||||||
}
|
}
|
||||||
saw_git = saw_git || ig.0.has_git;
|
saw_git = saw_git || ig.0.has_git;
|
||||||
}
|
}
|
||||||
if self.0.opts.parents {
|
if self.0.opts.parents {
|
||||||
if let Some(abs_parent_path) = self.absolute_base() {
|
if let Some(abs_parent_path) = self.absolute_base() {
|
||||||
let path = abs_parent_path.join(path);
|
let path = abs_parent_path.join(path);
|
||||||
for ig in self.parents().skip_while(|ig|!ig.0.is_absolute_parent) {
|
for ig in
|
||||||
|
self.parents().skip_while(|ig| !ig.0.is_absolute_parent)
|
||||||
|
{
|
||||||
if m_custom_ignore.is_none() {
|
if m_custom_ignore.is_none() {
|
||||||
m_custom_ignore =
|
m_custom_ignore =
|
||||||
ig.0.custom_ignore_matcher.matched(&path, is_dir)
|
ig.0.custom_ignore_matcher
|
||||||
.map(IgnoreMatch::gitignore);
|
.matched(&path, is_dir)
|
||||||
|
.map(IgnoreMatch::gitignore);
|
||||||
}
|
}
|
||||||
if m_ignore.is_none() {
|
if m_ignore.is_none() {
|
||||||
m_ignore =
|
m_ignore =
|
||||||
ig.0.ignore_matcher.matched(&path, is_dir)
|
ig.0.ignore_matcher
|
||||||
.map(IgnoreMatch::gitignore);
|
.matched(&path, is_dir)
|
||||||
|
.map(IgnoreMatch::gitignore);
|
||||||
}
|
}
|
||||||
if any_git && !saw_git && m_gi.is_none() {
|
if any_git && !saw_git && m_gi.is_none() {
|
||||||
m_gi =
|
m_gi =
|
||||||
ig.0.git_ignore_matcher.matched(&path, is_dir)
|
ig.0.git_ignore_matcher
|
||||||
.map(IgnoreMatch::gitignore);
|
.matched(&path, is_dir)
|
||||||
|
.map(IgnoreMatch::gitignore);
|
||||||
}
|
}
|
||||||
if any_git && !saw_git && m_gi_exclude.is_none() {
|
if any_git && !saw_git && m_gi_exclude.is_none() {
|
||||||
m_gi_exclude =
|
m_gi_exclude =
|
||||||
ig.0.git_exclude_matcher.matched(&path, is_dir)
|
ig.0.git_exclude_matcher
|
||||||
.map(IgnoreMatch::gitignore);
|
.matched(&path, is_dir)
|
||||||
|
.map(IgnoreMatch::gitignore);
|
||||||
}
|
}
|
||||||
saw_git = saw_git || ig.0.has_git;
|
saw_git = saw_git || ig.0.has_git;
|
||||||
}
|
}
|
||||||
@@ -435,20 +480,25 @@ impl Ignore {
|
|||||||
}
|
}
|
||||||
m_explicit = gi.matched(&path, is_dir).map(IgnoreMatch::gitignore);
|
m_explicit = gi.matched(&path, is_dir).map(IgnoreMatch::gitignore);
|
||||||
}
|
}
|
||||||
let m_global =
|
let m_global = if any_git {
|
||||||
if any_git {
|
self.0
|
||||||
self.0.git_global_matcher
|
.git_global_matcher
|
||||||
.matched(&path, is_dir)
|
.matched(&path, is_dir)
|
||||||
.map(IgnoreMatch::gitignore)
|
.map(IgnoreMatch::gitignore)
|
||||||
} else {
|
} else {
|
||||||
Match::None
|
Match::None
|
||||||
};
|
};
|
||||||
|
|
||||||
m_custom_ignore.or(m_ignore).or(m_gi).or(m_gi_exclude).or(m_global).or(m_explicit)
|
m_custom_ignore
|
||||||
|
.or(m_ignore)
|
||||||
|
.or(m_gi)
|
||||||
|
.or(m_gi_exclude)
|
||||||
|
.or(m_global)
|
||||||
|
.or(m_explicit)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over parent ignore matchers, including this one.
|
/// Returns an iterator over parent ignore matchers, including this one.
|
||||||
pub fn parents(&self) -> Parents {
|
pub fn parents(&self) -> Parents<'_> {
|
||||||
Parents(Some(self))
|
Parents(Some(self))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -515,6 +565,7 @@ impl IgnoreBuilder {
|
|||||||
git_ignore: true,
|
git_ignore: true,
|
||||||
git_exclude: true,
|
git_exclude: true,
|
||||||
ignore_case_insensitive: false,
|
ignore_case_insensitive: false,
|
||||||
|
require_git: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -524,20 +575,19 @@ impl IgnoreBuilder {
|
|||||||
/// The matcher returned won't match anything until ignore rules from
|
/// The matcher returned won't match anything until ignore rules from
|
||||||
/// directories are added to it.
|
/// directories are added to it.
|
||||||
pub fn build(&self) -> Ignore {
|
pub fn build(&self) -> Ignore {
|
||||||
let git_global_matcher =
|
let git_global_matcher = if !self.opts.git_global {
|
||||||
if !self.opts.git_global {
|
Gitignore::empty()
|
||||||
Gitignore::empty()
|
} else {
|
||||||
} else {
|
let mut builder = GitignoreBuilder::new("");
|
||||||
let mut builder = GitignoreBuilder::new("");
|
builder
|
||||||
builder
|
.case_insensitive(self.opts.ignore_case_insensitive)
|
||||||
.case_insensitive(self.opts.ignore_case_insensitive)
|
.unwrap();
|
||||||
.unwrap();
|
let (gi, err) = builder.build_global();
|
||||||
let (gi, err) = builder.build_global();
|
if let Some(err) = err {
|
||||||
if let Some(err) = err {
|
log::debug!("{}", err);
|
||||||
debug!("{}", err);
|
}
|
||||||
}
|
gi
|
||||||
gi
|
};
|
||||||
};
|
|
||||||
|
|
||||||
Ignore(Arc::new(IgnoreInner {
|
Ignore(Arc::new(IgnoreInner {
|
||||||
compiled: Arc::new(RwLock::new(HashMap::new())),
|
compiled: Arc::new(RwLock::new(HashMap::new())),
|
||||||
@@ -548,7 +598,9 @@ impl IgnoreBuilder {
|
|||||||
is_absolute_parent: true,
|
is_absolute_parent: true,
|
||||||
absolute_base: None,
|
absolute_base: None,
|
||||||
explicit_ignores: Arc::new(self.explicit_ignores.clone()),
|
explicit_ignores: Arc::new(self.explicit_ignores.clone()),
|
||||||
custom_ignore_filenames: Arc::new(self.custom_ignore_filenames.clone()),
|
custom_ignore_filenames: Arc::new(
|
||||||
|
self.custom_ignore_filenames.clone(),
|
||||||
|
),
|
||||||
custom_ignore_matcher: Gitignore::empty(),
|
custom_ignore_matcher: Gitignore::empty(),
|
||||||
ignore_matcher: Gitignore::empty(),
|
ignore_matcher: Gitignore::empty(),
|
||||||
git_global_matcher: Arc::new(git_global_matcher),
|
git_global_matcher: Arc::new(git_global_matcher),
|
||||||
@@ -593,7 +645,7 @@ impl IgnoreBuilder {
|
|||||||
/// later names.
|
/// later names.
|
||||||
pub fn add_custom_ignore_filename<S: AsRef<OsStr>>(
|
pub fn add_custom_ignore_filename<S: AsRef<OsStr>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
file_name: S
|
file_name: S,
|
||||||
) -> &mut IgnoreBuilder {
|
) -> &mut IgnoreBuilder {
|
||||||
self.custom_ignore_filenames.push(file_name.as_ref().to_os_string());
|
self.custom_ignore_filenames.push(file_name.as_ref().to_os_string());
|
||||||
self
|
self
|
||||||
@@ -664,6 +716,16 @@ impl IgnoreBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether a git repository is required to apply git-related ignore
|
||||||
|
/// rules (global rules, .gitignore and local exclude rules).
|
||||||
|
///
|
||||||
|
/// When disabled, git-related ignore rules are applied even when searching
|
||||||
|
/// outside a git repository.
|
||||||
|
pub fn require_git(&mut self, yes: bool) -> &mut IgnoreBuilder {
|
||||||
|
self.opts.require_git = yes;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Process ignore files case insensitively
|
/// Process ignore files case insensitively
|
||||||
///
|
///
|
||||||
/// This is disabled by default.
|
/// This is disabled by default.
|
||||||
@@ -678,12 +740,15 @@ impl IgnoreBuilder {
|
|||||||
|
|
||||||
/// Creates a new gitignore matcher for the directory given.
|
/// Creates a new gitignore matcher for the directory given.
|
||||||
///
|
///
|
||||||
/// Ignore globs are extracted from each of the file names in `dir` in the
|
/// The matcher is meant to match files below `dir`.
|
||||||
/// order given (earlier names have lower precedence than later names).
|
/// Ignore globs are extracted from each of the file names relative to
|
||||||
|
/// `dir_for_ignorefile` in the order given (earlier names have lower
|
||||||
|
/// precedence than later names).
|
||||||
///
|
///
|
||||||
/// I/O errors are ignored.
|
/// I/O errors are ignored.
|
||||||
pub fn create_gitignore<T: AsRef<OsStr>>(
|
pub fn create_gitignore<T: AsRef<OsStr>>(
|
||||||
dir: &Path,
|
dir: &Path,
|
||||||
|
dir_for_ignorefile: &Path,
|
||||||
names: &[T],
|
names: &[T],
|
||||||
case_insensitive: bool,
|
case_insensitive: bool,
|
||||||
) -> (Gitignore, Option<Error>) {
|
) -> (Gitignore, Option<Error>) {
|
||||||
@@ -691,8 +756,22 @@ pub fn create_gitignore<T: AsRef<OsStr>>(
|
|||||||
let mut errs = PartialErrorBuilder::default();
|
let mut errs = PartialErrorBuilder::default();
|
||||||
builder.case_insensitive(case_insensitive).unwrap();
|
builder.case_insensitive(case_insensitive).unwrap();
|
||||||
for name in names {
|
for name in names {
|
||||||
let gipath = dir.join(name.as_ref());
|
let gipath = dir_for_ignorefile.join(name.as_ref());
|
||||||
errs.maybe_push_ignore_io(builder.add(gipath));
|
// This check is not necessary, but is added for performance. Namely,
|
||||||
|
// a simple stat call checking for existence can often be just a bit
|
||||||
|
// quicker than actually trying to open a file. Since the number of
|
||||||
|
// directories without ignore files likely greatly exceeds the number
|
||||||
|
// with ignore files, this check generally makes sense.
|
||||||
|
//
|
||||||
|
// However, until demonstrated otherwise, we speculatively do not do
|
||||||
|
// this on Windows since Windows is notorious for having slow file
|
||||||
|
// system operations. Namely, it's not clear whether this analysis
|
||||||
|
// makes sense on Windows.
|
||||||
|
//
|
||||||
|
// For more details: https://github.com/BurntSushi/ripgrep/pull/1381
|
||||||
|
if cfg!(windows) || gipath.exists() {
|
||||||
|
errs.maybe_push_ignore_io(builder.add(gipath));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let gi = match builder.build() {
|
let gi = match builder.build() {
|
||||||
Ok(gi) => gi,
|
Ok(gi) => gi,
|
||||||
@@ -704,17 +783,70 @@ pub fn create_gitignore<T: AsRef<OsStr>>(
|
|||||||
(gi, errs.into_error_option())
|
(gi, errs.into_error_option())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Find the GIT_COMMON_DIR for the given git worktree.
|
||||||
|
///
|
||||||
|
/// This is the directory that may contain a private ignore file
|
||||||
|
/// "info/exclude". Unlike git, this function does *not* read environment
|
||||||
|
/// variables GIT_DIR and GIT_COMMON_DIR, because it is not clear how to use
|
||||||
|
/// them when multiple repositories are searched.
|
||||||
|
///
|
||||||
|
/// Some I/O errors are ignored.
|
||||||
|
fn resolve_git_commondir(
|
||||||
|
dir: &Path,
|
||||||
|
git_type: Option<FileType>,
|
||||||
|
) -> Result<PathBuf, Option<Error>> {
|
||||||
|
let git_dir_path = || dir.join(".git");
|
||||||
|
let git_dir = git_dir_path();
|
||||||
|
if !git_type.map_or(false, |ft| ft.is_file()) {
|
||||||
|
return Ok(git_dir);
|
||||||
|
}
|
||||||
|
let file = match File::open(git_dir) {
|
||||||
|
Ok(file) => io::BufReader::new(file),
|
||||||
|
Err(err) => {
|
||||||
|
return Err(Some(Error::Io(err).with_path(git_dir_path())));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let dot_git_line = match file.lines().next() {
|
||||||
|
Some(Ok(line)) => line,
|
||||||
|
Some(Err(err)) => {
|
||||||
|
return Err(Some(Error::Io(err).with_path(git_dir_path())));
|
||||||
|
}
|
||||||
|
None => return Err(None),
|
||||||
|
};
|
||||||
|
if !dot_git_line.starts_with("gitdir: ") {
|
||||||
|
return Err(None);
|
||||||
|
}
|
||||||
|
let real_git_dir = PathBuf::from(&dot_git_line["gitdir: ".len()..]);
|
||||||
|
let git_commondir_file = || real_git_dir.join("commondir");
|
||||||
|
let file = match File::open(git_commondir_file()) {
|
||||||
|
Ok(file) => io::BufReader::new(file),
|
||||||
|
Err(_) => return Err(None),
|
||||||
|
};
|
||||||
|
let commondir_line = match file.lines().next() {
|
||||||
|
Some(Ok(line)) => line,
|
||||||
|
Some(Err(err)) => {
|
||||||
|
return Err(Some(Error::Io(err).with_path(git_commondir_file())));
|
||||||
|
}
|
||||||
|
None => return Err(None),
|
||||||
|
};
|
||||||
|
let commondir_abs = if commondir_line.starts_with(".") {
|
||||||
|
real_git_dir.join(commondir_line) // relative commondir
|
||||||
|
} else {
|
||||||
|
PathBuf::from(commondir_line)
|
||||||
|
};
|
||||||
|
Ok(commondir_abs)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use tempfile::{self, TempDir};
|
use crate::dir::IgnoreBuilder;
|
||||||
|
use crate::gitignore::Gitignore;
|
||||||
use dir::IgnoreBuilder;
|
use crate::tests::TempDir;
|
||||||
use gitignore::Gitignore;
|
use crate::Error;
|
||||||
use Error;
|
|
||||||
|
|
||||||
fn wfile<P: AsRef<Path>>(path: P, contents: &str) {
|
fn wfile<P: AsRef<Path>>(path: P, contents: &str) {
|
||||||
let mut file = File::create(path).unwrap();
|
let mut file = File::create(path).unwrap();
|
||||||
@@ -732,19 +864,19 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tmpdir(prefix: &str) -> TempDir {
|
fn tmpdir() -> TempDir {
|
||||||
tempfile::Builder::new().prefix(prefix).tempdir().unwrap()
|
TempDir::new().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn explicit_ignore() {
|
fn explicit_ignore() {
|
||||||
let td = tmpdir("ignore-test-");
|
let td = tmpdir();
|
||||||
wfile(td.path().join("not-an-ignore"), "foo\n!bar");
|
wfile(td.path().join("not-an-ignore"), "foo\n!bar");
|
||||||
|
|
||||||
let (gi, err) = Gitignore::new(td.path().join("not-an-ignore"));
|
let (gi, err) = Gitignore::new(td.path().join("not-an-ignore"));
|
||||||
assert!(err.is_none());
|
assert!(err.is_none());
|
||||||
let (ig, err) = IgnoreBuilder::new()
|
let (ig, err) =
|
||||||
.add_ignore(gi).build().add_child(td.path());
|
IgnoreBuilder::new().add_ignore(gi).build().add_child(td.path());
|
||||||
assert!(err.is_none());
|
assert!(err.is_none());
|
||||||
assert!(ig.matched("foo", false).is_ignore());
|
assert!(ig.matched("foo", false).is_ignore());
|
||||||
assert!(ig.matched("bar", false).is_whitelist());
|
assert!(ig.matched("bar", false).is_whitelist());
|
||||||
@@ -753,7 +885,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn git_exclude() {
|
fn git_exclude() {
|
||||||
let td = tmpdir("ignore-test-");
|
let td = tmpdir();
|
||||||
mkdirp(td.path().join(".git/info"));
|
mkdirp(td.path().join(".git/info"));
|
||||||
wfile(td.path().join(".git/info/exclude"), "foo\n!bar");
|
wfile(td.path().join(".git/info/exclude"), "foo\n!bar");
|
||||||
|
|
||||||
@@ -766,7 +898,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn gitignore() {
|
fn gitignore() {
|
||||||
let td = tmpdir("ignore-test-");
|
let td = tmpdir();
|
||||||
mkdirp(td.path().join(".git"));
|
mkdirp(td.path().join(".git"));
|
||||||
wfile(td.path().join(".gitignore"), "foo\n!bar");
|
wfile(td.path().join(".gitignore"), "foo\n!bar");
|
||||||
|
|
||||||
@@ -779,7 +911,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn gitignore_no_git() {
|
fn gitignore_no_git() {
|
||||||
let td = tmpdir("ignore-test-");
|
let td = tmpdir();
|
||||||
wfile(td.path().join(".gitignore"), "foo\n!bar");
|
wfile(td.path().join(".gitignore"), "foo\n!bar");
|
||||||
|
|
||||||
let (ig, err) = IgnoreBuilder::new().build().add_child(td.path());
|
let (ig, err) = IgnoreBuilder::new().build().add_child(td.path());
|
||||||
@@ -789,9 +921,24 @@ mod tests {
|
|||||||
assert!(ig.matched("baz", false).is_none());
|
assert!(ig.matched("baz", false).is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gitignore_allowed_no_git() {
|
||||||
|
let td = tmpdir();
|
||||||
|
wfile(td.path().join(".gitignore"), "foo\n!bar");
|
||||||
|
|
||||||
|
let (ig, err) = IgnoreBuilder::new()
|
||||||
|
.require_git(false)
|
||||||
|
.build()
|
||||||
|
.add_child(td.path());
|
||||||
|
assert!(err.is_none());
|
||||||
|
assert!(ig.matched("foo", false).is_ignore());
|
||||||
|
assert!(ig.matched("bar", false).is_whitelist());
|
||||||
|
assert!(ig.matched("baz", false).is_none());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ignore() {
|
fn ignore() {
|
||||||
let td = tmpdir("ignore-test-");
|
let td = tmpdir();
|
||||||
wfile(td.path().join(".ignore"), "foo\n!bar");
|
wfile(td.path().join(".ignore"), "foo\n!bar");
|
||||||
|
|
||||||
let (ig, err) = IgnoreBuilder::new().build().add_child(td.path());
|
let (ig, err) = IgnoreBuilder::new().build().add_child(td.path());
|
||||||
@@ -803,13 +950,14 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn custom_ignore() {
|
fn custom_ignore() {
|
||||||
let td = tmpdir("ignore-test-");
|
let td = tmpdir();
|
||||||
let custom_ignore = ".customignore";
|
let custom_ignore = ".customignore";
|
||||||
wfile(td.path().join(custom_ignore), "foo\n!bar");
|
wfile(td.path().join(custom_ignore), "foo\n!bar");
|
||||||
|
|
||||||
let (ig, err) = IgnoreBuilder::new()
|
let (ig, err) = IgnoreBuilder::new()
|
||||||
.add_custom_ignore_filename(custom_ignore)
|
.add_custom_ignore_filename(custom_ignore)
|
||||||
.build().add_child(td.path());
|
.build()
|
||||||
|
.add_child(td.path());
|
||||||
assert!(err.is_none());
|
assert!(err.is_none());
|
||||||
assert!(ig.matched("foo", false).is_ignore());
|
assert!(ig.matched("foo", false).is_ignore());
|
||||||
assert!(ig.matched("bar", false).is_whitelist());
|
assert!(ig.matched("bar", false).is_whitelist());
|
||||||
@@ -819,14 +967,15 @@ mod tests {
|
|||||||
// Tests that a custom ignore file will override an .ignore.
|
// Tests that a custom ignore file will override an .ignore.
|
||||||
#[test]
|
#[test]
|
||||||
fn custom_ignore_over_ignore() {
|
fn custom_ignore_over_ignore() {
|
||||||
let td = tmpdir("ignore-test-");
|
let td = tmpdir();
|
||||||
let custom_ignore = ".customignore";
|
let custom_ignore = ".customignore";
|
||||||
wfile(td.path().join(".ignore"), "foo");
|
wfile(td.path().join(".ignore"), "foo");
|
||||||
wfile(td.path().join(custom_ignore), "!foo");
|
wfile(td.path().join(custom_ignore), "!foo");
|
||||||
|
|
||||||
let (ig, err) = IgnoreBuilder::new()
|
let (ig, err) = IgnoreBuilder::new()
|
||||||
.add_custom_ignore_filename(custom_ignore)
|
.add_custom_ignore_filename(custom_ignore)
|
||||||
.build().add_child(td.path());
|
.build()
|
||||||
|
.add_child(td.path());
|
||||||
assert!(err.is_none());
|
assert!(err.is_none());
|
||||||
assert!(ig.matched("foo", false).is_whitelist());
|
assert!(ig.matched("foo", false).is_whitelist());
|
||||||
}
|
}
|
||||||
@@ -834,7 +983,7 @@ mod tests {
|
|||||||
// Tests that earlier custom ignore files have lower precedence than later.
|
// Tests that earlier custom ignore files have lower precedence than later.
|
||||||
#[test]
|
#[test]
|
||||||
fn custom_ignore_precedence() {
|
fn custom_ignore_precedence() {
|
||||||
let td = tmpdir("ignore-test-");
|
let td = tmpdir();
|
||||||
let custom_ignore1 = ".customignore1";
|
let custom_ignore1 = ".customignore1";
|
||||||
let custom_ignore2 = ".customignore2";
|
let custom_ignore2 = ".customignore2";
|
||||||
wfile(td.path().join(custom_ignore1), "foo");
|
wfile(td.path().join(custom_ignore1), "foo");
|
||||||
@@ -843,7 +992,8 @@ mod tests {
|
|||||||
let (ig, err) = IgnoreBuilder::new()
|
let (ig, err) = IgnoreBuilder::new()
|
||||||
.add_custom_ignore_filename(custom_ignore1)
|
.add_custom_ignore_filename(custom_ignore1)
|
||||||
.add_custom_ignore_filename(custom_ignore2)
|
.add_custom_ignore_filename(custom_ignore2)
|
||||||
.build().add_child(td.path());
|
.build()
|
||||||
|
.add_child(td.path());
|
||||||
assert!(err.is_none());
|
assert!(err.is_none());
|
||||||
assert!(ig.matched("foo", false).is_whitelist());
|
assert!(ig.matched("foo", false).is_whitelist());
|
||||||
}
|
}
|
||||||
@@ -851,7 +1001,7 @@ mod tests {
|
|||||||
// Tests that an .ignore will override a .gitignore.
|
// Tests that an .ignore will override a .gitignore.
|
||||||
#[test]
|
#[test]
|
||||||
fn ignore_over_gitignore() {
|
fn ignore_over_gitignore() {
|
||||||
let td = tmpdir("ignore-test-");
|
let td = tmpdir();
|
||||||
wfile(td.path().join(".gitignore"), "foo");
|
wfile(td.path().join(".gitignore"), "foo");
|
||||||
wfile(td.path().join(".ignore"), "!foo");
|
wfile(td.path().join(".ignore"), "!foo");
|
||||||
|
|
||||||
@@ -863,7 +1013,7 @@ mod tests {
|
|||||||
// Tests that exclude has lower precedent than both .ignore and .gitignore.
|
// Tests that exclude has lower precedent than both .ignore and .gitignore.
|
||||||
#[test]
|
#[test]
|
||||||
fn exclude_lowest() {
|
fn exclude_lowest() {
|
||||||
let td = tmpdir("ignore-test-");
|
let td = tmpdir();
|
||||||
wfile(td.path().join(".gitignore"), "!foo");
|
wfile(td.path().join(".gitignore"), "!foo");
|
||||||
wfile(td.path().join(".ignore"), "!bar");
|
wfile(td.path().join(".ignore"), "!bar");
|
||||||
mkdirp(td.path().join(".git/info"));
|
mkdirp(td.path().join(".git/info"));
|
||||||
@@ -878,7 +1028,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn errored() {
|
fn errored() {
|
||||||
let td = tmpdir("ignore-test-");
|
let td = tmpdir();
|
||||||
wfile(td.path().join(".gitignore"), "{foo");
|
wfile(td.path().join(".gitignore"), "{foo");
|
||||||
|
|
||||||
let (_, err) = IgnoreBuilder::new().build().add_child(td.path());
|
let (_, err) = IgnoreBuilder::new().build().add_child(td.path());
|
||||||
@@ -887,7 +1037,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn errored_both() {
|
fn errored_both() {
|
||||||
let td = tmpdir("ignore-test-");
|
let td = tmpdir();
|
||||||
wfile(td.path().join(".gitignore"), "{foo");
|
wfile(td.path().join(".gitignore"), "{foo");
|
||||||
wfile(td.path().join(".ignore"), "{bar");
|
wfile(td.path().join(".ignore"), "{bar");
|
||||||
|
|
||||||
@@ -897,7 +1047,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn errored_partial() {
|
fn errored_partial() {
|
||||||
let td = tmpdir("ignore-test-");
|
let td = tmpdir();
|
||||||
mkdirp(td.path().join(".git"));
|
mkdirp(td.path().join(".git"));
|
||||||
wfile(td.path().join(".gitignore"), "{foo\nbar");
|
wfile(td.path().join(".gitignore"), "{foo\nbar");
|
||||||
|
|
||||||
@@ -908,7 +1058,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn errored_partial_and_ignore() {
|
fn errored_partial_and_ignore() {
|
||||||
let td = tmpdir("ignore-test-");
|
let td = tmpdir();
|
||||||
wfile(td.path().join(".gitignore"), "{foo\nbar");
|
wfile(td.path().join(".gitignore"), "{foo\nbar");
|
||||||
wfile(td.path().join(".ignore"), "!bar");
|
wfile(td.path().join(".ignore"), "!bar");
|
||||||
|
|
||||||
@@ -919,7 +1069,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn not_present_empty() {
|
fn not_present_empty() {
|
||||||
let td = tmpdir("ignore-test-");
|
let td = tmpdir();
|
||||||
|
|
||||||
let (_, err) = IgnoreBuilder::new().build().add_child(td.path());
|
let (_, err) = IgnoreBuilder::new().build().add_child(td.path());
|
||||||
assert!(err.is_none());
|
assert!(err.is_none());
|
||||||
@@ -929,7 +1079,7 @@ mod tests {
|
|||||||
fn stops_at_git_dir() {
|
fn stops_at_git_dir() {
|
||||||
// This tests that .gitignore files beyond a .git barrier aren't
|
// This tests that .gitignore files beyond a .git barrier aren't
|
||||||
// matched, but .ignore files are.
|
// matched, but .ignore files are.
|
||||||
let td = tmpdir("ignore-test-");
|
let td = tmpdir();
|
||||||
mkdirp(td.path().join(".git"));
|
mkdirp(td.path().join(".git"));
|
||||||
mkdirp(td.path().join("foo/.git"));
|
mkdirp(td.path().join("foo/.git"));
|
||||||
wfile(td.path().join(".gitignore"), "foo");
|
wfile(td.path().join(".gitignore"), "foo");
|
||||||
@@ -950,7 +1100,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn absolute_parent() {
|
fn absolute_parent() {
|
||||||
let td = tmpdir("ignore-test-");
|
let td = tmpdir();
|
||||||
mkdirp(td.path().join(".git"));
|
mkdirp(td.path().join(".git"));
|
||||||
mkdirp(td.path().join("foo"));
|
mkdirp(td.path().join("foo"));
|
||||||
wfile(td.path().join(".gitignore"), "bar");
|
wfile(td.path().join(".gitignore"), "bar");
|
||||||
@@ -973,7 +1123,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn absolute_parent_anchored() {
|
fn absolute_parent_anchored() {
|
||||||
let td = tmpdir("ignore-test-");
|
let td = tmpdir();
|
||||||
mkdirp(td.path().join(".git"));
|
mkdirp(td.path().join(".git"));
|
||||||
mkdirp(td.path().join("src/llvm"));
|
mkdirp(td.path().join("src/llvm"));
|
||||||
wfile(td.path().join(".gitignore"), "/llvm/\nfoo");
|
wfile(td.path().join(".gitignore"), "/llvm/\nfoo");
|
||||||
@@ -990,4 +1140,49 @@ mod tests {
|
|||||||
assert!(ig2.matched("foo", false).is_ignore());
|
assert!(ig2.matched("foo", false).is_ignore());
|
||||||
assert!(ig2.matched("src/foo", false).is_ignore());
|
assert!(ig2.matched("src/foo", false).is_ignore());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn git_info_exclude_in_linked_worktree() {
|
||||||
|
let td = tmpdir();
|
||||||
|
let git_dir = td.path().join(".git");
|
||||||
|
mkdirp(git_dir.join("info"));
|
||||||
|
wfile(git_dir.join("info/exclude"), "ignore_me");
|
||||||
|
mkdirp(git_dir.join("worktrees/linked-worktree"));
|
||||||
|
let commondir_path =
|
||||||
|
|| git_dir.join("worktrees/linked-worktree/commondir");
|
||||||
|
mkdirp(td.path().join("linked-worktree"));
|
||||||
|
let worktree_git_dir_abs = format!(
|
||||||
|
"gitdir: {}",
|
||||||
|
git_dir.join("worktrees/linked-worktree").to_str().unwrap(),
|
||||||
|
);
|
||||||
|
wfile(td.path().join("linked-worktree/.git"), &worktree_git_dir_abs);
|
||||||
|
|
||||||
|
// relative commondir
|
||||||
|
wfile(commondir_path(), "../..");
|
||||||
|
let ib = IgnoreBuilder::new().build();
|
||||||
|
let (ignore, err) = ib.add_child(td.path().join("linked-worktree"));
|
||||||
|
assert!(err.is_none());
|
||||||
|
assert!(ignore.matched("ignore_me", false).is_ignore());
|
||||||
|
|
||||||
|
// absolute commondir
|
||||||
|
wfile(commondir_path(), git_dir.to_str().unwrap());
|
||||||
|
let (ignore, err) = ib.add_child(td.path().join("linked-worktree"));
|
||||||
|
assert!(err.is_none());
|
||||||
|
assert!(ignore.matched("ignore_me", false).is_ignore());
|
||||||
|
|
||||||
|
// missing commondir file
|
||||||
|
assert!(fs::remove_file(commondir_path()).is_ok());
|
||||||
|
let (_, err) = ib.add_child(td.path().join("linked-worktree"));
|
||||||
|
// We squash the error in this case, because it occurs in repositories
|
||||||
|
// that are not linked worktrees but have submodules.
|
||||||
|
assert!(err.is_none());
|
||||||
|
|
||||||
|
wfile(td.path().join("linked-worktree/.git"), "garbage");
|
||||||
|
let (_, err) = ib.add_child(td.path().join("linked-worktree"));
|
||||||
|
assert!(err.is_none());
|
||||||
|
|
||||||
|
wfile(td.path().join("linked-worktree/.git"), "gitdir: garbage");
|
||||||
|
let (_, err) = ib.add_child(td.path().join("linked-worktree"));
|
||||||
|
assert!(err.is_none());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -19,8 +19,8 @@ use globset::{Candidate, GlobBuilder, GlobSet, GlobSetBuilder};
|
|||||||
use regex::bytes::Regex;
|
use regex::bytes::Regex;
|
||||||
use thread_local::ThreadLocal;
|
use thread_local::ThreadLocal;
|
||||||
|
|
||||||
use pathutil::{is_file_name, strip_prefix};
|
use crate::pathutil::{is_file_name, strip_prefix};
|
||||||
use {Error, Match, PartialErrorBuilder};
|
use crate::{Error, Match, PartialErrorBuilder};
|
||||||
|
|
||||||
/// Glob represents a single glob in a gitignore file.
|
/// Glob represents a single glob in a gitignore file.
|
||||||
///
|
///
|
||||||
@@ -249,7 +249,7 @@ impl Gitignore {
|
|||||||
return Match::None;
|
return Match::None;
|
||||||
}
|
}
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
let _matches = self.matches.as_ref().unwrap().get_default();
|
let _matches = self.matches.as_ref().unwrap().get_or_default();
|
||||||
let mut matches = _matches.borrow_mut();
|
let mut matches = _matches.borrow_mut();
|
||||||
let candidate = Candidate::new(path);
|
let candidate = Candidate::new(path);
|
||||||
self.set.matches_candidate_into(&candidate, &mut *matches);
|
self.set.matches_candidate_into(&candidate, &mut *matches);
|
||||||
@@ -332,13 +332,10 @@ impl GitignoreBuilder {
|
|||||||
pub fn build(&self) -> Result<Gitignore, Error> {
|
pub fn build(&self) -> Result<Gitignore, Error> {
|
||||||
let nignore = self.globs.iter().filter(|g| !g.is_whitelist()).count();
|
let nignore = self.globs.iter().filter(|g| !g.is_whitelist()).count();
|
||||||
let nwhite = self.globs.iter().filter(|g| g.is_whitelist()).count();
|
let nwhite = self.globs.iter().filter(|g| g.is_whitelist()).count();
|
||||||
let set =
|
let set = self
|
||||||
self.builder.build().map_err(|err| {
|
.builder
|
||||||
Error::Glob {
|
.build()
|
||||||
glob: None,
|
.map_err(|err| Error::Glob { glob: None, err: err.to_string() })?;
|
||||||
err: err.to_string(),
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
Ok(Gitignore {
|
Ok(Gitignore {
|
||||||
set: set,
|
set: set,
|
||||||
root: self.root.clone(),
|
root: self.root.clone(),
|
||||||
@@ -477,10 +474,13 @@ impl GitignoreBuilder {
|
|||||||
}
|
}
|
||||||
// If it ends with a slash, then this should only match directories,
|
// If it ends with a slash, then this should only match directories,
|
||||||
// but the slash should otherwise not be used while globbing.
|
// but the slash should otherwise not be used while globbing.
|
||||||
if let Some((i, c)) = line.char_indices().rev().nth(0) {
|
if line.as_bytes().last() == Some(&b'/') {
|
||||||
if c == '/' {
|
glob.is_only_dir = true;
|
||||||
glob.is_only_dir = true;
|
line = &line[..line.len() - 1];
|
||||||
line = &line[..i];
|
// If the slash was escaped, then remove the escape.
|
||||||
|
// See: https://github.com/BurntSushi/ripgrep/issues/2236
|
||||||
|
if line.as_bytes().last() == Some(&b'\\') {
|
||||||
|
line = &line[..line.len() - 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
glob.actual = line.to_string();
|
glob.actual = line.to_string();
|
||||||
@@ -499,18 +499,15 @@ impl GitignoreBuilder {
|
|||||||
if glob.actual.ends_with("/**") {
|
if glob.actual.ends_with("/**") {
|
||||||
glob.actual = format!("{}/*", glob.actual);
|
glob.actual = format!("{}/*", glob.actual);
|
||||||
}
|
}
|
||||||
let parsed =
|
let parsed = GlobBuilder::new(&glob.actual)
|
||||||
GlobBuilder::new(&glob.actual)
|
.literal_separator(true)
|
||||||
.literal_separator(true)
|
.case_insensitive(self.case_insensitive)
|
||||||
.case_insensitive(self.case_insensitive)
|
.backslash_escape(true)
|
||||||
.backslash_escape(true)
|
.build()
|
||||||
.build()
|
.map_err(|err| Error::Glob {
|
||||||
.map_err(|err| {
|
glob: Some(glob.original.clone()),
|
||||||
Error::Glob {
|
err: err.kind().to_string(),
|
||||||
glob: Some(glob.original.clone()),
|
})?;
|
||||||
err: err.kind().to_string(),
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
self.builder.add(parsed);
|
self.builder.add(parsed);
|
||||||
self.globs.push(glob);
|
self.globs.push(glob);
|
||||||
Ok(self)
|
Ok(self)
|
||||||
@@ -537,7 +534,7 @@ impl GitignoreBuilder {
|
|||||||
///
|
///
|
||||||
/// Note that the file path returned may not exist.
|
/// Note that the file path returned may not exist.
|
||||||
fn gitconfig_excludes_path() -> Option<PathBuf> {
|
fn gitconfig_excludes_path() -> Option<PathBuf> {
|
||||||
// git supports $HOME/.gitconfig and $XDG_CONFIG_DIR/git/config. Notably,
|
// git supports $HOME/.gitconfig and $XDG_CONFIG_HOME/git/config. Notably,
|
||||||
// both can be active at the same time, where $HOME/.gitconfig takes
|
// both can be active at the same time, where $HOME/.gitconfig takes
|
||||||
// precedent. So if $HOME/.gitconfig defines a `core.excludesFile`, then
|
// precedent. So if $HOME/.gitconfig defines a `core.excludesFile`, then
|
||||||
// we're done.
|
// we're done.
|
||||||
@@ -568,7 +565,7 @@ fn gitconfig_home_contents() -> Option<Vec<u8>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the file contents of git's global config file, if one exists, in
|
/// Returns the file contents of git's global config file, if one exists, in
|
||||||
/// the user's XDG_CONFIG_DIR directory.
|
/// the user's XDG_CONFIG_HOME directory.
|
||||||
fn gitconfig_xdg_contents() -> Option<Vec<u8>> {
|
fn gitconfig_xdg_contents() -> Option<Vec<u8>> {
|
||||||
let path = env::var_os("XDG_CONFIG_HOME")
|
let path = env::var_os("XDG_CONFIG_HOME")
|
||||||
.and_then(|x| if x.is_empty() { None } else { Some(PathBuf::from(x)) })
|
.and_then(|x| if x.is_empty() { None } else { Some(PathBuf::from(x)) })
|
||||||
@@ -598,10 +595,9 @@ fn parse_excludes_file(data: &[u8]) -> Option<PathBuf> {
|
|||||||
// N.B. This is the lazy approach, and isn't technically correct, but
|
// N.B. This is the lazy approach, and isn't technically correct, but
|
||||||
// probably works in more circumstances. I guess we would ideally have
|
// probably works in more circumstances. I guess we would ideally have
|
||||||
// a full INI parser. Yuck.
|
// a full INI parser. Yuck.
|
||||||
lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref RE: Regex = Regex::new(
|
static ref RE: Regex =
|
||||||
r"(?im)^\s*excludesfile\s*=\s*(.+)\s*$"
|
Regex::new(r"(?im)^\s*excludesfile\s*=\s*(.+)\s*$").unwrap();
|
||||||
).unwrap();
|
|
||||||
};
|
};
|
||||||
let caps = match RE.captures(data) {
|
let caps = match RE.captures(data) {
|
||||||
None => return None,
|
None => return None,
|
||||||
@@ -630,8 +626,8 @@ fn home_dir() -> Option<PathBuf> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::path::Path;
|
|
||||||
use super::{Gitignore, GitignoreBuilder};
|
use super::{Gitignore, GitignoreBuilder};
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
fn gi_from_str<P: AsRef<Path>>(root: P, s: &str) -> Gitignore {
|
fn gi_from_str<P: AsRef<Path>>(root: P, s: &str) -> Gitignore {
|
||||||
let mut builder = GitignoreBuilder::new(root);
|
let mut builder = GitignoreBuilder::new(root);
|
||||||
@@ -726,8 +722,11 @@ mod tests {
|
|||||||
not_ignored!(ignot12, ROOT, "\n\n\n", "foo");
|
not_ignored!(ignot12, ROOT, "\n\n\n", "foo");
|
||||||
not_ignored!(ignot13, ROOT, "foo/**", "foo", true);
|
not_ignored!(ignot13, ROOT, "foo/**", "foo", true);
|
||||||
not_ignored!(
|
not_ignored!(
|
||||||
ignot14, "./third_party/protobuf", "m4/ltoptions.m4",
|
ignot14,
|
||||||
"./third_party/protobuf/csharp/src/packages/repositories.config");
|
"./third_party/protobuf",
|
||||||
|
"m4/ltoptions.m4",
|
||||||
|
"./third_party/protobuf/csharp/src/packages/repositories.config"
|
||||||
|
);
|
||||||
not_ignored!(ignot15, ROOT, "!/bar", "foo/bar");
|
not_ignored!(ignot15, ROOT, "!/bar", "foo/bar");
|
||||||
not_ignored!(ignot16, ROOT, "*\n!**/", "foo", true);
|
not_ignored!(ignot16, ROOT, "*\n!**/", "foo", true);
|
||||||
not_ignored!(ignot17, ROOT, "src/*.rs", "src/grep/src/main.rs");
|
not_ignored!(ignot17, ROOT, "src/*.rs", "src/grep/src/main.rs");
|
||||||
@@ -771,9 +770,12 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn case_insensitive() {
|
fn case_insensitive() {
|
||||||
let gi = GitignoreBuilder::new(ROOT)
|
let gi = GitignoreBuilder::new(ROOT)
|
||||||
.case_insensitive(true).unwrap()
|
.case_insensitive(true)
|
||||||
.add_str(None, "*.html").unwrap()
|
.unwrap()
|
||||||
.build().unwrap();
|
.add_str(None, "*.html")
|
||||||
|
.unwrap()
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
assert!(gi.matched("foo.html", false).is_ignore());
|
assert!(gi.matched("foo.html", false).is_ignore());
|
||||||
assert!(gi.matched("foo.HTML", false).is_ignore());
|
assert!(gi.matched("foo.HTML", false).is_ignore());
|
||||||
assert!(!gi.matched("foo.htm", false).is_ignore());
|
assert!(!gi.matched("foo.htm", false).is_ignore());
|
||||||
@@ -46,33 +46,21 @@ See the documentation for `WalkBuilder` for many other options.
|
|||||||
|
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
extern crate crossbeam_channel as channel;
|
|
||||||
extern crate globset;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate lazy_static;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate log;
|
|
||||||
extern crate memchr;
|
|
||||||
extern crate regex;
|
|
||||||
extern crate same_file;
|
|
||||||
#[cfg(test)]
|
|
||||||
extern crate tempfile;
|
|
||||||
extern crate thread_local;
|
|
||||||
extern crate walkdir;
|
|
||||||
#[cfg(windows)]
|
|
||||||
extern crate winapi_util;
|
|
||||||
|
|
||||||
use std::error;
|
use std::error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
pub use walk::{DirEntry, Walk, WalkBuilder, WalkParallel, WalkState};
|
pub use crate::walk::{
|
||||||
|
DirEntry, ParallelVisitor, ParallelVisitorBuilder, Walk, WalkBuilder,
|
||||||
|
WalkParallel, WalkState,
|
||||||
|
};
|
||||||
|
|
||||||
|
mod default_types;
|
||||||
mod dir;
|
mod dir;
|
||||||
pub mod gitignore;
|
pub mod gitignore;
|
||||||
mod pathutil;
|
|
||||||
pub mod overrides;
|
pub mod overrides;
|
||||||
|
mod pathutil;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
mod walk;
|
mod walk;
|
||||||
|
|
||||||
@@ -145,20 +133,14 @@ impl Clone for Error {
|
|||||||
Error::WithDepth { depth, ref err } => {
|
Error::WithDepth { depth, ref err } => {
|
||||||
Error::WithDepth { depth: depth, err: err.clone() }
|
Error::WithDepth { depth: depth, err: err.clone() }
|
||||||
}
|
}
|
||||||
Error::Loop { ref ancestor, ref child } => {
|
Error::Loop { ref ancestor, ref child } => Error::Loop {
|
||||||
Error::Loop {
|
ancestor: ancestor.clone(),
|
||||||
ancestor: ancestor.clone(),
|
child: child.clone(),
|
||||||
child: child.clone()
|
},
|
||||||
}
|
Error::Io(ref err) => match err.raw_os_error() {
|
||||||
}
|
Some(e) => Error::Io(io::Error::from_raw_os_error(e)),
|
||||||
Error::Io(ref err) => {
|
None => Error::Io(io::Error::new(err.kind(), err.to_string())),
|
||||||
match err.raw_os_error() {
|
},
|
||||||
Some(e) => Error::Io(io::Error::from_raw_os_error(e)),
|
|
||||||
None => {
|
|
||||||
Error::Io(io::Error::new(err.kind(), err.to_string()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Error::Glob { ref glob, ref err } => {
|
Error::Glob { ref glob, ref err } => {
|
||||||
Error::Glob { glob: glob.clone(), err: err.clone() }
|
Error::Glob { glob: glob.clone(), err: err.clone() }
|
||||||
}
|
}
|
||||||
@@ -201,6 +183,71 @@ impl Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Inspect the original [`io::Error`] if there is one.
|
||||||
|
///
|
||||||
|
/// [`None`] is returned if the [`Error`] doesn't correspond to an
|
||||||
|
/// [`io::Error`]. This might happen, for example, when the error was
|
||||||
|
/// produced because a cycle was found in the directory tree while
|
||||||
|
/// following symbolic links.
|
||||||
|
///
|
||||||
|
/// This method returns a borrowed value that is bound to the lifetime of the [`Error`]. To
|
||||||
|
/// obtain an owned value, the [`into_io_error`] can be used instead.
|
||||||
|
///
|
||||||
|
/// > This is the original [`io::Error`] and is _not_ the same as
|
||||||
|
/// > [`impl From<Error> for std::io::Error`][impl] which contains additional context about the
|
||||||
|
/// error.
|
||||||
|
///
|
||||||
|
/// [`None`]: https://doc.rust-lang.org/stable/std/option/enum.Option.html#variant.None
|
||||||
|
/// [`io::Error`]: https://doc.rust-lang.org/stable/std/io/struct.Error.html
|
||||||
|
/// [`From`]: https://doc.rust-lang.org/stable/std/convert/trait.From.html
|
||||||
|
/// [`Error`]: struct.Error.html
|
||||||
|
/// [`into_io_error`]: struct.Error.html#method.into_io_error
|
||||||
|
/// [impl]: struct.Error.html#impl-From%3CError%3E
|
||||||
|
pub fn io_error(&self) -> Option<&std::io::Error> {
|
||||||
|
match *self {
|
||||||
|
Error::Partial(ref errs) => {
|
||||||
|
if errs.len() == 1 {
|
||||||
|
errs[0].io_error()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Error::WithLineNumber { ref err, .. } => err.io_error(),
|
||||||
|
Error::WithPath { ref err, .. } => err.io_error(),
|
||||||
|
Error::WithDepth { ref err, .. } => err.io_error(),
|
||||||
|
Error::Loop { .. } => None,
|
||||||
|
Error::Io(ref err) => Some(err),
|
||||||
|
Error::Glob { .. } => None,
|
||||||
|
Error::UnrecognizedFileType(_) => None,
|
||||||
|
Error::InvalidDefinition => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Similar to [`io_error`] except consumes self to convert to the original
|
||||||
|
/// [`io::Error`] if one exists.
|
||||||
|
///
|
||||||
|
/// [`io_error`]: struct.Error.html#method.io_error
|
||||||
|
/// [`io::Error`]: https://doc.rust-lang.org/stable/std/io/struct.Error.html
|
||||||
|
pub fn into_io_error(self) -> Option<std::io::Error> {
|
||||||
|
match self {
|
||||||
|
Error::Partial(mut errs) => {
|
||||||
|
if errs.len() == 1 {
|
||||||
|
errs.remove(0).into_io_error()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Error::WithLineNumber { err, .. } => err.into_io_error(),
|
||||||
|
Error::WithPath { err, .. } => err.into_io_error(),
|
||||||
|
Error::WithDepth { err, .. } => err.into_io_error(),
|
||||||
|
Error::Loop { .. } => None,
|
||||||
|
Error::Io(err) => Some(err),
|
||||||
|
Error::Glob { .. } => None,
|
||||||
|
Error::UnrecognizedFileType(_) => None,
|
||||||
|
Error::InvalidDefinition => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a depth associated with recursively walking a directory (if
|
/// Returns a depth associated with recursively walking a directory (if
|
||||||
/// this error was generated from a recursive directory iterator).
|
/// this error was generated from a recursive directory iterator).
|
||||||
pub fn depth(&self) -> Option<usize> {
|
pub fn depth(&self) -> Option<usize> {
|
||||||
@@ -221,19 +268,14 @@ impl Error {
|
|||||||
|
|
||||||
/// Turn an error into a tagged error with the given depth.
|
/// Turn an error into a tagged error with the given depth.
|
||||||
fn with_depth(self, depth: usize) -> Error {
|
fn with_depth(self, depth: usize) -> Error {
|
||||||
Error::WithDepth {
|
Error::WithDepth { depth: depth, err: Box::new(self) }
|
||||||
depth: depth,
|
|
||||||
err: Box::new(self),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Turn an error into a tagged error with the given file path and line
|
/// Turn an error into a tagged error with the given file path and line
|
||||||
/// number. If path is empty, then it is omitted from the error.
|
/// number. If path is empty, then it is omitted from the error.
|
||||||
fn tagged<P: AsRef<Path>>(self, path: P, lineno: u64) -> Error {
|
fn tagged<P: AsRef<Path>>(self, path: P, lineno: u64) -> Error {
|
||||||
let errline = Error::WithLineNumber {
|
let errline =
|
||||||
line: lineno,
|
Error::WithLineNumber { line: lineno, err: Box::new(self) };
|
||||||
err: Box::new(self),
|
|
||||||
};
|
|
||||||
if path.as_ref().as_os_str().is_empty() {
|
if path.as_ref().as_os_str().is_empty() {
|
||||||
return errline;
|
return errline;
|
||||||
}
|
}
|
||||||
@@ -255,16 +297,14 @@ impl Error {
|
|||||||
let path = err.path().map(|p| p.to_path_buf());
|
let path = err.path().map(|p| p.to_path_buf());
|
||||||
let mut ig_err = Error::Io(io::Error::from(err));
|
let mut ig_err = Error::Io(io::Error::from(err));
|
||||||
if let Some(path) = path {
|
if let Some(path) = path {
|
||||||
ig_err = Error::WithPath {
|
ig_err = Error::WithPath { path: path, err: Box::new(ig_err) };
|
||||||
path: path,
|
|
||||||
err: Box::new(ig_err),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
ig_err
|
ig_err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl error::Error for Error {
|
impl error::Error for Error {
|
||||||
|
#[allow(deprecated)]
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
match *self {
|
match *self {
|
||||||
Error::Partial(_) => "partial error",
|
Error::Partial(_) => "partial error",
|
||||||
@@ -281,7 +321,7 @@ impl error::Error for Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Error::Partial(ref errs) => {
|
Error::Partial(ref errs) => {
|
||||||
let msgs: Vec<String> =
|
let msgs: Vec<String> =
|
||||||
@@ -295,11 +335,13 @@ impl fmt::Display for Error {
|
|||||||
write!(f, "{}: {}", path.display(), err)
|
write!(f, "{}: {}", path.display(), err)
|
||||||
}
|
}
|
||||||
Error::WithDepth { ref err, .. } => err.fmt(f),
|
Error::WithDepth { ref err, .. } => err.fmt(f),
|
||||||
Error::Loop { ref ancestor, ref child } => {
|
Error::Loop { ref ancestor, ref child } => write!(
|
||||||
write!(f, "File system loop found: \
|
f,
|
||||||
|
"File system loop found: \
|
||||||
{} points to an ancestor {}",
|
{} points to an ancestor {}",
|
||||||
child.display(), ancestor.display())
|
child.display(),
|
||||||
}
|
ancestor.display()
|
||||||
|
),
|
||||||
Error::Io(ref err) => err.fmt(f),
|
Error::Io(ref err) => err.fmt(f),
|
||||||
Error::Glob { glob: None, ref err } => write!(f, "{}", err),
|
Error::Glob { glob: None, ref err } => write!(f, "{}", err),
|
||||||
Error::Glob { glob: Some(ref glob), ref err } => {
|
Error::Glob { glob: Some(ref glob), ref err } => {
|
||||||
@@ -308,10 +350,11 @@ impl fmt::Display for Error {
|
|||||||
Error::UnrecognizedFileType(ref ty) => {
|
Error::UnrecognizedFileType(ref ty) => {
|
||||||
write!(f, "unrecognized file type: {}", ty)
|
write!(f, "unrecognized file type: {}", ty)
|
||||||
}
|
}
|
||||||
Error::InvalidDefinition => {
|
Error::InvalidDefinition => write!(
|
||||||
write!(f, "invalid definition (format is type:glob, e.g., \
|
f,
|
||||||
html:*.html)")
|
"invalid definition (format is type:glob, e.g., \
|
||||||
}
|
html:*.html)"
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -442,3 +485,66 @@ impl<T> Match<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::env;
|
||||||
|
use std::error;
|
||||||
|
use std::fs;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::result;
|
||||||
|
|
||||||
|
/// A convenient result type alias.
|
||||||
|
pub type Result<T> =
|
||||||
|
result::Result<T, Box<dyn error::Error + Send + Sync>>;
|
||||||
|
|
||||||
|
macro_rules! err {
|
||||||
|
($($tt:tt)*) => {
|
||||||
|
Box::<dyn error::Error + Send + Sync>::from(format!($($tt)*))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A simple wrapper for creating a temporary directory that is
|
||||||
|
/// automatically deleted when it's dropped.
|
||||||
|
///
|
||||||
|
/// We use this in lieu of tempfile because tempfile brings in too many
|
||||||
|
/// dependencies.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TempDir(PathBuf);
|
||||||
|
|
||||||
|
impl Drop for TempDir {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
fs::remove_dir_all(&self.0).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TempDir {
|
||||||
|
/// Create a new empty temporary directory under the system's configured
|
||||||
|
/// temporary directory.
|
||||||
|
pub fn new() -> Result<TempDir> {
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
|
static TRIES: usize = 100;
|
||||||
|
static COUNTER: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
|
let tmpdir = env::temp_dir();
|
||||||
|
for _ in 0..TRIES {
|
||||||
|
let count = COUNTER.fetch_add(1, Ordering::SeqCst);
|
||||||
|
let path = tmpdir.join("rust-ignore").join(count.to_string());
|
||||||
|
if path.is_dir() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fs::create_dir_all(&path).map_err(|e| {
|
||||||
|
err!("failed to create {}: {}", path.display(), e)
|
||||||
|
})?;
|
||||||
|
return Ok(TempDir(path));
|
||||||
|
}
|
||||||
|
Err(err!("failed to create temp dir after {} tries", TRIES))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the underlying path to this temporary directory.
|
||||||
|
pub fn path(&self) -> &Path {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,8 +6,8 @@ line tools.
|
|||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use gitignore::{self, Gitignore, GitignoreBuilder};
|
use crate::gitignore::{self, Gitignore, GitignoreBuilder};
|
||||||
use {Error, Match};
|
use crate::{Error, Match};
|
||||||
|
|
||||||
/// Glob represents a single glob in an override matcher.
|
/// Glob represents a single glob in an override matcher.
|
||||||
///
|
///
|
||||||
@@ -115,9 +115,7 @@ impl OverrideBuilder {
|
|||||||
///
|
///
|
||||||
/// Matching is done relative to the directory path provided.
|
/// Matching is done relative to the directory path provided.
|
||||||
pub fn new<P: AsRef<Path>>(path: P) -> OverrideBuilder {
|
pub fn new<P: AsRef<Path>>(path: P) -> OverrideBuilder {
|
||||||
OverrideBuilder {
|
OverrideBuilder { builder: GitignoreBuilder::new(path) }
|
||||||
builder: GitignoreBuilder::new(path),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a new override matcher from the globs added so far.
|
/// Builds a new override matcher from the globs added so far.
|
||||||
@@ -240,9 +238,12 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn case_insensitive() {
|
fn case_insensitive() {
|
||||||
let ov = OverrideBuilder::new(ROOT)
|
let ov = OverrideBuilder::new(ROOT)
|
||||||
.case_insensitive(true).unwrap()
|
.case_insensitive(true)
|
||||||
.add("*.html").unwrap()
|
.unwrap()
|
||||||
.build().unwrap();
|
.add("*.html")
|
||||||
|
.unwrap()
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
assert!(ov.matched("foo.html", false).is_whitelist());
|
assert!(ov.matched("foo.html", false).is_whitelist());
|
||||||
assert!(ov.matched("foo.HTML", false).is_whitelist());
|
assert!(ov.matched("foo.HTML", false).is_whitelist());
|
||||||
assert!(ov.matched("foo.htm", false).is_ignore());
|
assert!(ov.matched("foo.htm", false).is_ignore());
|
||||||
@@ -251,9 +252,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn default_case_sensitive() {
|
fn default_case_sensitive() {
|
||||||
let ov = OverrideBuilder::new(ROOT)
|
let ov =
|
||||||
.add("*.html").unwrap()
|
OverrideBuilder::new(ROOT).add("*.html").unwrap().build().unwrap();
|
||||||
.build().unwrap();
|
|
||||||
assert!(ov.matched("foo.html", false).is_whitelist());
|
assert!(ov.matched("foo.html", false).is_whitelist());
|
||||||
assert!(ov.matched("foo.HTML", false).is_ignore());
|
assert!(ov.matched("foo.HTML", false).is_ignore());
|
||||||
assert!(ov.matched("foo.htm", false).is_ignore());
|
assert!(ov.matched("foo.htm", false).is_ignore());
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use walk::DirEntry;
|
use crate::walk::DirEntry;
|
||||||
|
|
||||||
/// Returns true if and only if this entry is considered to be hidden.
|
/// Returns true if and only if this entry is considered to be hidden.
|
||||||
///
|
///
|
||||||
@@ -91,8 +91,8 @@ pub fn strip_prefix<'a, P: AsRef<Path> + ?Sized>(
|
|||||||
/// the empty string.
|
/// the empty string.
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub fn is_file_name<P: AsRef<Path>>(path: P) -> bool {
|
pub fn is_file_name<P: AsRef<Path>>(path: P) -> bool {
|
||||||
use std::os::unix::ffi::OsStrExt;
|
|
||||||
use memchr::memchr;
|
use memchr::memchr;
|
||||||
|
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();
|
||||||
memchr(b'/', path).is_none()
|
memchr(b'/', path).is_none()
|
||||||
@@ -113,8 +113,8 @@ pub fn is_file_name<P: AsRef<Path>>(path: P) -> bool {
|
|||||||
pub fn file_name<'a, P: AsRef<Path> + ?Sized>(
|
pub fn file_name<'a, P: AsRef<Path> + ?Sized>(
|
||||||
path: &'a P,
|
path: &'a P,
|
||||||
) -> Option<&'a OsStr> {
|
) -> Option<&'a OsStr> {
|
||||||
use std::os::unix::ffi::OsStrExt;
|
|
||||||
use memchr::memrchr;
|
use memchr::memrchr;
|
||||||
|
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();
|
||||||
if path.is_empty() {
|
if path.is_empty() {
|
||||||
@@ -93,232 +93,9 @@ use globset::{GlobBuilder, GlobSet, GlobSetBuilder};
|
|||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use thread_local::ThreadLocal;
|
use thread_local::ThreadLocal;
|
||||||
|
|
||||||
use pathutil::file_name;
|
use crate::default_types::DEFAULT_TYPES;
|
||||||
use {Error, Match};
|
use crate::pathutil::file_name;
|
||||||
|
use crate::{Error, Match};
|
||||||
const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
|
|
||||||
("agda", &["*.agda", "*.lagda"]),
|
|
||||||
("ats", &["*.ats", "*.dats", "*.sats", "*.hats"]),
|
|
||||||
("aidl", &["*.aidl"]),
|
|
||||||
("amake", &["*.mk", "*.bp"]),
|
|
||||||
("asciidoc", &["*.adoc", "*.asc", "*.asciidoc"]),
|
|
||||||
("asm", &["*.asm", "*.s", "*.S"]),
|
|
||||||
("asp", &["*.aspx", "*.aspx.cs", "*.aspx.cs", "*.ascx", "*.ascx.cs", "*.ascx.vb"]),
|
|
||||||
("avro", &["*.avdl", "*.avpr", "*.avsc"]),
|
|
||||||
("awk", &["*.awk"]),
|
|
||||||
("bazel", &["*.bzl", "WORKSPACE", "BUILD", "BUILD.bazel"]),
|
|
||||||
("bitbake", &["*.bb", "*.bbappend", "*.bbclass", "*.conf", "*.inc"]),
|
|
||||||
("brotli", &["*.br"]),
|
|
||||||
("buildstream", &["*.bst"]),
|
|
||||||
("bzip2", &["*.bz2", "*.tbz2"]),
|
|
||||||
("c", &["*.[chH]", "*.[chH].in", "*.cats"]),
|
|
||||||
("cabal", &["*.cabal"]),
|
|
||||||
("cbor", &["*.cbor"]),
|
|
||||||
("ceylon", &["*.ceylon"]),
|
|
||||||
("clojure", &["*.clj", "*.cljc", "*.cljs", "*.cljx"]),
|
|
||||||
("cmake", &["*.cmake", "CMakeLists.txt"]),
|
|
||||||
("coffeescript", &["*.coffee"]),
|
|
||||||
("creole", &["*.creole"]),
|
|
||||||
("config", &["*.cfg", "*.conf", "*.config", "*.ini"]),
|
|
||||||
("cpp", &[
|
|
||||||
"*.[ChH]", "*.cc", "*.[ch]pp", "*.[ch]xx", "*.hh", "*.inl",
|
|
||||||
"*.[ChH].in", "*.cc.in", "*.[ch]pp.in", "*.[ch]xx.in", "*.hh.in",
|
|
||||||
]),
|
|
||||||
("crystal", &["Projectfile", "*.cr"]),
|
|
||||||
("cs", &["*.cs"]),
|
|
||||||
("csharp", &["*.cs"]),
|
|
||||||
("cshtml", &["*.cshtml"]),
|
|
||||||
("css", &["*.css", "*.scss"]),
|
|
||||||
("csv", &["*.csv"]),
|
|
||||||
("cython", &["*.pyx", "*.pxi", "*.pxd"]),
|
|
||||||
("dart", &["*.dart"]),
|
|
||||||
("d", &["*.d"]),
|
|
||||||
("dhall", &["*.dhall"]),
|
|
||||||
("docker", &["*Dockerfile*"]),
|
|
||||||
("elisp", &["*.el"]),
|
|
||||||
("elixir", &["*.ex", "*.eex", "*.exs"]),
|
|
||||||
("elm", &["*.elm"]),
|
|
||||||
("erlang", &["*.erl", "*.hrl"]),
|
|
||||||
("fidl", &["*.fidl"]),
|
|
||||||
("fish", &["*.fish"]),
|
|
||||||
("fortran", &[
|
|
||||||
"*.f", "*.F", "*.f77", "*.F77", "*.pfo",
|
|
||||||
"*.f90", "*.F90", "*.f95", "*.F95",
|
|
||||||
]),
|
|
||||||
("fsharp", &["*.fs", "*.fsx", "*.fsi"]),
|
|
||||||
("gn", &["*.gn", "*.gni"]),
|
|
||||||
("go", &["*.go"]),
|
|
||||||
("gzip", &["*.gz", "*.tgz"]),
|
|
||||||
("groovy", &["*.groovy", "*.gradle"]),
|
|
||||||
("h", &["*.h", "*.hpp"]),
|
|
||||||
("hbs", &["*.hbs"]),
|
|
||||||
("haskell", &["*.hs", "*.lhs", "*.cpphs", "*.c2hs", "*.hsc"]),
|
|
||||||
("hs", &["*.hs", "*.lhs"]),
|
|
||||||
("html", &["*.htm", "*.html", "*.ejs"]),
|
|
||||||
("idris", &["*.idr", "*.lidr"]),
|
|
||||||
("java", &["*.java", "*.jsp", "*.jspx", "*.properties"]),
|
|
||||||
("jinja", &["*.j2", "*.jinja", "*.jinja2"]),
|
|
||||||
("js", &[
|
|
||||||
"*.js", "*.jsx", "*.vue",
|
|
||||||
]),
|
|
||||||
("json", &["*.json", "composer.lock"]),
|
|
||||||
("jsonl", &["*.jsonl"]),
|
|
||||||
("julia", &["*.jl"]),
|
|
||||||
("jupyter", &["*.ipynb", "*.jpynb"]),
|
|
||||||
("jl", &["*.jl"]),
|
|
||||||
("kotlin", &["*.kt", "*.kts"]),
|
|
||||||
("less", &["*.less"]),
|
|
||||||
("license", &[
|
|
||||||
// General
|
|
||||||
"COPYING", "COPYING[.-]*",
|
|
||||||
"COPYRIGHT", "COPYRIGHT[.-]*",
|
|
||||||
"EULA", "EULA[.-]*",
|
|
||||||
"licen[cs]e", "licen[cs]e.*",
|
|
||||||
"LICEN[CS]E", "LICEN[CS]E[.-]*", "*[.-]LICEN[CS]E*",
|
|
||||||
"NOTICE", "NOTICE[.-]*",
|
|
||||||
"PATENTS", "PATENTS[.-]*",
|
|
||||||
"UNLICEN[CS]E", "UNLICEN[CS]E[.-]*",
|
|
||||||
// GPL (gpl.txt, etc.)
|
|
||||||
"agpl[.-]*",
|
|
||||||
"gpl[.-]*",
|
|
||||||
"lgpl[.-]*",
|
|
||||||
// Other license-specific (APACHE-2.0.txt, etc.)
|
|
||||||
"AGPL-*[0-9]*",
|
|
||||||
"APACHE-*[0-9]*",
|
|
||||||
"BSD-*[0-9]*",
|
|
||||||
"CC-BY-*",
|
|
||||||
"GFDL-*[0-9]*",
|
|
||||||
"GNU-*[0-9]*",
|
|
||||||
"GPL-*[0-9]*",
|
|
||||||
"LGPL-*[0-9]*",
|
|
||||||
"MIT-*[0-9]*",
|
|
||||||
"MPL-*[0-9]*",
|
|
||||||
"OFL-*[0-9]*",
|
|
||||||
]),
|
|
||||||
("lisp", &["*.el", "*.jl", "*.lisp", "*.lsp", "*.sc", "*.scm"]),
|
|
||||||
("lock", &["*.lock", "package-lock.json"]),
|
|
||||||
("log", &["*.log"]),
|
|
||||||
("lua", &["*.lua"]),
|
|
||||||
("lzma", &["*.lzma"]),
|
|
||||||
("lz4", &["*.lz4"]),
|
|
||||||
("m4", &["*.ac", "*.m4"]),
|
|
||||||
("make", &[
|
|
||||||
"[Gg][Nn][Uu]makefile", "[Mm]akefile",
|
|
||||||
"[Gg][Nn][Uu]makefile.am", "[Mm]akefile.am",
|
|
||||||
"[Gg][Nn][Uu]makefile.in", "[Mm]akefile.in",
|
|
||||||
"*.mk", "*.mak"
|
|
||||||
]),
|
|
||||||
("mako", &["*.mako", "*.mao"]),
|
|
||||||
("markdown", &["*.markdown", "*.md", "*.mdown", "*.mkdn"]),
|
|
||||||
("md", &["*.markdown", "*.md", "*.mdown", "*.mkdn"]),
|
|
||||||
("man", &["*.[0-9lnpx]", "*.[0-9][cEFMmpSx]"]),
|
|
||||||
("matlab", &["*.m"]),
|
|
||||||
("mk", &["mkfile"]),
|
|
||||||
("ml", &["*.ml"]),
|
|
||||||
("msbuild", &[
|
|
||||||
"*.csproj", "*.fsproj", "*.vcxproj", "*.proj", "*.props", "*.targets"
|
|
||||||
]),
|
|
||||||
("nim", &["*.nim"]),
|
|
||||||
("nix", &["*.nix"]),
|
|
||||||
("objc", &["*.h", "*.m"]),
|
|
||||||
("objcpp", &["*.h", "*.mm"]),
|
|
||||||
("ocaml", &["*.ml", "*.mli", "*.mll", "*.mly"]),
|
|
||||||
("org", &["*.org"]),
|
|
||||||
("pascal", &["*.pas", "*.dpr", "*.lpr", "*.pp", "*.inc"]),
|
|
||||||
("perl", &["*.perl", "*.pl", "*.PL", "*.plh", "*.plx", "*.pm", "*.t"]),
|
|
||||||
("pdf", &["*.pdf"]),
|
|
||||||
("php", &["*.php", "*.php3", "*.php4", "*.php5", "*.phtml"]),
|
|
||||||
("pod", &["*.pod"]),
|
|
||||||
("postscript", &[".eps", ".ps"]),
|
|
||||||
("protobuf", &["*.proto"]),
|
|
||||||
("ps", &["*.cdxml", "*.ps1", "*.ps1xml", "*.psd1", "*.psm1"]),
|
|
||||||
("puppet", &["*.erb", "*.pp", "*.rb"]),
|
|
||||||
("purs", &["*.purs"]),
|
|
||||||
("py", &["*.py"]),
|
|
||||||
("qmake", &["*.pro", "*.pri", "*.prf"]),
|
|
||||||
("qml", &["*.qml"]),
|
|
||||||
("readme", &["README*", "*README"]),
|
|
||||||
("r", &["*.R", "*.r", "*.Rmd", "*.Rnw"]),
|
|
||||||
("rdoc", &["*.rdoc"]),
|
|
||||||
("rst", &["*.rst"]),
|
|
||||||
("ruby", &["Gemfile", "*.gemspec", ".irbrc", "Rakefile", "*.rb"]),
|
|
||||||
("rust", &["*.rs"]),
|
|
||||||
("sass", &["*.sass", "*.scss"]),
|
|
||||||
("scala", &["*.scala", "*.sbt"]),
|
|
||||||
("sh", &[
|
|
||||||
// Portable/misc. init files
|
|
||||||
".login", ".logout", ".profile", "profile",
|
|
||||||
// bash-specific init files
|
|
||||||
".bash_login", "bash_login",
|
|
||||||
".bash_logout", "bash_logout",
|
|
||||||
".bash_profile", "bash_profile",
|
|
||||||
".bashrc", "bashrc", "*.bashrc",
|
|
||||||
// csh-specific init files
|
|
||||||
".cshrc", "*.cshrc",
|
|
||||||
// ksh-specific init files
|
|
||||||
".kshrc", "*.kshrc",
|
|
||||||
// tcsh-specific init files
|
|
||||||
".tcshrc",
|
|
||||||
// zsh-specific init files
|
|
||||||
".zshenv", "zshenv",
|
|
||||||
".zlogin", "zlogin",
|
|
||||||
".zlogout", "zlogout",
|
|
||||||
".zprofile", "zprofile",
|
|
||||||
".zshrc", "zshrc",
|
|
||||||
// Extensions
|
|
||||||
"*.bash", "*.csh", "*.ksh", "*.sh", "*.tcsh", "*.zsh",
|
|
||||||
]),
|
|
||||||
("smarty", &["*.tpl"]),
|
|
||||||
("sml", &["*.sml", "*.sig"]),
|
|
||||||
("soy", &["*.soy"]),
|
|
||||||
("spark", &["*.spark"]),
|
|
||||||
("sql", &["*.sql", "*.psql"]),
|
|
||||||
("stylus", &["*.styl"]),
|
|
||||||
("sv", &["*.v", "*.vg", "*.sv", "*.svh", "*.h"]),
|
|
||||||
("svg", &["*.svg"]),
|
|
||||||
("swift", &["*.swift"]),
|
|
||||||
("swig", &["*.def", "*.i"]),
|
|
||||||
("systemd", &[
|
|
||||||
"*.automount", "*.conf", "*.device", "*.link", "*.mount", "*.path",
|
|
||||||
"*.scope", "*.service", "*.slice", "*.socket", "*.swap", "*.target",
|
|
||||||
"*.timer",
|
|
||||||
]),
|
|
||||||
("taskpaper", &["*.taskpaper"]),
|
|
||||||
("tcl", &["*.tcl"]),
|
|
||||||
("tex", &["*.tex", "*.ltx", "*.cls", "*.sty", "*.bib", "*.dtx", "*.ins"]),
|
|
||||||
("textile", &["*.textile"]),
|
|
||||||
("thrift", &["*.thrift"]),
|
|
||||||
("tf", &["*.tf"]),
|
|
||||||
("ts", &["*.ts", "*.tsx"]),
|
|
||||||
("txt", &["*.txt"]),
|
|
||||||
("toml", &["*.toml", "Cargo.lock"]),
|
|
||||||
("twig", &["*.twig"]),
|
|
||||||
("vala", &["*.vala"]),
|
|
||||||
("vb", &["*.vb"]),
|
|
||||||
("verilog", &["*.v", "*.vh", "*.sv", "*.svh"]),
|
|
||||||
("vhdl", &["*.vhd", "*.vhdl"]),
|
|
||||||
("vim", &["*.vim"]),
|
|
||||||
("vimscript", &["*.vim"]),
|
|
||||||
("wiki", &["*.mediawiki", "*.wiki"]),
|
|
||||||
("webidl", &["*.idl", "*.webidl", "*.widl"]),
|
|
||||||
("xml", &[
|
|
||||||
"*.xml", "*.xml.dist", "*.dtd", "*.xsl", "*.xslt", "*.xsd", "*.xjb",
|
|
||||||
"*.rng", "*.sch",
|
|
||||||
]),
|
|
||||||
("xz", &["*.xz", "*.txz"]),
|
|
||||||
("yacc", &["*.y"]),
|
|
||||||
("yaml", &["*.yaml", "*.yml"]),
|
|
||||||
("zig", &["*.zig"]),
|
|
||||||
("zsh", &[
|
|
||||||
".zshenv", "zshenv",
|
|
||||||
".zlogin", "zlogin",
|
|
||||||
".zlogout", "zlogout",
|
|
||||||
".zprofile", "zprofile",
|
|
||||||
".zshrc", "zshrc",
|
|
||||||
"*.zsh",
|
|
||||||
]),
|
|
||||||
("zstd", &["*.zst", "*.zstd"]),
|
|
||||||
];
|
|
||||||
|
|
||||||
/// Glob represents a single glob in a set of file type definitions.
|
/// Glob represents a single glob in a set of file type definitions.
|
||||||
///
|
///
|
||||||
@@ -345,11 +122,7 @@ enum GlobInner<'a> {
|
|||||||
Matched {
|
Matched {
|
||||||
/// The file type definition which provided the glob.
|
/// The file type definition which provided the glob.
|
||||||
def: &'a FileTypeDef,
|
def: &'a FileTypeDef,
|
||||||
/// The index of the glob that matched inside the file type definition.
|
},
|
||||||
which: usize,
|
|
||||||
/// Whether the selection was negated or not.
|
|
||||||
negated: bool,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Glob<'a> {
|
impl<'a> Glob<'a> {
|
||||||
@@ -357,15 +130,13 @@ impl<'a> Glob<'a> {
|
|||||||
Glob(GlobInner::UnmatchedIgnore)
|
Glob(GlobInner::UnmatchedIgnore)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the file type defintion that matched, if one exists. A file type
|
/// Return the file type definition that matched, if one exists. A file type
|
||||||
/// definition always exists when a specific definition matches a file
|
/// definition always exists when a specific definition matches a file
|
||||||
/// path.
|
/// path.
|
||||||
pub fn file_type_def(&self) -> Option<&FileTypeDef> {
|
pub fn file_type_def(&self) -> Option<&FileTypeDef> {
|
||||||
match self {
|
match self {
|
||||||
Glob(GlobInner::UnmatchedIgnore) => None,
|
Glob(GlobInner::UnmatchedIgnore) => None,
|
||||||
Glob(GlobInner::Matched { def, .. }) => {
|
Glob(GlobInner::Matched { def, .. }) => Some(def),
|
||||||
Some(def)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -512,17 +283,13 @@ impl Types {
|
|||||||
return Match::None;
|
return Match::None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut matches = self.matches.get_default().borrow_mut();
|
let mut matches = self.matches.get_or_default().borrow_mut();
|
||||||
self.set.matches_into(name, &mut *matches);
|
self.set.matches_into(name, &mut *matches);
|
||||||
// The highest precedent match is the last one.
|
// The highest precedent match is the last one.
|
||||||
if let Some(&i) = matches.last() {
|
if let Some(&i) = matches.last() {
|
||||||
let (isel, iglob) = self.glob_to_selection[i];
|
let (isel, _) = self.glob_to_selection[i];
|
||||||
let sel = &self.selections[isel];
|
let sel = &self.selections[isel];
|
||||||
let glob = Glob(GlobInner::Matched {
|
let glob = Glob(GlobInner::Matched { def: sel.inner() });
|
||||||
def: sel.inner(),
|
|
||||||
which: iglob,
|
|
||||||
negated: sel.is_negated(),
|
|
||||||
});
|
|
||||||
return if sel.is_negated() {
|
return if sel.is_negated() {
|
||||||
Match::Ignore(glob)
|
Match::Ignore(glob)
|
||||||
} else {
|
} else {
|
||||||
@@ -551,10 +318,7 @@ impl TypesBuilder {
|
|||||||
/// of default type definitions can be added with `add_defaults`, and
|
/// of default type definitions can be added with `add_defaults`, and
|
||||||
/// additional type definitions can be added with `select` and `negate`.
|
/// additional type definitions can be added with `select` and `negate`.
|
||||||
pub fn new() -> TypesBuilder {
|
pub fn new() -> TypesBuilder {
|
||||||
TypesBuilder {
|
TypesBuilder { types: HashMap::new(), selections: vec![] }
|
||||||
types: HashMap::new(),
|
|
||||||
selections: vec![],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build the current set of file type definitions *and* selections into
|
/// Build the current set of file type definitions *and* selections into
|
||||||
@@ -579,19 +343,18 @@ impl TypesBuilder {
|
|||||||
GlobBuilder::new(glob)
|
GlobBuilder::new(glob)
|
||||||
.literal_separator(true)
|
.literal_separator(true)
|
||||||
.build()
|
.build()
|
||||||
.map_err(|err| {
|
.map_err(|err| Error::Glob {
|
||||||
Error::Glob {
|
glob: Some(glob.to_string()),
|
||||||
glob: Some(glob.to_string()),
|
err: err.kind().to_string(),
|
||||||
err: err.kind().to_string(),
|
})?,
|
||||||
}
|
);
|
||||||
})?);
|
|
||||||
glob_to_selection.push((isel, iglob));
|
glob_to_selection.push((isel, iglob));
|
||||||
}
|
}
|
||||||
selections.push(selection.clone().map(move |_| def));
|
selections.push(selection.clone().map(move |_| def));
|
||||||
}
|
}
|
||||||
let set = build_set.build().map_err(|err| {
|
let set = build_set
|
||||||
Error::Glob { glob: None, err: err.to_string() }
|
.build()
|
||||||
})?;
|
.map_err(|err| Error::Glob { glob: None, err: err.to_string() })?;
|
||||||
Ok(Types {
|
Ok(Types {
|
||||||
defs: defs,
|
defs: defs,
|
||||||
selections: selections,
|
selections: selections,
|
||||||
@@ -656,16 +419,21 @@ impl TypesBuilder {
|
|||||||
/// If `name` is `all` or otherwise contains any character that is not a
|
/// If `name` is `all` or otherwise contains any character that is not a
|
||||||
/// Unicode letter or number, then an error is returned.
|
/// Unicode letter or number, then an error is returned.
|
||||||
pub fn add(&mut self, name: &str, glob: &str) -> Result<(), Error> {
|
pub fn add(&mut self, name: &str, glob: &str) -> Result<(), Error> {
|
||||||
lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref RE: Regex = Regex::new(r"^[\pL\pN]+$").unwrap();
|
static ref RE: Regex = Regex::new(r"^[\pL\pN]+$").unwrap();
|
||||||
};
|
};
|
||||||
if name == "all" || !RE.is_match(name) {
|
if name == "all" || !RE.is_match(name) {
|
||||||
return Err(Error::InvalidDefinition);
|
return Err(Error::InvalidDefinition);
|
||||||
}
|
}
|
||||||
let (key, glob) = (name.to_string(), glob.to_string());
|
let (key, glob) = (name.to_string(), glob.to_string());
|
||||||
self.types.entry(key).or_insert_with(|| {
|
self.types
|
||||||
FileTypeDef { name: name.to_string(), globs: vec![] }
|
.entry(key)
|
||||||
}).globs.push(glob);
|
.or_insert_with(|| FileTypeDef {
|
||||||
|
name: name.to_string(),
|
||||||
|
globs: vec![],
|
||||||
|
})
|
||||||
|
.globs
|
||||||
|
.push(glob);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -692,7 +460,10 @@ impl TypesBuilder {
|
|||||||
3 => {
|
3 => {
|
||||||
let name = parts[0];
|
let name = parts[0];
|
||||||
let types_string = parts[2];
|
let types_string = parts[2];
|
||||||
if name.is_empty() || parts[1] != "include" || types_string.is_empty() {
|
if name.is_empty()
|
||||||
|
|| parts[1] != "include"
|
||||||
|
|| types_string.is_empty()
|
||||||
|
{
|
||||||
return Err(Error::InvalidDefinition);
|
return Err(Error::InvalidDefinition);
|
||||||
}
|
}
|
||||||
let types = types_string.split(',');
|
let types = types_string.split(',');
|
||||||
@@ -702,14 +473,15 @@ impl TypesBuilder {
|
|||||||
return Err(Error::InvalidDefinition);
|
return Err(Error::InvalidDefinition);
|
||||||
}
|
}
|
||||||
for type_name in types {
|
for type_name in types {
|
||||||
let globs = self.types.get(type_name).unwrap().globs.clone();
|
let globs =
|
||||||
|
self.types.get(type_name).unwrap().globs.clone();
|
||||||
for glob in globs {
|
for glob in globs {
|
||||||
self.add(name, &glob)?;
|
self.add(name, &glob)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => Err(Error::InvalidDefinition)
|
_ => Err(Error::InvalidDefinition),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -766,7 +538,7 @@ mod tests {
|
|||||||
"rust:*.rs",
|
"rust:*.rs",
|
||||||
"js:*.js",
|
"js:*.js",
|
||||||
"foo:*.{rs,foo}",
|
"foo:*.{rs,foo}",
|
||||||
"combo:include:html,rust"
|
"combo:include:html,rust",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -800,7 +572,7 @@ mod tests {
|
|||||||
"combo:include:html,python",
|
"combo:include:html,python",
|
||||||
// Bad format
|
// Bad format
|
||||||
"combo:foobar:html,rust",
|
"combo:foobar:html,rust",
|
||||||
""
|
"",
|
||||||
];
|
];
|
||||||
for def in bad_defs {
|
for def in bad_defs {
|
||||||
assert!(btypes.add_def(def).is_err());
|
assert!(btypes.add_def(def).is_err());
|
||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user