mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2025-08-19 14:13:49 -07:00
Compare commits
611 Commits
grep-searc
...
ignore-0.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
79018eb693 | ||
|
|
44cd344438 | ||
|
|
e493e54b9b | ||
|
|
8e8215aa65 | ||
|
|
3fe701498e | ||
|
|
e79085e9e4 | ||
|
|
764c197022 | ||
|
|
ef1611b5f5 | ||
|
|
45d12abbc5 | ||
|
|
5fde8391f9 | ||
|
|
3edb11c513 | ||
|
|
ed144be775 | ||
|
|
967e7ad0de | ||
|
|
9952ba2068 | ||
|
|
b751758d60 | ||
|
|
8f14cb18a5 | ||
|
|
da9d720431 | ||
|
|
a9d71a0368 | ||
|
|
f3646242cc | ||
|
|
601f212a0b | ||
|
|
5a565354f8 | ||
|
|
2a6532ae71 | ||
|
|
ece1f50cfe | ||
|
|
a7d26c8f14 | ||
|
|
bd222ae93f | ||
|
|
4359d8aac0 | ||
|
|
308819fb1f | ||
|
|
09108b7fda | ||
|
|
743d64f2e4 | ||
|
|
5962abc465 | ||
|
|
1604a18db3 | ||
|
|
9eeb0b01ce | ||
|
|
df4400209a | ||
|
|
77439f99a4 | ||
|
|
be7d6dd9ce | ||
|
|
9f15e3b671 | ||
|
|
254b8b67bb | ||
|
|
8a7f43b84d | ||
|
|
d968a27ed5 | ||
|
|
9b8f5cbaba | ||
|
|
c52da74ac3 | ||
|
|
7dcbff9a9b | ||
|
|
bef1f0e770 | ||
|
|
cd9815cb37 | ||
|
|
3f22c3a658 | ||
|
|
0913972104 | ||
|
|
f19b84fb23 | ||
|
|
59fc583aeb | ||
|
|
1c7c4e6640 | ||
|
|
69c5e3938d | ||
|
|
d9cf05ad50 | ||
|
|
af8b6caebb | ||
|
|
c84cfb6756 | ||
|
|
895e26a000 | ||
|
|
8c95290ff6 | ||
|
|
d6feeb7ff2 | ||
|
|
626ed00c19 | ||
|
|
332ad18401 | ||
|
|
fc3cf41247 | ||
|
|
a4868b8835 | ||
|
|
f99b991117 | ||
|
|
de0bc78982 | ||
|
|
147e96914c | ||
|
|
0abc40c23c | ||
|
|
f768796e4f | ||
|
|
da0c0c4705 | ||
|
|
05411b2b32 | ||
|
|
cc93db3b18 | ||
|
|
049354b766 | ||
|
|
386dd2806d | ||
|
|
5fe9a954e6 | ||
|
|
f158a42a71 | ||
|
|
5724391d39 | ||
|
|
0df71240ff | ||
|
|
f3164f2615 | ||
|
|
31d3e24130 | ||
|
|
bf842dbc7f | ||
|
|
6d5dba85bd | ||
|
|
afb89bcdad | ||
|
|
332dc56372 | ||
|
|
12a6ca45f9 | ||
|
|
9d703110cf | ||
|
|
e99b6bda0e | ||
|
|
276e2c9b9a | ||
|
|
9a9f54d44c | ||
|
|
47833b9ce7 | ||
|
|
44a9e37737 | ||
|
|
8fd05cacee | ||
|
|
4691d11034 | ||
|
|
519a6b68af | ||
|
|
9c940b45f4 | ||
|
|
0a167021c3 | ||
|
|
aeaa5fc1b1 | ||
|
|
7048a06c31 | ||
|
|
23be3cf850 | ||
|
|
b48bbf527d | ||
|
|
8eabe47b57 | ||
|
|
ff712bfd9d | ||
|
|
a7f2d48234 | ||
|
|
57500ad013 | ||
|
|
0b04553aff | ||
|
|
1ae121122f | ||
|
|
688003e51c | ||
|
|
718a00f6f2 | ||
|
|
7cbc535d70 | ||
|
|
7a6a40bae1 | ||
|
|
1e9ee2cc85 | ||
|
|
968491f8e9 | ||
|
|
63b0f31a22 | ||
|
|
7ecee299a5 | ||
|
|
dd396ff34e | ||
|
|
fb0a82f3c3 | ||
|
|
dbc8ca9cc1 | ||
|
|
c3db8db93d | ||
|
|
17ef4c40f3 | ||
|
|
a9e0477ea8 | ||
|
|
b3c5773266 | ||
|
|
118b950085 | ||
|
|
b45b2f58ea | ||
|
|
662a9bc73d | ||
|
|
401add0a99 | ||
|
|
f81b72721b | ||
|
|
1d4fccaadc | ||
|
|
09e464e674 | ||
|
|
31adff6f3c | ||
|
|
b41e596327 | ||
|
|
fb62266620 | ||
|
|
acf226c39d | ||
|
|
8299625e48 | ||
|
|
db256c87eb | ||
|
|
ba533f390e | ||
|
|
ba503eb677 | ||
|
|
f72c2dfd90 | ||
|
|
c0aa58b4f7 | ||
|
|
184ee4c328 | ||
|
|
e82fbf2c46 | ||
|
|
eb18da0450 | ||
|
|
0f7494216f | ||
|
|
442a278635 | ||
|
|
7ebed3ace6 | ||
|
|
8a7db1a918 |
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?
|
||||
|
||||
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.
|
||||
|
||||
#### Describe your question, feature request, or bug.
|
||||
#### Describe your bug.
|
||||
|
||||
If a question, please describe the problem you're trying to solve and give
|
||||
as much context as possible.
|
||||
Give a high level description of the bug.
|
||||
|
||||
If a feature request, please describe the behavior you want and the motivation.
|
||||
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?
|
||||
#### What are the steps to reproduce the behavior?
|
||||
|
||||
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
|
||||
@@ -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
|
||||
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
|
||||
your invocation of ripgrep.
|
||||
@@ -48,6 +50,6 @@ goes
|
||||
here
|
||||
```
|
||||
|
||||
#### If this is a bug, what is the expected behavior?
|
||||
#### What is the expected behavior?
|
||||
|
||||
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
|
||||
*.pyc
|
||||
ripgrep*_source.tar.bz2
|
||||
|
||||
# Cargo timings
|
||||
cargo-timing-*.html
|
||||
cargo-timing.html
|
||||
|
||||
108
.travis.yml
108
.travis.yml
@@ -1,108 +0,0 @@
|
||||
language: rust
|
||||
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.28.0
|
||||
env: TARGET=x86_64-unknown-linux-gnu
|
||||
- os: linux
|
||||
rust: 1.28.0
|
||||
env: TARGET=x86_64-unknown-linux-musl
|
||||
- os: linux
|
||||
rust: 1.28.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
|
||||
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
|
||||
480
CHANGELOG.md
480
CHANGELOG.md
@@ -1,3 +1,479 @@
|
||||
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
|
||||
fixes, some performance improvements and a few feature enhancements. Notably,
|
||||
ripgrep's user experience for binary file filtering has been improved. See the
|
||||
[guide's new section on binary data](GUIDE.md#binary-data) for more details.
|
||||
|
||||
This release also marks a change in ripgrep's versioning. Where as the previous
|
||||
version was `0.10.0`, this version is `11.0.0`. Moving forward, ripgrep's
|
||||
major version will be increased a few times per year. ripgrep will continue to
|
||||
be conservative with respect to backwards compatibility, but may occasionally
|
||||
introduce breaking changes, which will always be documented in this CHANGELOG.
|
||||
See [issue 1172](https://github.com/BurntSushi/ripgrep/issues/1172) for a bit
|
||||
more detail on why this versioning change was made.
|
||||
|
||||
This release increases the **minimum supported Rust version** from 1.28.0 to
|
||||
1.34.0.
|
||||
|
||||
**BREAKING CHANGES**:
|
||||
|
||||
* ripgrep has tweaked its exit status codes to be more like GNU grep's. Namely,
|
||||
if a non-fatal error occurs during a search, then ripgrep will now always
|
||||
emit a `2` exit status code, regardless of whether a match is found or not.
|
||||
Previously, ripgrep would only emit a `2` exit status code for a catastrophic
|
||||
error (e.g., regex syntax error). One exception to this is if ripgrep is run
|
||||
with `-q/--quiet`. In that case, if an error occurs and a match is found,
|
||||
then ripgrep will exit with a `0` exit status code.
|
||||
* Supplying the `-u/--unrestricted` flag three times is now equivalent to
|
||||
supplying `--no-ignore --hidden --binary`. Previously, `-uuu` was equivalent
|
||||
to `--no-ignore --hidden --text`. The difference is that `--binary` disables
|
||||
binary file filtering without potentially dumping binary data into your
|
||||
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
|
||||
necessary. All uses of AVX in ripgrep are now enabled automatically via
|
||||
runtime CPU feature detection. The `simd-accel` feature does remain available
|
||||
(only for enabling SIMD for transcoding), however, it does increase
|
||||
compilation times substantially at the moment.
|
||||
|
||||
Performance improvements:
|
||||
|
||||
* [PERF #497](https://github.com/BurntSushi/ripgrep/issues/497),
|
||||
[PERF #838](https://github.com/BurntSushi/ripgrep/issues/838):
|
||||
Make `rg -F -f dictionary-of-literals` much faster.
|
||||
|
||||
Feature enhancements:
|
||||
|
||||
* Added or improved file type filtering for Apache Thrift, ASP, Bazel, Brotli,
|
||||
BuildStream, bzip2, C, C++, Cython, gzip, Java, Make, Postscript, QML, Tex,
|
||||
XML, xz, zig and zstd.
|
||||
* [FEATURE #855](https://github.com/BurntSushi/ripgrep/issues/855):
|
||||
Add `--binary` flag for disabling binary file filtering.
|
||||
* [FEATURE #1078](https://github.com/BurntSushi/ripgrep/pull/1078):
|
||||
Add `--max-columns-preview` flag for showing a preview of long lines.
|
||||
* [FEATURE #1099](https://github.com/BurntSushi/ripgrep/pull/1099):
|
||||
Add support for Brotli and Zstd to the `-z/--search-zip` flag.
|
||||
* [FEATURE #1138](https://github.com/BurntSushi/ripgrep/pull/1138):
|
||||
Add `--no-ignore-dot` flag for ignoring `.ignore` files.
|
||||
* [FEATURE #1155](https://github.com/BurntSushi/ripgrep/pull/1155):
|
||||
Add `--auto-hybrid-regex` flag for automatically falling back to PCRE2.
|
||||
* [FEATURE #1159](https://github.com/BurntSushi/ripgrep/pull/1159):
|
||||
ripgrep's exit status logic should now match GNU grep. See updated man page.
|
||||
* [FEATURE #1164](https://github.com/BurntSushi/ripgrep/pull/1164):
|
||||
Add `--ignore-file-case-insensitive` for case insensitive ignore globs.
|
||||
* [FEATURE #1185](https://github.com/BurntSushi/ripgrep/pull/1185):
|
||||
Add `-I` flag as a short option for the `--no-filename` flag.
|
||||
* [FEATURE #1207](https://github.com/BurntSushi/ripgrep/pull/1207):
|
||||
Add `none` value to `-E/--encoding` to forcefully disable all transcoding.
|
||||
* [FEATURE da9d7204](https://github.com/BurntSushi/ripgrep/commit/da9d7204):
|
||||
Add `--pcre2-version` for querying showing PCRE2 version information.
|
||||
|
||||
Bug fixes:
|
||||
|
||||
* [BUG #306](https://github.com/BurntSushi/ripgrep/issues/306),
|
||||
[BUG #855](https://github.com/BurntSushi/ripgrep/issues/855):
|
||||
Improve the user experience for ripgrep's binary file filtering.
|
||||
* [BUG #373](https://github.com/BurntSushi/ripgrep/issues/373),
|
||||
[BUG #1098](https://github.com/BurntSushi/ripgrep/issues/1098):
|
||||
`**` is now accepted as valid syntax anywhere in a glob.
|
||||
* [BUG #916](https://github.com/BurntSushi/ripgrep/issues/916):
|
||||
ripgrep no longer hangs when searching `/proc` with a zombie process present.
|
||||
* [BUG #1052](https://github.com/BurntSushi/ripgrep/issues/1052):
|
||||
Fix bug where ripgrep could panic when transcoding UTF-16 files.
|
||||
* [BUG #1055](https://github.com/BurntSushi/ripgrep/issues/1055):
|
||||
Suggest `-U/--multiline` when a pattern contains a `\n`.
|
||||
* [BUG #1063](https://github.com/BurntSushi/ripgrep/issues/1063):
|
||||
Always strip a BOM if it's present, even for UTF-8.
|
||||
* [BUG #1064](https://github.com/BurntSushi/ripgrep/issues/1064):
|
||||
Fix inner literal detection that could lead to incorrect matches.
|
||||
* [BUG #1079](https://github.com/BurntSushi/ripgrep/issues/1079):
|
||||
Fixes a bug where the order of globs could result in missing a match.
|
||||
* [BUG #1089](https://github.com/BurntSushi/ripgrep/issues/1089):
|
||||
Fix another bug where ripgrep could panic when transcoding UTF-16 files.
|
||||
* [BUG #1091](https://github.com/BurntSushi/ripgrep/issues/1091):
|
||||
Add note about inverted flags to the man page.
|
||||
* [BUG #1093](https://github.com/BurntSushi/ripgrep/pull/1093):
|
||||
Fix handling of literal slashes in gitignore patterns.
|
||||
* [BUG #1095](https://github.com/BurntSushi/ripgrep/issues/1095):
|
||||
Fix corner cases involving the `--crlf` flag.
|
||||
* [BUG #1101](https://github.com/BurntSushi/ripgrep/issues/1101):
|
||||
Fix AsciiDoc escaping for man page output.
|
||||
* [BUG #1103](https://github.com/BurntSushi/ripgrep/issues/1103):
|
||||
Clarify what `--encoding auto` does.
|
||||
* [BUG #1106](https://github.com/BurntSushi/ripgrep/issues/1106):
|
||||
`--files-with-matches` and `--files-without-match` work with one file.
|
||||
* [BUG #1121](https://github.com/BurntSushi/ripgrep/issues/1121):
|
||||
Fix bug that was triggering Windows antimalware when using the `--files`
|
||||
flag.
|
||||
* [BUG #1125](https://github.com/BurntSushi/ripgrep/issues/1125),
|
||||
[BUG #1159](https://github.com/BurntSushi/ripgrep/issues/1159):
|
||||
ripgrep shouldn't panic for `rg -h | rg` and should emit correct exit status.
|
||||
* [BUG #1144](https://github.com/BurntSushi/ripgrep/issues/1144):
|
||||
Fixes a bug where line numbers could be wrong on big-endian machines.
|
||||
* [BUG #1154](https://github.com/BurntSushi/ripgrep/issues/1154):
|
||||
Windows files with "hidden" attribute are now treated as hidden.
|
||||
* [BUG #1173](https://github.com/BurntSushi/ripgrep/issues/1173):
|
||||
Fix handling of `**` patterns in gitignore files.
|
||||
* [BUG #1174](https://github.com/BurntSushi/ripgrep/issues/1174):
|
||||
Fix handling of repeated `**` patterns in gitignore files.
|
||||
* [BUG #1176](https://github.com/BurntSushi/ripgrep/issues/1176):
|
||||
Fix bug where `-F`/`-x` weren't applied to patterns given via `-f`.
|
||||
* [BUG #1189](https://github.com/BurntSushi/ripgrep/issues/1189):
|
||||
Document cases where ripgrep may use a lot of memory.
|
||||
* [BUG #1203](https://github.com/BurntSushi/ripgrep/issues/1203):
|
||||
Fix a matching bug related to the suffix literal optimization.
|
||||
* [BUG 8f14cb18](https://github.com/BurntSushi/ripgrep/commit/8f14cb18):
|
||||
Increase the default stack size for PCRE2's JIT.
|
||||
|
||||
|
||||
0.10.0 (2018-09-07)
|
||||
===================
|
||||
This is a new minor version release of ripgrep that contains some major new
|
||||
@@ -240,7 +716,7 @@ Bug fixes:
|
||||
|
||||
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
|
||||
many bugs and improves the quality of life for ripgrep maintainers. This
|
||||
release also includes greatly improved documentation in the form of a
|
||||
@@ -938,7 +1414,7 @@ Bug fixes:
|
||||
=====
|
||||
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
|
||||
* [FEATURE #20](https://github.com/BurntSushi/ripgrep/issues/20):
|
||||
Adds a --no-filename flag.
|
||||
|
||||
819
Cargo.lock
generated
819
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
61
Cargo.toml
61
Cargo.toml
@@ -1,30 +1,27 @@
|
||||
[package]
|
||||
name = "ripgrep"
|
||||
version = "0.10.0" #:version
|
||||
version = "13.0.0" #:version
|
||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||
description = """
|
||||
ripgrep is a line-oriented search tool that recursively searches your current
|
||||
directory for a regex pattern while respecting your gitignore rules. ripgrep
|
||||
has first class support on Windows, macOS and Linux
|
||||
ripgrep is a line-oriented search tool that recursively searches the current
|
||||
directory for a regex pattern while respecting gitignore rules. ripgrep has
|
||||
first class support on Windows, macOS and Linux.
|
||||
"""
|
||||
documentation = "https://github.com/BurntSushi/ripgrep"
|
||||
homepage = "https://github.com/BurntSushi/ripgrep"
|
||||
repository = "https://github.com/BurntSushi/ripgrep"
|
||||
readme = "README.md"
|
||||
keywords = ["regex", "grep", "egrep", "search", "pattern"]
|
||||
categories = ["command-line-utilities", "text-processing"]
|
||||
license = "Unlicense OR MIT"
|
||||
exclude = ["HomebrewFormula"]
|
||||
build = "build.rs"
|
||||
autotests = false
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "BurntSushi/ripgrep" }
|
||||
appveyor = { repository = "BurntSushi/ripgrep" }
|
||||
edition = "2018"
|
||||
rust-version = "1.65"
|
||||
|
||||
[[bin]]
|
||||
bench = false
|
||||
path = "src/main.rs"
|
||||
path = "crates/core/main.rs"
|
||||
name = "rg"
|
||||
|
||||
[[test]]
|
||||
@@ -33,46 +30,49 @@ path = "tests/tests.rs"
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"globset",
|
||||
"grep",
|
||||
"grep-cli",
|
||||
"grep-matcher",
|
||||
"grep-pcre2",
|
||||
"grep-printer",
|
||||
"grep-regex",
|
||||
"grep-searcher",
|
||||
"ignore",
|
||||
"crates/globset",
|
||||
"crates/grep",
|
||||
"crates/cli",
|
||||
"crates/matcher",
|
||||
"crates/pcre2",
|
||||
"crates/printer",
|
||||
"crates/regex",
|
||||
"crates/searcher",
|
||||
"crates/ignore",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
grep = { version = "0.2.2", path = "grep" }
|
||||
ignore = { version = "0.4.4", path = "ignore" }
|
||||
bstr = "1.1.0"
|
||||
grep = { version = "0.2.8", path = "crates/grep" }
|
||||
ignore = { version = "0.4.18", path = "crates/ignore" }
|
||||
lazy_static = "1.1.0"
|
||||
log = "0.4.5"
|
||||
num_cpus = "1.8.0"
|
||||
regex = "1.0.5"
|
||||
regex = "1.3.5"
|
||||
serde_json = "1.0.23"
|
||||
termcolor = "1.0.3"
|
||||
termcolor = "1.1.0"
|
||||
|
||||
[dependencies.clap]
|
||||
version = "2.32.0"
|
||||
version = "2.33.0"
|
||||
default-features = false
|
||||
features = ["suggestions"]
|
||||
|
||||
[target.'cfg(all(target_env = "musl", target_pointer_width = "64"))'.dependencies.jemallocator]
|
||||
version = "0.5.0"
|
||||
|
||||
[build-dependencies]
|
||||
lazy_static = "1.1.0"
|
||||
|
||||
[build-dependencies.clap]
|
||||
version = "2.32.0"
|
||||
version = "2.33.0"
|
||||
default-features = false
|
||||
features = ["suggestions"]
|
||||
|
||||
[dev-dependencies]
|
||||
serde = "1.0.77"
|
||||
serde_derive = "1.0.77"
|
||||
walkdir = "2"
|
||||
|
||||
[features]
|
||||
avx-accel = ["grep/avx-accel"]
|
||||
simd-accel = ["grep/simd-accel"]
|
||||
pcre2 = ["grep/pcre2"]
|
||||
|
||||
@@ -81,6 +81,7 @@ debug = 1
|
||||
|
||||
[package.metadata.deb]
|
||||
features = ["pcre2"]
|
||||
section = "utils"
|
||||
assets = [
|
||||
["target/release/rg", "usr/bin/", "755"],
|
||||
["COPYING", "usr/share/doc/ripgrep/", "644"],
|
||||
@@ -90,13 +91,13 @@ assets = [
|
||||
["README.md", "usr/share/doc/ripgrep/README", "644"],
|
||||
["FAQ.md", "usr/share/doc/ripgrep/FAQ", "644"],
|
||||
# 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
|
||||
# 'ci/build_deb.sh' script.
|
||||
# 'ci/build-deb' script.
|
||||
["deployment/deb/rg.1", "usr/share/man/man1/rg.1", "644"],
|
||||
# Similarly for shell completions.
|
||||
["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"],
|
||||
]
|
||||
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"
|
||||
86
FAQ.md
86
FAQ.md
@@ -5,14 +5,15 @@
|
||||
* [When is the next release?](#release)
|
||||
* [Does ripgrep have a man page?](#manpage)
|
||||
* [Does ripgrep have support for shell auto-completion?](#complete)
|
||||
* [How do I use lookaround and/or backreferences?](#fancy)
|
||||
* [How do I configure ripgrep's colors?](#colors)
|
||||
* [How do I enable true colors on Windows?](#truecolors-windows)
|
||||
* [How do I stop ripgrep from messing up colors when I kill it?](#stop-ripgrep)
|
||||
* [How can I get results in a consistent order?](#order)
|
||||
* [How do I search files that aren't UTF-8?](#encoding)
|
||||
* [How do I search compressed files?](#compressed)
|
||||
* [How do I search over multiple lines?](#multiline)
|
||||
* [How do I 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 make the `-f/--file` flag faster?](#dfa-size)
|
||||
* [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)
|
||||
* [Can ripgrep replace grep?](#posix4ever)
|
||||
* [What does the "rip" in ripgrep mean?](#intentcountsforsomething)
|
||||
* [How can I donate to ripgrep or its maintainers?](#donations)
|
||||
|
||||
|
||||
<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
|
||||
effort basis and no dates **will ever be given**.
|
||||
|
||||
One exception to this is high impact bugs. If a ripgrep release contains a
|
||||
significant regression, then there will generally be a strong push to get a
|
||||
patch release out with a fix.
|
||||
An exception to this _can be_ high impact bugs. If a ripgrep release contains
|
||||
a significant regression, then there will generally be a strong push to get a
|
||||
patch release out with a fix. However, no promises are made.
|
||||
|
||||
|
||||
<h3 name="manpage">
|
||||
Does ripgrep have a man page?
|
||||
</h3>
|
||||
|
||||
Yes! Whenever ripgrep is compiled on a system with `asciidoc` present, then a
|
||||
man page is generated from ripgrep's argv parser. After compiling ripgrep, you
|
||||
can find the man page like so from the root of the repository:
|
||||
Yes! Whenever ripgrep is compiled on a system with `asciidoctor` or `asciidoc`
|
||||
present, then a man page is generated from ripgrep's argv parser. After
|
||||
compiling ripgrep, you can find the man page like so from the root of the
|
||||
repository:
|
||||
|
||||
```
|
||||
$ find ./target -name rg.1 -print0 | xargs -0 ls -t | head -n1
|
||||
@@ -118,7 +121,7 @@ from run to run of ripgrep.
|
||||
The only way to make the order of results consistent is to ask ripgrep to
|
||||
sort the output. Currently, this will disable all parallelism. (On smaller
|
||||
repositories, you might not notice much of a performance difference!) You
|
||||
can achieve this with the `--sort-files` flag.
|
||||
can achieve this with the `--sort path` flag.
|
||||
|
||||
There is more discussion on this topic here:
|
||||
https://github.com/BurntSushi/ripgrep/issues/152
|
||||
@@ -136,10 +139,10 @@ How do I search compressed files?
|
||||
</h3>
|
||||
|
||||
ripgrep's `-z/--search-zip` flag will cause it to search compressed files
|
||||
automatically. Currently, this supports gzip, bzip2, lzma, lz4 and xz only and
|
||||
requires the corresponding `gzip`, `bzip2` and `xz` binaries to be installed on
|
||||
your system. (That is, ripgrep does decompression by shelling out to another
|
||||
process.)
|
||||
automatically. Currently, this supports gzip, bzip2, xz, lzma, lz4, Brotli and
|
||||
Zstd. Each of these requires the corresponding `gzip`, `bzip2`, `xz`,
|
||||
`lz4`, `brotli` and `zstd` binaries to be installed on your system. (That is,
|
||||
ripgrep does decompression by shelling out to another process.)
|
||||
|
||||
ripgrep currently does not search archive formats, so `*.tar.gz` files, for
|
||||
example, are skipped.
|
||||
@@ -149,9 +152,8 @@ example, are skipped.
|
||||
How do I search over multiple lines?
|
||||
</h3>
|
||||
|
||||
This isn't currently possible. ripgrep is fundamentally a line-oriented search
|
||||
tool. With that said,
|
||||
[multiline search is a planned opt-in feature](https://github.com/BurntSushi/ripgrep/issues/176).
|
||||
The `-U/--multiline` flag enables ripgrep to report results that span over
|
||||
multiple lines.
|
||||
|
||||
|
||||
<h3 name="fancy">
|
||||
@@ -206,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
|
||||
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}'
|
||||
@@ -314,6 +316,26 @@ available
|
||||
[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">
|
||||
How do I get around the regex size limit?
|
||||
</h3>
|
||||
@@ -823,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
|
||||
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
|
||||
**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).
|
||||
|
||||
Note: the above command assumes that you are using GNU sed. If you are using
|
||||
@@ -870,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
|
||||
ideological activism by promoting the Unlicense's goal: to disclaim
|
||||
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
|
||||
is also offered under the MIT license, which is ubiquitous and accepted by
|
||||
almost everyone.
|
||||
@@ -935,8 +957,8 @@ Here are some cases where you might *not* want to use ripgrep. The same caveats
|
||||
for the previous section apply.
|
||||
|
||||
* Are you writing portable shell scripts intended to work in a variety of
|
||||
environments? Great, probably not a good idea to use ripgrep! ripgrep is has
|
||||
nowhere near the ubquity of grep, so if you do use ripgrep, you might need
|
||||
environments? Great, probably not a good idea to use ripgrep! ripgrep has
|
||||
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.
|
||||
* 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.
|
||||
@@ -982,3 +1004,21 @@ grep](#posix4ever),
|
||||
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
|
||||
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/)
|
||||
|
||||
368
GUIDE.md
368
GUIDE.md
@@ -18,6 +18,8 @@ translatable to any command line shell environment.
|
||||
* [Replacements](#replacements)
|
||||
* [Configuration file](#configuration-file)
|
||||
* [File encoding](#file-encoding)
|
||||
* [Binary data](#binary-data)
|
||||
* [Preprocessor](#preprocessor)
|
||||
* [Common options](#common-options)
|
||||
|
||||
|
||||
@@ -109,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
|
||||
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
|
||||
@@ -175,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
|
||||
the following:
|
||||
|
||||
1. Files and directories that match the rules in your `.gitignore` glob
|
||||
pattern.
|
||||
1. Files and directories that match glob patterns in these three categories:
|
||||
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.
|
||||
3. Binary files. (ripgrep considers any file with a `NUL` byte to be binary.)
|
||||
4. Symbolic links aren't followed.
|
||||
|
||||
All of these things can be toggled using various flags provided by ripgrep:
|
||||
|
||||
1. You can disable `.gitignore` handling with the `--no-ignore` flag.
|
||||
2. Hidden files and directories can be searched with the `--hidden` flag.
|
||||
1. You can disable all ignore-related filtering with the `--no-ignore` 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.
|
||||
Be careful with this flag! Binary files may emit control characters to your
|
||||
terminal, which might cause strange behavior.
|
||||
@@ -235,6 +242,11 @@ Like `.gitignore`, a `.ignore` file can be placed in any directory. Its rules
|
||||
will be processed with respect to the directory it resides in, just like
|
||||
`.gitignore`.
|
||||
|
||||
To process `.gitignore` and `.ignore` files case insensitively, use the flag
|
||||
`--ignore-file-case-insensitive`. This is especially useful on case insensitive
|
||||
file systems like those on Windows and macOS. Note though that this can come
|
||||
with a significant performance penalty, and is therefore disabled by default.
|
||||
|
||||
For a more in depth description of how glob patterns in a `.gitignore` file
|
||||
are interpreted, please see `man gitignore`.
|
||||
|
||||
@@ -370,7 +382,7 @@ make: *.mak, *.mk, GNUmakefile, Gnumakefile, Makefile, gnumakefile, makefile
|
||||
By default, ripgrep comes with a bunch of pre-defined types. Generally, these
|
||||
types correspond to well known public formats. But you can define your own
|
||||
types as well. For example, perhaps you frequently search "web" files, which
|
||||
consist of Javascript, HTML and CSS:
|
||||
consist of JavaScript, HTML and CSS:
|
||||
|
||||
```
|
||||
$ rg --type-add 'web:*.html' --type-add 'web:*.css' --type-add 'web:*.js' -tweb title
|
||||
@@ -405,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.
|
||||
([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
|
||||
|
||||
@@ -520,9 +547,9 @@ config file. Once the environment variable is set, open the file and just type
|
||||
in the flags you want set automatically. There are only two rules for
|
||||
describing the format of the config file:
|
||||
|
||||
1. Every line is a shell argument, after trimming ASCII whitespace.
|
||||
2. Lines starting with `#` (optionally preceded by any amount of
|
||||
ASCII whitespace) are ignored.
|
||||
1. Every line is a shell argument, after trimming whitespace.
|
||||
2. Lines starting with `#` (optionally preceded by any amount of whitespace)
|
||||
are ignored.
|
||||
|
||||
In particular, there is no escaping. Each line is given to ripgrep as a single
|
||||
command line argument verbatim.
|
||||
@@ -532,8 +559,9 @@ formatting peculiarities:
|
||||
|
||||
```
|
||||
$ cat $HOME/.ripgreprc
|
||||
# Don't let ripgrep vomit really long lines to my terminal.
|
||||
# Don't let ripgrep vomit really long lines to my terminal, and show a preview.
|
||||
--max-columns=150
|
||||
--max-columns-preview
|
||||
|
||||
# Add my 'web' type.
|
||||
--type-add
|
||||
@@ -598,13 +626,14 @@ topic, but we can try to summarize its relevancy to ripgrep:
|
||||
* Files are generally just a bundle of bytes. There is no reliable way to know
|
||||
their encoding.
|
||||
* Either the encoding of the pattern must match the encoding of the files being
|
||||
searched, or a form of transcoding must be performed converts either the
|
||||
searched, or a form of transcoding must be performed that converts either the
|
||||
pattern or the file to the same encoding as the other.
|
||||
* ripgrep tends to work best on plain text files, and among plain text files,
|
||||
the most popular encodings likely consist of ASCII, latin1 or UTF-8. As
|
||||
a special exception, UTF-16 is prevalent in Windows environments
|
||||
|
||||
In light of the above, here is how ripgrep behaves:
|
||||
In light of the above, here is how ripgrep behaves when `--encoding auto` is
|
||||
given, which is the default:
|
||||
|
||||
* All input is assumed to be ASCII compatible (which means every byte that
|
||||
corresponds to an ASCII codepoint actually is an ASCII codepoint). This
|
||||
@@ -620,12 +649,15 @@ In light of the above, here is how ripgrep behaves:
|
||||
they correspond to a UTF-16 BOM, then ripgrep will transcode the contents of
|
||||
the file from UTF-16 to UTF-8, and then execute the search on the transcoded
|
||||
version of the file. (This incurs a performance penalty since transcoding
|
||||
is slower than regex searching.)
|
||||
is needed in addition to regex searching.) If the file contains invalid
|
||||
UTF-16, then the Unicode replacement codepoint is substituted in place of
|
||||
invalid code units.
|
||||
* To handle other cases, ripgrep provides a `-E/--encoding` flag, which permits
|
||||
you to specify an encoding from the
|
||||
[Encoding Standard](https://encoding.spec.whatwg.org/#concept-encoding-get).
|
||||
ripgrep will assume *all* files searched are the encoding specified and
|
||||
will perform a transcoding step just like in the UTF-16 case described above.
|
||||
ripgrep will assume *all* files searched are the encoding specified (unless
|
||||
the file has a BOM) and will perform a transcoding step just like in the
|
||||
UTF-16 case described above.
|
||||
|
||||
By default, ripgrep will not require its input be valid UTF-8. That is, ripgrep
|
||||
can and will search arbitrary bytes. The key here is that if you're searching
|
||||
@@ -635,9 +667,26 @@ pattern won't find anything. With all that said, this mode of operation is
|
||||
important, because it lets you find ASCII or UTF-8 *within* files that are
|
||||
otherwise arbitrary bytes.
|
||||
|
||||
As a special case, the `-E/--encoding` flag supports the value `none`, which
|
||||
will completely disable all encoding related logic, including BOM sniffing.
|
||||
When `-E/--encoding` is set to `none`, ripgrep will search the raw bytes of
|
||||
the underlying file with no transcoding step. For example, here's how you might
|
||||
search the raw UTF-16 encoding of the string `Шерлок`:
|
||||
|
||||
```
|
||||
$ rg '(?-u)\(\x045\x04@\x04;\x04>\x04:\x04' -E none -a some-utf16-file
|
||||
```
|
||||
|
||||
Of course, that's just an example meant to show how one can drop down into
|
||||
raw bytes. Namely, the simpler command works as you might expect automatically:
|
||||
|
||||
```
|
||||
$ rg 'Шерлок' some-utf16-file
|
||||
```
|
||||
|
||||
Finally, it is possible to disable ripgrep's Unicode support from within the
|
||||
pattern regular expression. For example, let's say you wanted `.` to match any
|
||||
byte rather than any Unicode codepoint. (You might want this while searching a
|
||||
regular expression. For example, let's say you wanted `.` to match any byte
|
||||
rather than any Unicode codepoint. (You might want this while searching a
|
||||
binary file, since `.` by default will not match invalid UTF-8.) You could do
|
||||
this by disabling Unicode via a regular expression flag:
|
||||
|
||||
@@ -654,6 +703,282 @@ $ rg '\w(?-u:\w)\w'
|
||||
```
|
||||
|
||||
|
||||
### Binary data
|
||||
|
||||
In addition to skipping hidden files and files in your `.gitignore` by default,
|
||||
ripgrep also attempts to skip binary files. ripgrep does this by default
|
||||
because binary files (like PDFs or images) are typically not things you want to
|
||||
search when searching for regex matches. Moreover, if content in a binary file
|
||||
did match, then it's possible for undesirable binary data to be printed to your
|
||||
terminal and wreak havoc.
|
||||
|
||||
Unfortunately, unlike skipping hidden files and respecting your `.gitignore`
|
||||
rules, a file cannot as easily be classified as binary. In order to figure out
|
||||
whether a file is binary, the most effective heuristic that balances
|
||||
correctness with performance is to simply look for `NUL` bytes. At that point,
|
||||
the determination is simple: a file is considered "binary" if and only if it
|
||||
contains a `NUL` byte somewhere in its contents.
|
||||
|
||||
The issue is that while most binary files will have a `NUL` byte toward the
|
||||
beginning of its contents, this is not necessarily true. The `NUL` byte might
|
||||
be the very last byte in a large file, but that file is still considered
|
||||
binary. While this leads to a fair amount of complexity inside ripgrep's
|
||||
implementation, it also results in some unintuitive user experiences.
|
||||
|
||||
At a high level, ripgrep operates in three different modes with respect to
|
||||
binary files:
|
||||
|
||||
1. The default mode is to attempt to remove binary files from a search
|
||||
completely. This is meant to mirror how ripgrep removes hidden files and
|
||||
files in your `.gitignore` automatically. That is, as soon as a file is
|
||||
detected as binary, searching stops. If a match was already printed (because
|
||||
it was detected long before a `NUL` byte), then ripgrep will print a warning
|
||||
message indicating that the search stopped prematurely. This default mode
|
||||
**only applies to files searched by ripgrep as a result of recursive
|
||||
directory traversal**, which is consistent with ripgrep's other automatic
|
||||
filtering. For example, `rg foo .file` will search `.file` even though it
|
||||
is hidden. Similarly, `rg foo binary-file` will search `binary-file` in
|
||||
"binary" mode automatically.
|
||||
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
|
||||
will continue searching a file that is known to be binary until the first
|
||||
of two conditions is met: 1) the end of the file has been reached or 2) a
|
||||
match is or has been seen. This means that in binary mode, if ripgrep
|
||||
reports no matches, then there are no matches in the file. When a match does
|
||||
occur, ripgrep prints a message similar to one it prints when in its default
|
||||
mode indicating that the search has stopped prematurely. This mode can be
|
||||
forcefully enabled for all files with the `--binary` flag. The purpose of
|
||||
binary mode is to provide a way to discover matches in all files, but to
|
||||
avoid having binary data dumped into your terminal.
|
||||
3. Text mode completely disables all binary detection and searches all files
|
||||
as if they were text. This is useful when searching a file that is
|
||||
predominantly text but contains a `NUL` byte, or if you are specifically
|
||||
trying to search binary data. This mode can be enabled with the `-a/--text`
|
||||
flag. Note that when using this mode on very large binary files, it is
|
||||
possible for ripgrep to use a lot of memory.
|
||||
|
||||
Unfortunately, there is one additional complexity in ripgrep that can make it
|
||||
difficult to reason about binary files. That is, the way binary detection works
|
||||
depends on the way that ripgrep searches your files. Specifically:
|
||||
|
||||
* When ripgrep uses memory maps, then binary detection is only performed on the
|
||||
first few kilobytes of the file in addition to every matching line.
|
||||
* When ripgrep doesn't use memory maps, then binary detection is performed on
|
||||
all bytes searched.
|
||||
|
||||
This means that whether a file is detected as binary or not can change based
|
||||
on the internal search strategy used by ripgrep. If you prefer to keep
|
||||
ripgrep's binary file detection consistent, then you can disable memory maps
|
||||
via the `--no-mmap` flag. (The cost will be a small performance regression when
|
||||
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
|
||||
|
||||
ripgrep has a lot of flags. Too many to keep in your head at once. This section
|
||||
@@ -668,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
|
||||
if the pattern contains any uppercase letters. Usually this flag is put into
|
||||
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
|
||||
by word boundaries. That is, given `pattern`, the `--word-regexp` flag will
|
||||
cause ripgrep to behave as if `pattern` were actually `\b(?:pattern)\b`.
|
||||
@@ -675,10 +1002,11 @@ 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
|
||||
search them.
|
||||
* `-a/--text`: Search binary files as if they were plain text.
|
||||
* `-z/--search-zip`: Search compressed files (gzip, bzip2, lzma, xz). This is
|
||||
disabled by default.
|
||||
* `-U/--multiline`: Permit matches to span multiple lines.
|
||||
* `-z/--search-zip`: Search compressed files (gzip, bzip2, lzma, xz, lz4,
|
||||
brotli, zstd). This is disabled by default.
|
||||
* `-C/--context`: Show the lines surrounding a match.
|
||||
* `--sort-files`: Force ripgrep to sort its output by file name. (This disables
|
||||
* `--sort path`: Force ripgrep to sort its output by file name. (This disables
|
||||
parallelism, so it might be slower.)
|
||||
* `-L/--follow`: Follow symbolic links while recursively searching.
|
||||
* `-M/--max-columns`: Limit the length of lines printed by ripgrep.
|
||||
|
||||
264
README.md
264
README.md
@@ -1,17 +1,18 @@
|
||||
ripgrep (rg)
|
||||
------------
|
||||
ripgrep is a line-oriented search tool that recursively searches your current
|
||||
directory for a regex pattern while respecting your gitignore rules. ripgrep
|
||||
has first class support on Windows, macOS and Linux, with binary downloads
|
||||
available for [every release](https://github.com/BurntSushi/ripgrep/releases).
|
||||
ripgrep is similar to other popular search tools like The Silver Searcher,
|
||||
ack and grep.
|
||||
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. (To disable
|
||||
all automatic filtering by default, use `rg -uuu`.) ripgrep has first class
|
||||
support on Windows, macOS and Linux, with binary downloads available for [every
|
||||
release](https://github.com/BurntSushi/ripgrep/releases). ripgrep is similar to
|
||||
other popular search tools like The Silver Searcher, ack and grep.
|
||||
|
||||
[](https://travis-ci.org/BurntSushi/ripgrep)
|
||||
[](https://ci.appveyor.com/project/BurntSushi/ripgrep)
|
||||
[](https://github.com/BurntSushi/ripgrep/actions)
|
||||
[](https://crates.io/crates/ripgrep)
|
||||
[](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
|
||||
@@ -27,60 +28,60 @@ Please see the [CHANGELOG](CHANGELOG.md) for a release history.
|
||||
* [Configuration files](GUIDE.md#configuration-file)
|
||||
* [Shell completions](FAQ.md#complete)
|
||||
* [Building](#building)
|
||||
* [Translations](#translations)
|
||||
|
||||
|
||||
### Screenshot of search results
|
||||
|
||||
[](http://burntsushi.net/stuff/ripgrep1.png)
|
||||
[](https://burntsushi.net/stuff/ripgrep1.png)
|
||||
|
||||
|
||||
### Quick examples comparing tools
|
||||
|
||||
This example searches the entire Linux kernel source tree (after running
|
||||
`make defconfig && make -j8`) for `[A-Z]+_SUSPEND`, where all matches must be
|
||||
words. Timings were collected on a system with an Intel i7-6900K 3.2 GHz, and
|
||||
ripgrep was compiled with SIMD enabled.
|
||||
This example searches the entire
|
||||
[Linux kernel source tree](https://github.com/BurntSushi/linux)
|
||||
(after running `make defconfig && make -j8`) for `[A-Z]+_SUSPEND`, where
|
||||
all matches must be words. Timings were collected on a system with an Intel
|
||||
i7-6900K 3.2 GHz.
|
||||
|
||||
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.
|
||||
|
||||
| Tool | Command | Line count | Time |
|
||||
| ---- | ------- | ---------- | ---- |
|
||||
| ripgrep (Unicode) | `rg -n -w '[A-Z]+_SUSPEND'` | 450 | **0.106s** |
|
||||
| [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 |
|
||||
| [The Silver Searcher](https://github.com/ggreer/the_silver_searcher) | `ag -w '[A-Z]+_SUSPEND'` | 450 | 0.589s |
|
||||
| [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 |
|
||||
| [sift](https://github.com/svent/sift) | `sift --git -n -w '[A-Z]+_SUSPEND'` | 450 | 3.505s |
|
||||
| [ack](https://github.com/petdance/ack2) | `ack -w '[A-Z]+_SUSPEND'` | 1878 | 6.823s |
|
||||
| [The Platinum Searcher](https://github.com/monochromegane/the_platinum_searcher) | `pt -w -e '[A-Z]+_SUSPEND'` | 450 | 14.208s |
|
||||
| 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) | `git grep -P -n -w '[A-Z]+_SUSPEND'` | 452 | 0.348s |
|
||||
| [ugrep (Unicode)](https://github.com/Genivia/ugrep) | `ugrep -r --ignore-files --no-hidden -I -w '[A-Z]+_SUSPEND'` | 452 | 0.506s |
|
||||
| [The Silver Searcher](https://github.com/ggreer/the_silver_searcher) | `ag -w '[A-Z]+_SUSPEND'` | 452 | 0.654s |
|
||||
| [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/beyondgrep/ack3) | `ack -w '[A-Z]+_SUSPEND'` | 452 | 4.054s |
|
||||
| [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
|
||||
[bug](https://github.com/petdance/ack2/issues/14).)
|
||||
|
||||
Here's another benchmark that disregards gitignore 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 doing equivalent work:
|
||||
Here's another benchmark on the same corpus as above that disregards gitignore
|
||||
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
|
||||
doing equivalent work:
|
||||
|
||||
| Tool | Command | Line count | Time |
|
||||
| ---- | ------- | ---------- | ---- |
|
||||
| ripgrep | `rg -L -u -tc -n -w '[A-Z]+_SUSPEND'` | 404 | **0.079s** |
|
||||
| [ucg](https://github.com/gvansickle/ucg) | `ucg --type=cc -w '[A-Z]+_SUSPEND'` | 390 | 0.163s |
|
||||
| [GNU grep](https://www.gnu.org/software/grep/) | `egrep -R -n --include='*.c' --include='*.h' -w '[A-Z]+_SUSPEND'` | 404 | 0.611s |
|
||||
| ripgrep | `rg -uuu -tc -n -w '[A-Z]+_SUSPEND'` | 388 | **0.096s** |
|
||||
| [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'` | 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 and GNU grep on a single
|
||||
large file (~9.3GB,
|
||||
[`OpenSubtitles2016.raw.en.gz`](http://opus.lingfil.uu.se/OpenSubtitles2016/mono/OpenSubtitles2016.raw.en.gz)):
|
||||
And finally, a straight-up comparison between ripgrep, ugrep and GNU grep on a
|
||||
single large file cached in memory
|
||||
(~13GB, [`OpenSubtitles.raw.en.gz`](http://opus.nlpl.eu/download.php?f=OpenSubtitles/v2018/mono/OpenSubtitles.raw.en.gz)):
|
||||
|
||||
| Tool | Command | Line count | Time |
|
||||
| ---- | ------- | ---------- | ---- |
|
||||
| ripgrep | `rg -w 'Sherlock [A-Z]\w+'` | 5268 | **2.108s** |
|
||||
| [GNU grep](https://www.gnu.org/software/grep/) | `LC_ALL=C egrep -w 'Sherlock [A-Z]\w+'` | 5268 | 7.014s |
|
||||
| ripgrep | `rg -w 'Sherlock [A-Z]\w+'` | 7882 | **2.769s** |
|
||||
| [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)
|
||||
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?
|
||||
@@ -89,33 +90,40 @@ 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
|
||||
[the FAQ](FAQ.md#posix4ever) for more details on whether ripgrep can truly
|
||||
replace grep.)
|
||||
* Like other tools specialized to code search, ripgrep defaults to recursive
|
||||
directory search and won't search files ignored by your `.gitignore` files.
|
||||
It also ignores hidden and binary files by default. ripgrep also implements
|
||||
full support for `.gitignore`, whereas there are many bugs related to that
|
||||
functionality in other code search tools claiming to provide the same
|
||||
functionality.
|
||||
* ripgrep can search specific types of files. For example, `rg -tpy foo`
|
||||
limits your search to Python files and `rg -Tjs foo` excludes Javascript
|
||||
files from your search. ripgrep can be taught about new file types with
|
||||
custom matching rules.
|
||||
* Like other tools specialized to code search, ripgrep defaults to
|
||||
[recursive search](GUIDE.md#recursive-search) and does [automatic
|
||||
filtering](GUIDE.md#automatic-filtering). Namely, ripgrep won't search files
|
||||
ignored by your `.gitignore`/`.ignore`/`.rgignore` files, it won't search
|
||||
hidden files and it won't search binary files. Automatic filtering can be
|
||||
disabled with `rg -uuu`.
|
||||
* ripgrep can [search specific types of files](GUIDE.md#manual-filtering-file-types).
|
||||
For example, `rg -tpy foo` limits your search to Python files and `rg -Tjs
|
||||
foo` excludes JavaScript files from your search. ripgrep can be taught about
|
||||
new file types with custom matching rules.
|
||||
* ripgrep supports many features found in `grep`, such as showing the context
|
||||
of search results, searching multiple patterns, highlighting matches with
|
||||
color and full Unicode support. Unlike GNU grep, ripgrep stays fast while
|
||||
supporting Unicode (which is always on).
|
||||
* ripgrep has optional support for switching its regex engine to use PCRE2.
|
||||
Among other things, this makes it possible to use look-around and
|
||||
backreferences in your patterns, which are supported in ripgrep's default
|
||||
regex engine. PCRE2 support is enabled with `-P`.
|
||||
* ripgrep supports searching files in text encodings other than UTF-8, such
|
||||
as UTF-16, latin-1, GBK, EUC-JP, Shift_JIS and more. (Some support for
|
||||
automatically detecting UTF-16 is provided. Other text encodings must be
|
||||
specifically specified with the `-E/--encoding` flag.)
|
||||
* ripgrep supports searching files compressed in a common format (gzip, xz,
|
||||
lzma, bzip2 or lz4) with the `-z/--search-zip` flag.
|
||||
* ripgrep supports arbitrary input preprocessing filters which could be PDF
|
||||
text extraction, less supported decompression, decrypting, automatic encoding
|
||||
detection and so on.
|
||||
backreferences in your patterns, which are not supported in ripgrep's default
|
||||
regex engine. PCRE2 support can be enabled with `-P/--pcre2` (use PCRE2
|
||||
always) or `--auto-hybrid-regex` (use PCRE2 only if needed). An alternative
|
||||
syntax is provided via the `--engine (default|pcre2|auto-hybrid)` option.
|
||||
* ripgrep has [rudimentary support for replacements](GUIDE.md#replacements),
|
||||
which permit rewriting output based on what was matched.
|
||||
* ripgrep supports [searching files in text encodings](GUIDE.md#file-encoding)
|
||||
other than UTF-8, such as UTF-16, latin-1, GBK, EUC-JP, Shift_JIS and more.
|
||||
(Some support for automatically detecting UTF-16 is provided. Other text
|
||||
encodings must be specifically specified with the `-E/--encoding` flag.)
|
||||
* ripgrep supports searching files compressed in a common format (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
|
||||
bugs and Unicode support.
|
||||
@@ -146,12 +154,12 @@ or more of the following:
|
||||
### Is it really faster than everything else?
|
||||
|
||||
Generally, yes. A large number of benchmarks with detailed analysis for each is
|
||||
[available on my blog](http://blog.burntsushi.net/ripgrep/).
|
||||
[available on my blog](https://blog.burntsushi.net/ripgrep/).
|
||||
|
||||
Summarizing, ripgrep is fast because:
|
||||
|
||||
* 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
|
||||
optimizations to make searching very fast. (PCRE2 support can be opted into
|
||||
with the `-P/--pcre2` flag.)
|
||||
@@ -188,32 +196,17 @@ multiline search and opt-in fancy regex support via PCRE2.
|
||||
The binary name for ripgrep is `rg`.
|
||||
|
||||
**[Archives of precompiled binaries for ripgrep are available for Windows,
|
||||
macOS and Linux.](https://github.com/BurntSushi/ripgrep/releases)** Users of
|
||||
platforms not explicitly mentioned below are advised to download one of these
|
||||
archives.
|
||||
macOS and Linux.](https://github.com/BurntSushi/ripgrep/releases)** Linux and
|
||||
Windows binaries are static executables. Users of platforms not explicitly
|
||||
mentioned below are advised to download one of these archives.
|
||||
|
||||
Linux binaries are static executables. Windows binaries are available either as
|
||||
built with MinGW (GNU) or with Microsoft Visual C++ (MSVC). When possible,
|
||||
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):
|
||||
If you're a **macOS Homebrew** or a **Linuxbrew** user, then you can install
|
||||
ripgrep from homebrew-core:
|
||||
|
||||
```
|
||||
$ 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
|
||||
[official ports](https://www.macports.org/ports.php?by=name&substr=ripgrep):
|
||||
|
||||
@@ -229,7 +222,7 @@ $ choco install ripgrep
|
||||
```
|
||||
|
||||
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
|
||||
@@ -248,29 +241,21 @@ If you're a **Gentoo** user, you can install ripgrep from the
|
||||
$ emerge sys-apps/ripgrep
|
||||
```
|
||||
|
||||
If you're a **Fedora 27+** user, you can install ripgrep from official
|
||||
If you're a **Fedora** user, you can install ripgrep from official
|
||||
repositories.
|
||||
|
||||
```
|
||||
$ sudo dnf install ripgrep
|
||||
```
|
||||
|
||||
If you're a **Fedora 24+** user, you can install ripgrep from
|
||||
[copr](https://copr.fedorainfracloud.org/coprs/carlwgeorge/ripgrep/):
|
||||
|
||||
```
|
||||
$ sudo dnf copr enable carlwgeorge/ripgrep
|
||||
$ sudo dnf install ripgrep
|
||||
```
|
||||
|
||||
If you're an **openSUSE Tumbleweed** user, you can install ripgrep from the
|
||||
[official repo](http://software.opensuse.org/package/ripgrep):
|
||||
If you're an **openSUSE** user, ripgrep is included in **openSUSE Tumbleweed**
|
||||
and **openSUSE Leap** since 15.1.
|
||||
|
||||
```
|
||||
$ 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/):
|
||||
|
||||
```
|
||||
@@ -286,22 +271,36 @@ $ nix-env --install 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**),
|
||||
then ripgrep can be installed using a binary `.deb` file provided in each
|
||||
[ripgrep release](https://github.com/BurntSushi/ripgrep/releases). Note that
|
||||
ripgrep is not in the official Debian or Ubuntu repositories.
|
||||
[ripgrep release](https://github.com/BurntSushi/ripgrep/releases).
|
||||
|
||||
```
|
||||
$ curl -LO https://github.com/BurntSushi/ripgrep/releases/download/0.9.0/ripgrep_0.9.0_amd64.deb
|
||||
$ sudo dpkg -i ripgrep_0.9.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_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).
|
||||
```
|
||||
$ sudo apt-get install ripgrep
|
||||
```
|
||||
|
||||
If you're an **Ubuntu Cosmic (18.10)** (or newer) user, ripgrep is
|
||||
[available](https://launchpad.net/ubuntu/+source/rust-ripgrep) using the same
|
||||
packaging as Debian:
|
||||
|
||||
```
|
||||
$ sudo apt-get install ripgrep
|
||||
```
|
||||
|
||||
(N.B. Various snaps for ripgrep on Ubuntu are also available, but none of them
|
||||
seem to work right and generate a number of very strange bug reports that I
|
||||
don't know how to fix and don't have the time to fix. Therefore, it is no
|
||||
@@ -315,22 +314,36 @@ 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
|
||||
[official ports](http://openports.se/textproc/ripgrep):
|
||||
[official ports](https://openports.se/textproc/ripgrep):
|
||||
|
||||
```
|
||||
$ doas pkg_add ripgrep
|
||||
```
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
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`.
|
||||
|
||||
* Note that the minimum supported version of Rust for ripgrep is **1.28.0**,
|
||||
* Note that the minimum supported version of Rust for ripgrep is **1.34.0**,
|
||||
although ripgrep may work with older versions.
|
||||
* Note that the binary may be bigger than expected because it contains debug
|
||||
symbols. This is intentional. To remove debug symbols and therefore reduce
|
||||
@@ -340,18 +353,12 @@ If you're a **Rust programmer**, ripgrep can be installed with `cargo`.
|
||||
$ cargo install ripgrep
|
||||
```
|
||||
|
||||
When compiling with Rust 1.27 or newer, this will automatically enable SIMD
|
||||
optimizations for search.
|
||||
|
||||
ripgrep isn't currently in any other package repositories.
|
||||
[I'd like to change that](https://github.com/BurntSushi/ripgrep/issues/10).
|
||||
|
||||
|
||||
### Building
|
||||
|
||||
ripgrep is written in Rust, so you'll need to grab a
|
||||
[Rust installation](https://www.rust-lang.org/) in order to compile it.
|
||||
ripgrep compiles with Rust 1.28.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.
|
||||
|
||||
To build ripgrep:
|
||||
@@ -368,18 +375,14 @@ If you have a Rust nightly compiler and a recent Intel CPU, then you can enable
|
||||
additional optional SIMD acceleration like so:
|
||||
|
||||
```
|
||||
RUSTFLAGS="-C target-cpu=native" cargo build --release --features 'simd-accel avx-accel'
|
||||
RUSTFLAGS="-C target-cpu=native" cargo build --release --features 'simd-accel'
|
||||
```
|
||||
|
||||
If your machine doesn't support AVX instructions, then simply remove
|
||||
`avx-accel` from the features list. Similarly for SIMD (which corresponds
|
||||
roughly to SSE instructions).
|
||||
|
||||
The `simd-accel` and `avx-accel` features enable SIMD support in certain
|
||||
ripgrep dependencies (responsible for counting lines and transcoding). They
|
||||
are not necessary to get SIMD optimizations for search; those are enabled
|
||||
automatically. Hopefully, some day, the `simd-accel` and `avx-accel` features
|
||||
will similarly become unnecessary.
|
||||
The `simd-accel` feature enables SIMD support in certain ripgrep dependencies
|
||||
(responsible for transcoding). They are not necessary to get SIMD optimizations
|
||||
for search; those are enabled automatically. Hopefully, some day, the
|
||||
`simd-accel` feature will similarly become unnecessary. **WARNING:** Currently,
|
||||
enabling this option can increase compilation times dramatically.
|
||||
|
||||
Finally, optional PCRE2 support can be built with ripgrep by enabling the
|
||||
`pcre2` feature:
|
||||
@@ -388,8 +391,8 @@ Finally, optional PCRE2 support can be built with ripgrep by enabling the
|
||||
$ cargo build --release --features 'pcre2'
|
||||
```
|
||||
|
||||
(Tip: use `--features 'pcre2 simd-accel avx-accel'` to also include compile
|
||||
time SIMD optimizations, which will only work with a nightly compiler.)
|
||||
(Tip: use `--features 'pcre2 simd-accel'` to also include compile time SIMD
|
||||
optimizations, which will only work with a nightly compiler.)
|
||||
|
||||
Enabling the PCRE2 feature works with a stable Rust compiler and will
|
||||
attempt to automatically find and link with your system's PCRE2 library via
|
||||
@@ -425,3 +428,20 @@ $ cargo test --all
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
SUBTITLES_DIR = 'subtitles'
|
||||
SUBTITLES_EN_NAME = 'OpenSubtitles2016.raw.en'
|
||||
SUBTITLES_EN_NAME_SAMPLE = 'OpenSubtitles2016.raw.sample.en'
|
||||
SUBTITLES_EN_NAME = 'en.txt'
|
||||
SUBTITLES_EN_NAME_SAMPLE = 'en.sample.txt'
|
||||
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_RU_NAME = 'OpenSubtitles2016.raw.ru'
|
||||
SUBTITLES_EN_URL = 'https://object.pouta.csc.fi/OPUS-OpenSubtitles/v2016/mono/en.txt.gz' # noqa
|
||||
SUBTITLES_RU_NAME = 'ru.txt'
|
||||
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_CLONE = 'git://github.com/BurntSushi/linux'
|
||||
LINUX_CLONE = 'https://github.com/BurntSushi/linux'
|
||||
|
||||
# Grep takes locale settings from the environment. There is a *substantial*
|
||||
# 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.
|
||||
|
||||
This is a purposefully unfair benchmark for use in performance
|
||||
analysis, but it is pedagogically useful to demonstrate how
|
||||
default behaviors differ.
|
||||
analysis, but it is pedagogically useful to demonstrate how default
|
||||
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')
|
||||
cwd = path.join(suite_dir, LINUX_DIR)
|
||||
@@ -69,16 +71,11 @@ def bench_linux_literal_default(suite_dir):
|
||||
return Benchmark(pattern=pat, commands=[
|
||||
mkcmd('rg', ['rg', 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
|
||||
# default, but I'd guess it to be on most desktop systems.
|
||||
mkcmd('pt', ['pt', pat]),
|
||||
# sift reports an extra line here for a binary file matched.
|
||||
mkcmd('sift', ['sift', pat]),
|
||||
mkcmd('git grep', ['git', 'grep', pat], env={'LC_ALL': 'en_US.UTF-8'}),
|
||||
mkcmd('git grep', ['git', 'grep', pat], env=GREP_UNICODE),
|
||||
mkcmd('ugrep', ['ugrep', '-r', pat, './']),
|
||||
mkcmd('grep', ['grep', '-r', pat, './'], env=GREP_UNICODE),
|
||||
])
|
||||
|
||||
|
||||
@@ -100,16 +97,16 @@ def bench_linux_literal(suite_dir):
|
||||
return Command(*args, **kwargs)
|
||||
|
||||
return Benchmark(pattern=pat, commands=[
|
||||
mkcmd('rg (ignore)', ['rg', '-n', pat]),
|
||||
mkcmd('rg (ignore) (mmap)', ['rg', '-n', '--mmap', pat]),
|
||||
mkcmd('ag (ignore) (mmap)', ['ag', '-s', pat]),
|
||||
mkcmd('pt (ignore)', ['pt', pat]),
|
||||
mkcmd('sift (ignore)', SIFT + ['-n', '--git', pat]),
|
||||
mkcmd('git grep (ignore)', [
|
||||
mkcmd('rg', ['rg', '-n', pat]),
|
||||
mkcmd('rg (mmap)', ['rg', '-n', '--mmap', pat]),
|
||||
mkcmd('ag (mmap)', ['ag', '-s', pat]),
|
||||
mkcmd('git grep', [
|
||||
'git', 'grep', '-I', '-n', pat,
|
||||
], env={'LC_ALL': 'C'}),
|
||||
mkcmd('rg (whitelist)', ['rg', '-n', '--no-ignore', '-tall', pat]),
|
||||
mkcmd('ucg (whitelist)', ['ucg', '--nosmart-case', pat]),
|
||||
mkcmd('ugrep', [
|
||||
'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 Benchmark(pattern=pat, commands=[
|
||||
mkcmd('rg (ignore)', ['rg', '-n', '-i', pat]),
|
||||
mkcmd('rg (ignore) (mmap)', ['rg', '-n', '-i', '--mmap', pat]),
|
||||
mkcmd('ag (ignore) (mmap)', ['ag', '-i', pat]),
|
||||
mkcmd('pt (ignore)', ['pt', '-i', pat]),
|
||||
mkcmd('sift (ignore)', SIFT + ['-n', '-i', '--git', pat]),
|
||||
mkcmd('rg', ['rg', '-n', '-i', pat]),
|
||||
mkcmd('rg (mmap)', ['rg', '-n', '-i', '--mmap', pat]),
|
||||
mkcmd('ag (mmap)', ['ag', '-i', pat]),
|
||||
# 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
|
||||
# ASCII literal, so we should give `git grep` all the opportunity to
|
||||
# do its best.
|
||||
mkcmd('git grep (ignore)', [
|
||||
mkcmd('git grep', [
|
||||
'git', 'grep', '-I', '-n', '-i', pat,
|
||||
], env={'LC_ALL': 'C'}),
|
||||
mkcmd('rg (whitelist)', [
|
||||
'rg', '-n', '-i', '--no-ignore', '-tall', pat,
|
||||
]),
|
||||
mkcmd('ucg (whitelist)', ['ucg', '-i', pat]),
|
||||
mkcmd('ugrep', [
|
||||
'ugrep', '-r', '--ignore-files', '--no-hidden', '-I',
|
||||
'-n', '-i', pat, './',
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
def bench_linux_re_literal_suffix(suite_dir):
|
||||
'''
|
||||
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')
|
||||
cwd = path.join(suite_dir, LINUX_DIR)
|
||||
@@ -164,26 +156,23 @@ def bench_linux_re_literal_suffix(suite_dir):
|
||||
return Command(*args, **kwargs)
|
||||
|
||||
return Benchmark(pattern=pat, commands=[
|
||||
mkcmd('rg (ignore)', ['rg', '-n', pat]),
|
||||
mkcmd('ag (ignore)', ['ag', '-s', pat]),
|
||||
mkcmd('pt (ignore)', ['pt', '-e', pat]),
|
||||
mkcmd('sift (ignore)', SIFT + ['-n', '--git', pat]),
|
||||
mkcmd('rg', ['rg', '-n', pat]),
|
||||
mkcmd('ag', ['ag', '-s', pat]),
|
||||
mkcmd(
|
||||
'git grep (ignore)',
|
||||
'git grep',
|
||||
['git', 'grep', '-E', '-I', '-n', pat],
|
||||
env={'LC_ALL': 'C'},
|
||||
),
|
||||
mkcmd('rg (whitelist)', ['rg', '-n', '--no-ignore', '-tall', pat]),
|
||||
mkcmd('ucg (whitelist)', ['ucg', '--nosmart-case', pat]),
|
||||
mkcmd('ugrep', [
|
||||
'ugrep', '-r', '--ignore-files', '--no-hidden', '-I',
|
||||
'-n', pat, './',
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
def bench_linux_word(suite_dir):
|
||||
'''
|
||||
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')
|
||||
cwd = path.join(suite_dir, LINUX_DIR)
|
||||
@@ -194,28 +183,23 @@ def bench_linux_word(suite_dir):
|
||||
return Command(*args, **kwargs)
|
||||
|
||||
return Benchmark(pattern=pat, commands=[
|
||||
mkcmd('rg (ignore)', ['rg', '-n', '-w', pat]),
|
||||
mkcmd('ag (ignore)', ['ag', '-s', '-w', pat]),
|
||||
mkcmd('pt (ignore)', ['pt', '-w', pat]),
|
||||
mkcmd('sift (ignore)', SIFT + ['-n', '-w', '--git', pat]),
|
||||
mkcmd('rg', ['rg', '-n', '-w', pat]),
|
||||
mkcmd('ag', ['ag', '-s', '-w', pat]),
|
||||
mkcmd(
|
||||
'git grep (ignore)',
|
||||
'git grep',
|
||||
['git', 'grep', '-E', '-I', '-n', '-w', pat],
|
||||
env={'LC_ALL': 'C'},
|
||||
),
|
||||
mkcmd('rg (whitelist)', [
|
||||
'rg', '-n', '-w', '--no-ignore', '-tall', pat,
|
||||
]),
|
||||
mkcmd('ucg (whitelist)', ['ucg', '--nosmart-case', '-w', pat]),
|
||||
mkcmd('ugrep', [
|
||||
'ugrep', '-r', '--ignore-files', '--no-hidden', '-I',
|
||||
'-n', '-w', pat, './',
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
def bench_linux_unicode_greek(suite_dir):
|
||||
'''
|
||||
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')
|
||||
cwd = path.join(suite_dir, LINUX_DIR)
|
||||
@@ -227,8 +211,10 @@ def bench_linux_unicode_greek(suite_dir):
|
||||
|
||||
return Benchmark(pattern=pat, commands=[
|
||||
mkcmd('rg', ['rg', '-n', pat]),
|
||||
mkcmd('pt', ['pt', '-e', pat]),
|
||||
mkcmd('sift', SIFT + ['-n', '--git', pat]),
|
||||
mkcmd('ugrep', [
|
||||
'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=[
|
||||
mkcmd('rg', ['rg', '-n', '-i', pat]),
|
||||
mkcmd('pt', ['pt', '-i', '-e', pat]),
|
||||
mkcmd('sift', SIFT + ['-n', '-i', '--git', pat]),
|
||||
mkcmd('ugrep', [
|
||||
'ugrep', '-r', '--ignore-files', '--no-hidden', '-I',
|
||||
'-n', '-i', pat, './',
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
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
|
||||
this right. Everything else uses the standard ASCII interpretation
|
||||
of \w.
|
||||
of \\w.
|
||||
'''
|
||||
require(suite_dir, 'linux')
|
||||
cwd = path.join(suite_dir, LINUX_DIR)
|
||||
@@ -270,26 +258,27 @@ def bench_linux_unicode_word(suite_dir):
|
||||
return Command(*args, **kwargs)
|
||||
|
||||
return Benchmark(pattern=pat, commands=[
|
||||
mkcmd('rg (ignore)', ['rg', '-n', pat]),
|
||||
mkcmd('rg (ignore) (ASCII)', ['rg', '-n', '(?-u)' + pat]),
|
||||
mkcmd('ag (ignore) (ASCII)', ['ag', '-s', pat]),
|
||||
mkcmd('pt (ignore) (ASCII)', ['pt', '-e', pat]),
|
||||
mkcmd('sift (ignore) (ASCII)', SIFT + ['-n', '--git', pat]),
|
||||
mkcmd('rg', ['rg', '-n', pat]),
|
||||
mkcmd('rg (ASCII)', ['rg', '-n', '(?-u)' + pat]),
|
||||
mkcmd('ag (ASCII)', ['ag', '-s', pat]),
|
||||
mkcmd(
|
||||
'git grep (ignore)',
|
||||
'git grep',
|
||||
['git', 'grep', '-E', '-I', '-n', pat],
|
||||
env={'LC_ALL': 'en_US.UTF-8'},
|
||||
),
|
||||
mkcmd(
|
||||
'git grep (ignore) (ASCII)',
|
||||
'git grep (ASCII)',
|
||||
['git', 'grep', '-E', '-I', '-n', pat],
|
||||
env={'LC_ALL': 'C'},
|
||||
),
|
||||
mkcmd('rg (whitelist)', ['rg', '-n', '--no-ignore', '-tall', pat]),
|
||||
mkcmd('rg (whitelist) (ASCII)', [
|
||||
'rg', '-n', '--no-ignore', '-tall', '(?-u)' + pat,
|
||||
mkcmd('ugrep', [
|
||||
'ugrep', '-r', '--ignore-files', '--no-hidden', '-I',
|
||||
'-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 Benchmark(pattern=pat, commands=[
|
||||
mkcmd('rg (ignore)', ['rg', '-n', pat]),
|
||||
mkcmd('rg (ignore) (ASCII)', ['rg', '-n', '(?-u)' + pat]),
|
||||
mkcmd('ag (ignore) (ASCII)', ['ag', '-s', pat]),
|
||||
mkcmd('pt (ignore) (ASCII)', ['pt', '-e', pat]),
|
||||
mkcmd('sift (ignore) (ASCII)', SIFT + ['-n', '--git', pat]),
|
||||
mkcmd('rg', ['rg', '-n', pat]),
|
||||
mkcmd('rg (ASCII)', ['rg', '-n', '(?-u)' + pat]),
|
||||
mkcmd('ag (ASCII)', ['ag', '-s', pat]),
|
||||
mkcmd(
|
||||
'git grep (ignore)',
|
||||
'git grep',
|
||||
['git', 'grep', '-E', '-I', '-n', pat],
|
||||
env={'LC_ALL': 'en_US.UTF-8'},
|
||||
),
|
||||
mkcmd(
|
||||
'git grep (ignore) (ASCII)',
|
||||
'git grep (ASCII)',
|
||||
['git', 'grep', '-E', '-I', '-n', pat],
|
||||
env={'LC_ALL': 'C'},
|
||||
),
|
||||
mkcmd('rg (whitelist)', ['rg', '-n', '--no-ignore', '-tall', pat]),
|
||||
mkcmd('rg (whitelist) (ASCII)', [
|
||||
'rg', '-n', '--no-ignore', '-tall', '(?-u)' + pat,
|
||||
mkcmd('ugrep', [
|
||||
'ugrep', '-r', '--ignore-files', '--no-hidden', '-I',
|
||||
'-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 Benchmark(pattern=pat, commands=[
|
||||
mkcmd('rg (ignore)', ['rg', '-n', pat]),
|
||||
mkcmd('ag (ignore)', ['ag', '-s', pat]),
|
||||
mkcmd('rg', ['rg', '-n', pat]),
|
||||
mkcmd('ag', ['ag', '-s', pat]),
|
||||
mkcmd(
|
||||
'git grep (ignore)',
|
||||
'git grep',
|
||||
['git', 'grep', '-E', '-I', '-n', pat],
|
||||
env={'LC_ALL': 'C'},
|
||||
),
|
||||
mkcmd('rg (whitelist)', ['rg', '--no-ignore', '-n', pat]),
|
||||
mkcmd('ucg (whitelist)', ['ucg', '--nosmart-case', pat]),
|
||||
mkcmd('ugrep', [
|
||||
'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 Benchmark(pattern=pat, commands=[
|
||||
mkcmd('rg (ignore)', ['rg', '-n', '-i', pat]),
|
||||
mkcmd('ag (ignore)', ['ag', '-i', pat]),
|
||||
mkcmd('rg', ['rg', '-n', '-i', pat]),
|
||||
mkcmd('ag', ['ag', '-i', pat]),
|
||||
mkcmd(
|
||||
'git grep (ignore)',
|
||||
'git grep',
|
||||
['git', 'grep', '-E', '-I', '-n', '-i', pat],
|
||||
env={'LC_ALL': 'C'},
|
||||
),
|
||||
mkcmd('rg (whitelist)', ['rg', '--no-ignore', '-n', '-i', pat]),
|
||||
mkcmd('ucg (whitelist)', ['ucg', '-i', pat]),
|
||||
mkcmd('ugrep', [
|
||||
'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=[
|
||||
Command('rg', ['rg', pat, en]),
|
||||
Command('rg (no mmap)', ['rg', '--no-mmap', pat, en]),
|
||||
Command('pt', ['pt', '-N', pat, en]),
|
||||
Command('sift', ['sift', pat, en]),
|
||||
Command('grep', ['grep', '-a', pat, en], env=GREP_ASCII),
|
||||
Command('grep', ['grep', pat, en], env=GREP_ASCII),
|
||||
Command('rg (lines)', ['rg', '-n', pat, en]),
|
||||
Command('ag (lines)', ['ag', '-s', pat, en]),
|
||||
Command('ucg (lines)', ['ucg', '--nosmart-case', pat, en]),
|
||||
Command('pt (lines)', ['pt', pat, en]),
|
||||
Command('sift (lines)', ['sift', '-n', pat, en]),
|
||||
Command('grep (lines)', ['grep', '-an', pat, en], env=GREP_ASCII),
|
||||
Command('grep (lines)', ['grep', '-n', pat, en], env=GREP_ASCII),
|
||||
Command('ugrep (lines)', ['ugrep', '-n', pat, en])
|
||||
])
|
||||
|
||||
|
||||
@@ -420,13 +410,11 @@ def bench_subtitles_en_literal_casei(suite_dir):
|
||||
|
||||
return Benchmark(pattern=pat, commands=[
|
||||
Command('rg', ['rg', '-i', pat, en]),
|
||||
Command('grep', ['grep', '-ai', pat, en], env=GREP_UNICODE),
|
||||
Command('grep (ASCII)', [
|
||||
'grep', '-E', '-ai', pat, en,
|
||||
], env=GREP_ASCII),
|
||||
Command('grep', ['grep', '-i', pat, en], env=GREP_UNICODE),
|
||||
Command('grep (ASCII)', ['grep', '-E', '-i', pat, en], env=GREP_ASCII),
|
||||
Command('rg (lines)', ['rg', '-n', '-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,
|
||||
]),
|
||||
Command('ag (ASCII)', ['ag', '-sw', pat, en]),
|
||||
Command('ucg (ASCII)', ['ucg', '--nosmart-case', pat, en]),
|
||||
Command('grep (ASCII)', [
|
||||
'grep', '-anw', pat, en,
|
||||
], env=GREP_ASCII),
|
||||
Command('grep (ASCII)', ['grep', '-nw', pat, en], env=GREP_ASCII),
|
||||
Command('ugrep (ASCII)', ['ugrep', '-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=[
|
||||
Command('rg (lines)', ['rg', '-n', pat, en]),
|
||||
Command('ag (lines)', ['ag', '-s', pat, en]),
|
||||
Command('ucg (lines)', ['ucg', '--nosmart-case', pat, en]),
|
||||
Command('grep (lines)', [
|
||||
'grep', '-E', '-an', pat, en,
|
||||
], env=GREP_ASCII),
|
||||
Command('grep (lines)', ['grep', '-E', '-n', pat, en], env=GREP_ASCII),
|
||||
Command('ugrep (lines)', ['ugrep', '-n', pat, en]),
|
||||
Command('rg', ['rg', pat, en]),
|
||||
Command('grep', [
|
||||
'grep', '-E', '-a', pat, en,
|
||||
], env=GREP_ASCII),
|
||||
Command('grep', ['grep', '-E', pat, en], env=GREP_ASCII),
|
||||
])
|
||||
|
||||
|
||||
@@ -496,12 +478,12 @@ def bench_subtitles_en_alternate_casei(suite_dir):
|
||||
|
||||
return Benchmark(pattern=pat, commands=[
|
||||
Command('ag (ASCII)', ['ag', '-s', '-i', pat, en]),
|
||||
Command('ucg (ASCII)', ['ucg', '-i', pat, en]),
|
||||
Command('grep (ASCII)', [
|
||||
'grep', '-E', '-ani', pat, en,
|
||||
'grep', '-E', '-ni', pat, en,
|
||||
], env=GREP_ASCII),
|
||||
Command('ugrep (ASCII)', ['ugrep', '-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=[
|
||||
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('ag (ASCII)', ['ag', '-s', pat, en]),
|
||||
Command('ucg (ASCII)', ['ucg', '--nosmart-case', pat, en]),
|
||||
Command('grep (ASCII)', [
|
||||
'grep', '-E', '-an', pat, en,
|
||||
], env=GREP_ASCII),
|
||||
Command('grep (ASCII)', ['grep', '-E', '-n', pat, en], env=GREP_ASCII),
|
||||
Command('ugrep (ASCII)', ['ugrep', '-n', '-U', pat, en])
|
||||
])
|
||||
|
||||
|
||||
@@ -540,12 +521,11 @@ def bench_subtitles_en_no_literal(suite_dir):
|
||||
|
||||
return Benchmark(pattern=pat, commands=[
|
||||
Command('rg', ['rg', '-n', pat, en]),
|
||||
Command('ugrep', ['ugrep', '-n', pat, en]),
|
||||
Command('rg (ASCII)', ['rg', '-n', '(?-u)' + pat, en]),
|
||||
Command('ag (ASCII)', ['ag', '-s', pat, en]),
|
||||
Command('ucg (ASCII)', ['ucg', '--nosmart-case', pat, en]),
|
||||
Command('grep (ASCII)', [
|
||||
'grep', '-E', '-an', pat, en,
|
||||
], env=GREP_ASCII),
|
||||
Command('grep (ASCII)', ['grep', '-E', '-n', pat, en], env=GREP_ASCII),
|
||||
Command('ugrep (ASCII)', ['ugrep', '-n', '-U', pat, en])
|
||||
])
|
||||
|
||||
|
||||
@@ -560,15 +540,15 @@ def bench_subtitles_ru_literal(suite_dir):
|
||||
return Benchmark(pattern=pat, commands=[
|
||||
Command('rg', ['rg', pat, ru]),
|
||||
Command('rg (no mmap)', ['rg', '--no-mmap', pat, ru]),
|
||||
Command('pt', ['pt', '-N', pat, ru]),
|
||||
Command('sift', ['sift', pat, ru]),
|
||||
Command('grep', ['grep', '-a', pat, ru], env=GREP_ASCII),
|
||||
Command('grep', ['grep', pat, ru], env=GREP_ASCII),
|
||||
Command('rg (lines)', ['rg', '-n', pat, ru]),
|
||||
Command('ag (lines)', ['ag', '-s', pat, ru]),
|
||||
Command('ucg (lines)', ['ucg', '--nosmart-case', pat, ru]),
|
||||
Command('pt (lines)', ['pt', pat, ru]),
|
||||
Command('sift (lines)', ['sift', '-n', pat, ru]),
|
||||
Command('grep (lines)', ['grep', '-an', pat, ru], env=GREP_ASCII),
|
||||
Command('grep (lines)', ['grep', '-n', pat, ru], env=GREP_ASCII),
|
||||
# ugrep incorrectly identifies this corpus as binary, but it is
|
||||
# entirely valid UTF-8. So we tell ugrep to always treat the corpus
|
||||
# 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=[
|
||||
Command('rg', ['rg', '-i', pat, ru]),
|
||||
Command('grep', ['grep', '-ai', pat, ru], env=GREP_UNICODE),
|
||||
Command('grep (ASCII)', [
|
||||
'grep', '-E', '-ai', pat, ru,
|
||||
], env=GREP_ASCII),
|
||||
Command('grep', ['grep', '-i', pat, ru], env=GREP_UNICODE),
|
||||
Command('grep (ASCII)', ['grep', '-E', '-i', pat, ru], env=GREP_ASCII),
|
||||
Command('rg (lines)', ['rg', '-n', '-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=[
|
||||
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('ucg (ASCII)', ['ucg', '--nosmart-case', pat, ru]),
|
||||
Command('grep (ASCII)', [
|
||||
'grep', '-anw', pat, ru,
|
||||
'grep', '-nw', pat, ru,
|
||||
], 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('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=[
|
||||
Command('rg (lines)', ['rg', '-n', pat, ru]),
|
||||
Command('ag (lines)', ['ag', '-s', pat, ru]),
|
||||
Command('ucg (lines)', ['ucg', '--nosmart-case', pat, ru]),
|
||||
Command('grep (lines)', [
|
||||
'grep', '-E', '-an', pat, ru,
|
||||
], env=GREP_ASCII),
|
||||
Command('grep (lines)', ['grep', '-E', '-n', pat, ru], env=GREP_ASCII),
|
||||
# See bench_subtitles_ru_literal for why we use '-a' here.
|
||||
Command('ugrep (lines)', ['ugrep', '-an', pat, ru]),
|
||||
Command('rg', ['rg', pat, ru]),
|
||||
Command('grep', [
|
||||
'grep', '-E', '-a', pat, ru,
|
||||
], env=GREP_ASCII),
|
||||
Command('grep', ['grep', '-E', pat, ru], env=GREP_ASCII),
|
||||
])
|
||||
|
||||
|
||||
@@ -658,12 +639,13 @@ def bench_subtitles_ru_alternate_casei(suite_dir):
|
||||
|
||||
return Benchmark(pattern=pat, commands=[
|
||||
Command('ag (ASCII)', ['ag', '-s', '-i', pat, ru]),
|
||||
Command('ucg (ASCII)', ['ucg', '-i', pat, ru]),
|
||||
Command('grep (ASCII)', [
|
||||
'grep', '-E', '-ani', pat, ru,
|
||||
'grep', '-E', '-ni', pat, ru,
|
||||
], 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('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=[
|
||||
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('ucg (ASCII)', ['ucg', '--nosmart-case', pat, ru]),
|
||||
Command('grep (ASCII)', [
|
||||
'grep', '-E', '-an', pat, ru,
|
||||
], env=GREP_ASCII),
|
||||
Command('grep (ASCII)', ['grep', '-E', '-n', pat, ru], env=GREP_ASCII),
|
||||
# See bench_subtitles_ru_literal for why we use '-a' here.
|
||||
Command('ugrep (ASCII)', ['ugrep', '-a', '-n', '-U', pat, ru]),
|
||||
])
|
||||
|
||||
|
||||
@@ -701,12 +683,13 @@ def bench_subtitles_ru_no_literal(suite_dir):
|
||||
|
||||
return Benchmark(pattern=pat, commands=[
|
||||
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('ag (ASCII)', ['ag', '-s', pat, ru]),
|
||||
Command('ucg (ASCII)', ['ucg', '--nosmart-case', pat, ru]),
|
||||
Command('grep (ASCII)', [
|
||||
'grep', '-E', '-an', pat, ru,
|
||||
], env=GREP_ASCII),
|
||||
Command('grep (ASCII)', ['grep', '-E', '-n', pat, ru], env=GREP_ASCII),
|
||||
# See bench_subtitles_ru_literal for why we use '-a' here.
|
||||
Command('ugrep (ASCII)', ['ugrep', '-anU', pat, ru])
|
||||
])
|
||||
|
||||
|
||||
@@ -756,7 +739,7 @@ class Benchmark(object):
|
||||
def __init__(self, name=None, pattern=None, commands=None,
|
||||
warmup_count=1, count=3, line_count=True,
|
||||
allow_missing_commands=False,
|
||||
disabled_cmds=None):
|
||||
disabled_cmds=None, order=0):
|
||||
'''
|
||||
Create a single benchmark.
|
||||
|
||||
@@ -792,6 +775,8 @@ class Benchmark(object):
|
||||
will simply skip it.
|
||||
:param list(str) disabled_cmds:
|
||||
A list of commands to skip.
|
||||
:param int order:
|
||||
An integer indicating the sequence number of this benchmark.
|
||||
'''
|
||||
self.name = name
|
||||
self.pattern = pattern
|
||||
@@ -801,6 +786,7 @@ class Benchmark(object):
|
||||
self.line_count = line_count
|
||||
self.allow_missing_commands = allow_missing_commands
|
||||
self.disabled_cmds = set(disabled_cmds or [])
|
||||
self.order = order
|
||||
|
||||
def raise_if_missing(self):
|
||||
'''
|
||||
@@ -894,7 +880,7 @@ class Result(object):
|
||||
'''
|
||||
Create a new set of results, initially empty.
|
||||
|
||||
:param Benchmarl benchmark:
|
||||
:param Benchmark benchmark:
|
||||
The benchmark that produced these results.
|
||||
'''
|
||||
self.benchmark = benchmark
|
||||
@@ -1088,7 +1074,7 @@ def download_subtitles_en(suite_dir):
|
||||
# benchmarks finish in a reasonable time.
|
||||
with open(path.join(subtitle_dir, en_path_sample), 'wb+') as f:
|
||||
run_cmd(
|
||||
['head', '-n', '32722372', en_path],
|
||||
['head', '-n', '55000000', en_path],
|
||||
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
|
||||
emitted to stderr and it is not yielded.
|
||||
'''
|
||||
for fun in sorted(globals()):
|
||||
if not fun.startswith('bench_'):
|
||||
benchmarks = []
|
||||
for global_name in globals():
|
||||
if not global_name.startswith('bench_'):
|
||||
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):
|
||||
continue
|
||||
try:
|
||||
benchmark = globals()[fun](suite_dir)
|
||||
fun = globals()[global_name]
|
||||
benchmark = fun(suite_dir)
|
||||
benchmark.name = name
|
||||
benchmark.warmup_count = warmup_iter
|
||||
benchmark.count = bench_iter
|
||||
benchmark.allow_missing_commands = allow_missing_commands
|
||||
benchmark.disabled_cmds = disabled_cmds
|
||||
benchmark.order = fun.__code__.co_firstlineno
|
||||
benchmark.raise_if_missing()
|
||||
except MissingDependencies as e:
|
||||
eprint(
|
||||
@@ -1190,7 +1179,8 @@ def collect_benchmarks(suite_dir, filter_pat=None,
|
||||
'(run with --allow-missing to run incomplete benchmarks)'
|
||||
eprint(fmt % (', '.join(e.missing_names), name))
|
||||
continue
|
||||
yield benchmark
|
||||
benchmarks.append(benchmark)
|
||||
return sorted(benchmarks, key=lambda b: b.order)
|
||||
|
||||
|
||||
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)*
|
||||
81
build.rs
81
build.rs
@@ -1,8 +1,3 @@
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
use std::env;
|
||||
use std::fs::{self, File};
|
||||
use std::io::{self, Read, Write};
|
||||
@@ -14,7 +9,7 @@ use clap::Shell;
|
||||
use app::{RGArg, RGArgKind};
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[path = "src/app.rs"]
|
||||
#[path = "crates/core/app.rs"]
|
||||
mod app;
|
||||
|
||||
fn main() {
|
||||
@@ -26,7 +21,8 @@ fn main() {
|
||||
eprintln!(
|
||||
"OUT_DIR environment variable not defined. \
|
||||
Please file a bug: \
|
||||
https://github.com/BurntSushi/ripgrep/issues/new");
|
||||
https://github.com/BurntSushi/ripgrep/issues/new"
|
||||
);
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
@@ -69,6 +65,51 @@ fn git_revision_hash() -> Option<String> {
|
||||
}
|
||||
|
||||
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 let Err(err) = process::Command::new("a2x").output() {
|
||||
eprintln!("Could not run 'a2x' binary, skipping man page generation.");
|
||||
@@ -90,13 +131,15 @@ fn generate_man_page<P: AsRef<Path>>(outdir: P) -> io::Result<()> {
|
||||
|
||||
let githash = git_revision_hash();
|
||||
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())?;
|
||||
let result = process::Command::new("a2x")
|
||||
.arg("--no-xmllint")
|
||||
.arg("--doctype").arg("manpage")
|
||||
.arg("--format").arg("manpage")
|
||||
.arg("--doctype")
|
||||
.arg("manpage")
|
||||
.arg("--format")
|
||||
.arg("manpage")
|
||||
.arg(&txt_path)
|
||||
.spawn()?
|
||||
.wait()?;
|
||||
@@ -119,7 +162,7 @@ fn formatted_options() -> io::Result<String> {
|
||||
// ripgrep only has two positional arguments, and probably will only
|
||||
// ever have two positional arguments, so we just hardcode them into
|
||||
// the template.
|
||||
if let app::RGArgKind::Positional{..} = arg.kind {
|
||||
if let app::RGArgKind::Positional { .. } = arg.kind {
|
||||
continue;
|
||||
}
|
||||
formatted.push(formatted_arg(&arg)?);
|
||||
@@ -129,7 +172,9 @@ fn formatted_options() -> io::Result<String> {
|
||||
|
||||
fn formatted_arg(arg: &RGArg) -> io::Result<String> {
|
||||
match arg.kind {
|
||||
RGArgKind::Positional{..} => panic!("unexpected positional argument"),
|
||||
RGArgKind::Positional { .. } => {
|
||||
panic!("unexpected positional argument")
|
||||
}
|
||||
RGArgKind::Switch { long, short, multiple } => {
|
||||
let mut out = vec![];
|
||||
|
||||
@@ -168,7 +213,17 @@ fn formatted_arg(arg: &RGArg) -> io::Result<String> {
|
||||
}
|
||||
|
||||
fn formatted_doc_txt(arg: &RGArg) -> io::Result<String> {
|
||||
let paragraphs: Vec<&str> = arg.doc_long.split("\n\n").collect();
|
||||
let paragraphs: Vec<String> = arg
|
||||
.doc_long
|
||||
.replace("{", "{")
|
||||
.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")
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
if paragraphs.is_empty() {
|
||||
return Err(ioerr(format!("missing docs for --{}", arg.name)));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
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
|
||||
# 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
|
||||
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
|
||||
# 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)
|
||||
# produced from that build, put it into a predictable location and then build
|
||||
# the deb, which knows where to look.
|
||||
|
||||
DEPLOY_DIR=deployment/deb
|
||||
mkdir -p "$DEPLOY_DIR"
|
||||
cargo build
|
||||
|
||||
# Find and copy man page.
|
||||
manpage="$(find ./target/debug -name rg.1 -print0 | xargs -0 ls -t | head -n1)"
|
||||
cp "$manpage" "$DEPLOY_DIR/"
|
||||
DEPLOY_DIR=deployment/deb
|
||||
OUT_DIR="$("$D"/cargo-out-dir target/debug/)"
|
||||
mkdir -p "$DEPLOY_DIR"
|
||||
|
||||
# Do the same for shell completions.
|
||||
compbash="$(find ./target/debug -name rg.bash -print0 | xargs -0 ls -t | head -n1)"
|
||||
cp "$compbash" "$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/"
|
||||
# Copy man page and shell completions.
|
||||
cp "$OUT_DIR"/{rg.1,rg.bash,rg.fish} "$DEPLOY_DIR/"
|
||||
cp complete/_rg "$DEPLOY_DIR/"
|
||||
|
||||
# Since we're distributing the dpkg, we don't know whether the user will have
|
||||
# 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() {
|
||||
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 -a help_args comp_args
|
||||
|
||||
@@ -44,8 +44,8 @@ main() {
|
||||
# Occasionally we may have to handle some manually, however
|
||||
help_args=( ${(f)"$(
|
||||
$rg --help |
|
||||
$rg -i -- '^\s+--?[a-z0-9]|--[imnp]' |
|
||||
$rg -ior '$1' -- $'[\t /\"\'`.,](-[a-z0-9]|--[a-z0-9-]+)\\b' |
|
||||
$rg -i -- '^\s+--?[a-z0-9.]|--[a-z]' |
|
||||
$rg -ior '$1' -- $'[\t /\"\'`.,](-[a-z0-9.]|--[a-z0-9-]+)(,|\\b)' |
|
||||
$rg -v -- --print0 | # False positives
|
||||
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
|
||||
}
|
||||
|
||||
is_musl() {
|
||||
case "$TARGET" in
|
||||
*-musl) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
is_x86() {
|
||||
case "$(architecture)" in
|
||||
amd64|i386) return 0 ;;
|
||||
@@ -62,6 +69,13 @@ is_x86() {
|
||||
esac
|
||||
}
|
||||
|
||||
is_x86_64() {
|
||||
case "$(architecture)" in
|
||||
amd64) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
is_arm() {
|
||||
case "$(architecture)" in
|
||||
armhf) return 0 ;;
|
||||
@@ -82,3 +96,12 @@ is_osx() {
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
builder() {
|
||||
if is_musl && is_x86_64; then
|
||||
cargo install cross
|
||||
echo "cross"
|
||||
else
|
||||
echo "cargo"
|
||||
fi
|
||||
}
|
||||
|
||||
65
complete/_rg
65
complete/_rg
@@ -3,7 +3,7 @@
|
||||
##
|
||||
# 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.
|
||||
#
|
||||
# For convenience, a completion reference guide is included at the bottom of
|
||||
@@ -43,6 +43,7 @@ _rg() {
|
||||
+ '(exclusive)' # Misc. fully exclusive options
|
||||
'(: * -)'{-h,--help}'[display help information]'
|
||||
'(: * -)'{-V,--version}'[display version information]'
|
||||
'(: * -)'--pcre2-version'[print the version of PCRE2 used by ripgrep, if available]'
|
||||
|
||||
+ '(buffered)' # buffering options
|
||||
'--line-buffered[force line buffering]'
|
||||
@@ -71,11 +72,19 @@ _rg() {
|
||||
+ '(count)' # Counting options
|
||||
{-c,--count}'[only show count of matching lines 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
|
||||
{-E+,--encoding=}'[specify text encoding of files to search]: :_rg_encodings'
|
||||
$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
|
||||
'(1)*'{-f+,--file=}'[specify file containing patterns to search for]: :_files'
|
||||
|
||||
@@ -85,7 +94,7 @@ _rg() {
|
||||
|
||||
+ '(file-name)' # File-name options
|
||||
{-H,--with-filename}'[show file name for matches]'
|
||||
"--no-filename[don't show file name for matches]"
|
||||
{-I,--no-filename}"[don't show file name for matches]"
|
||||
|
||||
+ '(file-system)' # File system options
|
||||
"--one-file-system[don't descend into directories on other file systems]"
|
||||
@@ -103,17 +112,33 @@ _rg() {
|
||||
'*'{-g+,--glob=}'[include/exclude files matching specified 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
|
||||
'(pretty-vimgrep)--heading[show matches grouped by file name]'
|
||||
"(pretty-vimgrep)--no-heading[don't show matches grouped by file name]"
|
||||
|
||||
+ '(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]"
|
||||
|
||||
+ '(hybrid)' # hybrid regex options
|
||||
'--auto-hybrid-regex[dynamically use PCRE2 if necessary]'
|
||||
$no"--no-auto-hybrid-regex[don't dynamically use PCRE2 if necessary]"
|
||||
|
||||
+ '(ignore)' # Ignore-file options
|
||||
"(--no-ignore-global --no-ignore-parent --no-ignore-vcs)--no-ignore[don't respect ignore files]"
|
||||
$no'(--ignore-global --ignore-parent --ignore-vcs)--ignore[respect ignore files]'
|
||||
"(--no-ignore-global --no-ignore-parent --no-ignore-vcs --no-ignore-dot)--no-ignore[don't respect ignore files]"
|
||||
$no'(--ignore-global --ignore-parent --ignore-vcs --ignore-dot)--ignore[respect ignore files]'
|
||||
|
||||
+ '(ignore-file-case-insensitive)' # Ignore-file case sensitivity options
|
||||
'--ignore-file-case-insensitive[process ignore files case insensitively]'
|
||||
$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
|
||||
"--no-ignore-global[don't respect global ignore files]"
|
||||
@@ -127,6 +152,18 @@ _rg() {
|
||||
"--no-ignore-vcs[don't respect version control ignore files]"
|
||||
$no'--ignore-vcs[respect version control ignore files]'
|
||||
|
||||
+ '(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[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[output results in JSON Lines format]'
|
||||
$no"--no-json[don't output results in JSON Lines format]"
|
||||
@@ -140,6 +177,10 @@ _rg() {
|
||||
$no"--no-crlf[don't use CRLF as line terminator]"
|
||||
'(text)--null-data[use NUL as line terminator]'
|
||||
|
||||
+ '(max-columns-preview)' # max column preview options
|
||||
'--max-columns-preview[show preview for long lines (with -M)]'
|
||||
$no"--no-max-columns-preview[don't show preview for long lines (with -M)]"
|
||||
|
||||
+ '(max-depth)' # Directory-depth options
|
||||
'--max-depth=[specify max number of directories to descend]:number of directories'
|
||||
'!--maxdepth=:number of directories'
|
||||
@@ -219,6 +260,8 @@ _rg() {
|
||||
|
||||
+ '(text)' # Binary-search options
|
||||
{-a,--text}'[search binary files as if they were text]'
|
||||
"--binary[search binary files, don't print binary data]"
|
||||
$no"--no-binary[don't search binary files]"
|
||||
$no"(--null-data)--no-text[don't search binary files as if they were text]"
|
||||
|
||||
+ '(threads)' # Thread-count options
|
||||
@@ -240,6 +283,10 @@ _rg() {
|
||||
{-w,--word-regexp}'[only show matches surrounded by word 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
|
||||
'(--pre)'{-z,--search-zip}'[search in compressed files]'
|
||||
$no"--no-search-zip[don't search in compressed files]"
|
||||
@@ -254,7 +301,11 @@ _rg() {
|
||||
))'
|
||||
'*--colors=[specify color and style settings]: :->colorspec'
|
||||
'--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]'
|
||||
'--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)'
|
||||
"(1 stats)--files[show each file that would be searched (but don't search)]"
|
||||
'*--ignore-file=[specify additional ignore file]:ignore file:_files'
|
||||
@@ -274,7 +325,7 @@ _rg() {
|
||||
'(--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
|
||||
[[ $_RG_COMPLETE_LIST_ARGS == (1|t*|y*) ]] && {
|
||||
print -rl - $args
|
||||
@@ -370,7 +421,7 @@ _rg_encodings() {
|
||||
shift{-,_}jis csshiftjis {,x-}sjis ms_kanji ms932
|
||||
utf{,-}8 utf-16{,be,le} unicode-1-1-utf-8
|
||||
windows-{31j,874,949,125{0..8}} dos-874 tis-620 ansi_x3.4-1968
|
||||
x-user-defined auto
|
||||
x-user-defined auto none
|
||||
)
|
||||
|
||||
_wanted encodings expl encoding compadd -a "$@" - _encodings
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
[package]
|
||||
name = "grep-cli"
|
||||
version = "0.1.1" #:version
|
||||
version = "0.1.6" #:version
|
||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||
description = """
|
||||
Utilities for search oriented command line applications.
|
||||
"""
|
||||
documentation = "https://docs.rs/grep-cli"
|
||||
homepage = "https://github.com/BurntSushi/ripgrep"
|
||||
repository = "https://github.com/BurntSushi/ripgrep"
|
||||
homepage = "https://github.com/BurntSushi/ripgrep/tree/master/crates/cli"
|
||||
repository = "https://github.com/BurntSushi/ripgrep/tree/master/crates/cli"
|
||||
readme = "README.md"
|
||||
keywords = ["regex", "grep", "cli", "utility", "util"]
|
||||
license = "Unlicense/MIT"
|
||||
license = "Unlicense OR MIT"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
atty = "0.2.11"
|
||||
globset = { version = "0.4.2", path = "../globset" }
|
||||
bstr = "1.1.0"
|
||||
globset = { version = "0.4.10", path = "../globset" }
|
||||
lazy_static = "1.1.0"
|
||||
log = "0.4.5"
|
||||
regex = "1.0.5"
|
||||
same-file = "1.0.3"
|
||||
termcolor = "1.0.3"
|
||||
regex = "1.1"
|
||||
same-file = "1.0.4"
|
||||
termcolor = "1.0.4"
|
||||
|
||||
[target.'cfg(windows)'.dependencies.winapi-util]
|
||||
version = "0.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,
|
||||
this crate strives for compatibility across Windows, macOS and Linux.
|
||||
|
||||
[](https://travis-ci.org/BurntSushi/ripgrep)
|
||||
[](https://ci.appveyor.com/project/BurntSushi/ripgrep)
|
||||
[](https://github.com/BurntSushi/ripgrep/actions)
|
||||
[](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
|
||||
@@ -30,9 +29,3 @@ Add this to your `Cargo.toml`:
|
||||
[dependencies]
|
||||
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::fs::File;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
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.
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -24,7 +24,7 @@ struct DecompressionCommand {
|
||||
/// The glob that matches this command.
|
||||
glob: String,
|
||||
/// The command or binary name.
|
||||
bin: OsString,
|
||||
bin: PathBuf,
|
||||
/// The arguments to invoke with the command.
|
||||
args: Vec<OsString>,
|
||||
}
|
||||
@@ -38,10 +38,7 @@ impl Default for DecompressionMatcherBuilder {
|
||||
impl DecompressionMatcherBuilder {
|
||||
/// Create a new builder for configuring a decompression matcher.
|
||||
pub fn new() -> DecompressionMatcherBuilder {
|
||||
DecompressionMatcherBuilder {
|
||||
commands: vec![],
|
||||
defaults: true,
|
||||
}
|
||||
DecompressionMatcherBuilder { commands: vec![], defaults: true }
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// returned.
|
||||
pub fn build(&self) -> Result<DecompressionMatcher, CommandError> {
|
||||
let defaults =
|
||||
if !self.defaults {
|
||||
vec![]
|
||||
} else {
|
||||
default_decompression_commands()
|
||||
};
|
||||
let defaults = if !self.defaults {
|
||||
vec![]
|
||||
} else {
|
||||
default_decompression_commands()
|
||||
};
|
||||
let mut glob_builder = GlobSetBuilder::new();
|
||||
let mut commands = vec![];
|
||||
for decomp_cmd in defaults.iter().chain(&self.commands) {
|
||||
@@ -87,26 +83,61 @@ impl DecompressionMatcherBuilder {
|
||||
///
|
||||
/// 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 it is silently ignored and the association is
|
||||
/// dropped. For this reason, callers should prefer `try_associate`.
|
||||
pub fn associate<P, I, A>(
|
||||
&mut self,
|
||||
glob: &str,
|
||||
program: P,
|
||||
args: I,
|
||||
) -> &mut DecompressionMatcherBuilder
|
||||
where P: AsRef<OsStr>,
|
||||
I: IntoIterator<Item=A>,
|
||||
A: AsRef<OsStr>,
|
||||
where
|
||||
P: AsRef<OsStr>,
|
||||
I: IntoIterator<Item = A>,
|
||||
A: AsRef<OsStr>,
|
||||
{
|
||||
|
||||
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 });
|
||||
let _ = self.try_associate(glob, program, args);
|
||||
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.
|
||||
@@ -199,7 +230,7 @@ impl DecompressionReaderBuilder {
|
||||
match self.command_builder.build(&mut cmd) {
|
||||
Ok(cmd_reader) => Ok(DecompressionReader { rdr: Ok(cmd_reader) }),
|
||||
Err(err) => {
|
||||
debug!(
|
||||
log::debug!(
|
||||
"{}: error spawning command '{:?}': {} \
|
||||
(falling back to uncompressed reader)",
|
||||
path.display(),
|
||||
@@ -335,6 +366,30 @@ impl DecompressionReader {
|
||||
let file = File::open(path)?;
|
||||
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 {
|
||||
@@ -346,36 +401,110 @@ 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> {
|
||||
const ARGS_GZIP: &[&str] = &["gzip", "-d", "-c"];
|
||||
const ARGS_BZIP: &[&str] = &["bzip2", "-d", "-c"];
|
||||
const ARGS_XZ: &[&str] = &["xz", "-d", "-c"];
|
||||
const ARGS_LZ4: &[&str] = &["lz4", "-d", "-c"];
|
||||
const ARGS_LZMA: &[&str] = &["xz", "--format=lzma", "-d", "-c"];
|
||||
const ARGS_BROTLI: &[&str] = &["brotli", "-d", "-c"];
|
||||
const ARGS_ZSTD: &[&str] = &["zstd", "-q", "-d", "-c"];
|
||||
const ARGS_UNCOMPRESS: &[&str] = &["uncompress", "-c"];
|
||||
|
||||
fn cmd(glob: &str, args: &[&str]) -> DecompressionCommand {
|
||||
DecompressionCommand {
|
||||
fn add(glob: &str, args: &[&str], cmds: &mut Vec<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(),
|
||||
bin: OsStr::new(&args[0]).to_os_string(),
|
||||
bin,
|
||||
args: args
|
||||
.iter()
|
||||
.skip(1)
|
||||
.map(|s| OsStr::new(s).to_os_string())
|
||||
.collect(),
|
||||
}
|
||||
});
|
||||
}
|
||||
vec![
|
||||
cmd("*.gz", ARGS_GZIP),
|
||||
cmd("*.tgz", ARGS_GZIP),
|
||||
|
||||
cmd("*.bz2", ARGS_BZIP),
|
||||
cmd("*.tbz2", ARGS_BZIP),
|
||||
|
||||
cmd("*.xz", ARGS_XZ),
|
||||
cmd("*.txz", ARGS_XZ),
|
||||
|
||||
cmd("*.lz4", ARGS_LZ4),
|
||||
|
||||
cmd("*.lzma", ARGS_LZMA),
|
||||
]
|
||||
let mut cmds = vec![];
|
||||
add("*.gz", ARGS_GZIP, &mut cmds);
|
||||
add("*.tgz", ARGS_GZIP, &mut cmds);
|
||||
add("*.bz2", ARGS_BZIP, &mut cmds);
|
||||
add("*.tbz2", ARGS_BZIP, &mut cmds);
|
||||
add("*.xz", ARGS_XZ, &mut cmds);
|
||||
add("*.txz", ARGS_XZ, &mut cmds);
|
||||
add("*.lz4", ARGS_LZ4, &mut cmds);
|
||||
add("*.lzma", ARGS_LZMA, &mut cmds);
|
||||
add("*.br", ARGS_BROTLI, &mut cmds);
|
||||
add("*.zst", ARGS_ZSTD, &mut cmds);
|
||||
add("*.zstd", ARGS_ZSTD, &mut cmds);
|
||||
add("*.Z", ARGS_UNCOMPRESS, &mut cmds);
|
||||
cmds
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
use std::ffi::OsStr;
|
||||
use std::str;
|
||||
|
||||
use bstr::{ByteSlice, ByteVec};
|
||||
|
||||
/// A single state in the state machine used by `unescape`.
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
enum State {
|
||||
@@ -35,18 +37,15 @@ enum State {
|
||||
///
|
||||
/// assert_eq!(r"foo\nbar\xFFbaz", escape(b"foo\nbar\xFFbaz"));
|
||||
/// ```
|
||||
pub fn escape(mut bytes: &[u8]) -> String {
|
||||
pub fn escape(bytes: &[u8]) -> String {
|
||||
let mut escaped = String::new();
|
||||
while let Some(result) = decode_utf8(bytes) {
|
||||
match result {
|
||||
Ok(cp) => {
|
||||
escape_char(cp, &mut escaped);
|
||||
bytes = &bytes[cp.len_utf8()..];
|
||||
}
|
||||
Err(byte) => {
|
||||
escape_byte(byte, &mut escaped);
|
||||
bytes = &bytes[1..];
|
||||
for (s, e, ch) in bytes.char_indices() {
|
||||
if ch == '\u{FFFD}' {
|
||||
for b in bytes[s..e].bytes() {
|
||||
escape_byte(b, &mut escaped);
|
||||
}
|
||||
} else {
|
||||
escape_char(ch, &mut escaped);
|
||||
}
|
||||
}
|
||||
escaped
|
||||
@@ -56,19 +55,7 @@ pub fn escape(mut bytes: &[u8]) -> String {
|
||||
///
|
||||
/// This is like [`escape`](fn.escape.html), but accepts an OS string.
|
||||
pub fn escape_os(string: &OsStr) -> String {
|
||||
#[cfg(unix)]
|
||||
fn imp(string: &OsStr) -> String {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
escape(string.as_bytes())
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
fn imp(string: &OsStr) -> String {
|
||||
escape(string.to_string_lossy().as_bytes())
|
||||
}
|
||||
|
||||
imp(string)
|
||||
escape(Vec::from_os_str_lossy(string).as_bytes())
|
||||
}
|
||||
|
||||
/// Unescapes a string.
|
||||
@@ -108,51 +95,61 @@ pub fn unescape(s: &str) -> Vec<u8> {
|
||||
let mut state = Literal;
|
||||
for c in s.chars() {
|
||||
match state {
|
||||
Escape => {
|
||||
match c {
|
||||
'\\' => { bytes.push(b'\\'); state = Literal; }
|
||||
'n' => { bytes.push(b'\n'); 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;
|
||||
}
|
||||
Escape => match c {
|
||||
'\\' => {
|
||||
bytes.push(b'\\');
|
||||
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;
|
||||
}
|
||||
'n' => {
|
||||
bytes.push(b'\n');
|
||||
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;
|
||||
}
|
||||
'r' => {
|
||||
bytes.push(b'\r');
|
||||
state = Literal;
|
||||
}
|
||||
}
|
||||
Literal => {
|
||||
match c {
|
||||
'\\' => { state = Escape; }
|
||||
c => { bytes.extend(c.to_string().as_bytes()); }
|
||||
't' => {
|
||||
bytes.push(b'\t');
|
||||
state = Literal;
|
||||
}
|
||||
}
|
||||
'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 {
|
||||
@@ -186,7 +183,7 @@ fn escape_char(cp: char, into: &mut String) {
|
||||
/// Adds the given byte to the given string, escaping it if necessary.
|
||||
fn escape_byte(byte: u8, into: &mut String) {
|
||||
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'\r' => into.push_str(r"\r"),
|
||||
b'\t' => into.push_str(r"\t"),
|
||||
@@ -195,46 +192,6 @@ fn escape_byte(byte: u8, into: &mut String) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Decodes the next UTF-8 encoded codepoint from the given byte slice.
|
||||
///
|
||||
/// If no valid encoding of a codepoint exists at the beginning of the given
|
||||
/// byte slice, then the first byte is returned instead.
|
||||
///
|
||||
/// This returns `None` if and only if `bytes` is empty.
|
||||
fn decode_utf8(bytes: &[u8]) -> Option<Result<char, u8>> {
|
||||
if bytes.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let len = match utf8_len(bytes[0]) {
|
||||
None => return Some(Err(bytes[0])),
|
||||
Some(len) if len > bytes.len() => return Some(Err(bytes[0])),
|
||||
Some(len) => len,
|
||||
};
|
||||
match str::from_utf8(&bytes[..len]) {
|
||||
Ok(s) => Some(Ok(s.chars().next().unwrap())),
|
||||
Err(_) => Some(Err(bytes[0])),
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a UTF-8 leading byte, this returns the total number of code units
|
||||
/// in the following encoded codepoint.
|
||||
///
|
||||
/// If the given byte is not a valid UTF-8 leading byte, then this returns
|
||||
/// `None`.
|
||||
fn utf8_len(byte: u8) -> Option<usize> {
|
||||
if byte <= 0x7F {
|
||||
Some(1)
|
||||
} else if byte <= 0b110_11111 {
|
||||
Some(2)
|
||||
} else if byte <= 0b1110_1111 {
|
||||
Some(3)
|
||||
} else if byte <= 0b1111_0111 {
|
||||
Some(4)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{escape, unescape};
|
||||
@@ -7,8 +7,8 @@ use regex::Regex;
|
||||
|
||||
/// An error that occurs when parsing a human readable size description.
|
||||
///
|
||||
/// This error provides a end user friendly message describing why the
|
||||
/// description coudln't be parsed and what the expected format is.
|
||||
/// This error provides an end user friendly message describing why the
|
||||
/// description couldn't be parsed and what the expected format is.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct ParseSizeError {
|
||||
original: String,
|
||||
@@ -46,34 +46,29 @@ impl ParseSizeError {
|
||||
}
|
||||
|
||||
impl error::Error for ParseSizeError {
|
||||
fn description(&self) -> &str { "invalid size" }
|
||||
fn description(&self) -> &str {
|
||||
"invalid size"
|
||||
}
|
||||
}
|
||||
|
||||
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::*;
|
||||
|
||||
match self.kind {
|
||||
InvalidFormat => {
|
||||
write!(
|
||||
f,
|
||||
"invalid format for size '{}', which should be a sequence \
|
||||
InvalidFormat => write!(
|
||||
f,
|
||||
"invalid format for size '{}', which should be a sequence \
|
||||
of digits followed by an optional 'K', 'M' or 'G' \
|
||||
suffix",
|
||||
self.original
|
||||
)
|
||||
}
|
||||
InvalidInt(ref err) => {
|
||||
write!(
|
||||
f,
|
||||
"invalid integer found in size '{}': {}",
|
||||
self.original,
|
||||
err
|
||||
)
|
||||
}
|
||||
Overflow => {
|
||||
write!(f, "size too big in '{}'", self.original)
|
||||
}
|
||||
self.original
|
||||
),
|
||||
InvalidInt(ref err) => write!(
|
||||
f,
|
||||
"invalid integer found in size '{}': {}",
|
||||
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.
|
||||
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
|
||||
// regex dep, but we bring regex in any way for glob matching, so might
|
||||
// as well use it.
|
||||
@@ -104,17 +99,16 @@ pub fn parse_human_readable_size(size: &str) -> Result<u64, ParseSizeError> {
|
||||
Some(caps) => caps,
|
||||
None => return Err(ParseSizeError::format(size)),
|
||||
};
|
||||
let value: u64 = caps[1].parse().map_err(|err| {
|
||||
ParseSizeError::int(size, err)
|
||||
})?;
|
||||
let value: u64 =
|
||||
caps[1].parse().map_err(|err| ParseSizeError::int(size, err))?;
|
||||
let suffix = match caps.get(2) {
|
||||
None => return Ok(value),
|
||||
Some(cap) => cap.as_str(),
|
||||
};
|
||||
let bytes = match suffix {
|
||||
"K" => value.checked_mul(1<<10),
|
||||
"M" => value.checked_mul(1<<20),
|
||||
"G" => value.checked_mul(1<<30),
|
||||
"K" => value.checked_mul(1 << 10),
|
||||
"M" => value.checked_mul(1 << 20),
|
||||
"G" => value.checked_mul(1 << 30),
|
||||
// Because if the regex matches this group, it must be [KMG].
|
||||
_ => unreachable!(),
|
||||
};
|
||||
@@ -134,19 +128,19 @@ mod tests {
|
||||
#[test]
|
||||
fn suffix_k() {
|
||||
let x = parse_human_readable_size("123K").unwrap();
|
||||
assert_eq!(123 * (1<<10), x);
|
||||
assert_eq!(123 * (1 << 10), x);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn suffix_m() {
|
||||
let x = parse_human_readable_size("123M").unwrap();
|
||||
assert_eq!(123 * (1<<20), x);
|
||||
assert_eq!(123 * (1 << 20), x);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn suffix_g() {
|
||||
let x = parse_human_readable_size("123G").unwrap();
|
||||
assert_eq!(123 * (1<<30), x);
|
||||
assert_eq!(123 * (1 << 30), x);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -158,18 +158,6 @@ error message is crafted that typically tells the user how to fix the problem.
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
extern crate atty;
|
||||
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 escape;
|
||||
mod human;
|
||||
@@ -177,21 +165,19 @@ mod pattern;
|
||||
mod process;
|
||||
mod wtr;
|
||||
|
||||
pub use decompress::{
|
||||
DecompressionMatcher, DecompressionMatcherBuilder,
|
||||
pub use crate::decompress::{
|
||||
resolve_binary, DecompressionMatcher, DecompressionMatcherBuilder,
|
||||
DecompressionReader, DecompressionReaderBuilder,
|
||||
};
|
||||
pub use escape::{escape, escape_os, unescape, unescape_os};
|
||||
pub use human::{ParseSizeError, parse_human_readable_size};
|
||||
pub use pattern::{
|
||||
InvalidPatternError,
|
||||
pattern_from_os, pattern_from_bytes,
|
||||
patterns_from_path, patterns_from_reader, patterns_from_stdin,
|
||||
pub use crate::escape::{escape, escape_os, unescape, unescape_os};
|
||||
pub use crate::human::{parse_human_readable_size, ParseSizeError};
|
||||
pub use crate::pattern::{
|
||||
pattern_from_bytes, pattern_from_os, patterns_from_path,
|
||||
patterns_from_reader, patterns_from_stdin, InvalidPatternError,
|
||||
};
|
||||
pub use process::{CommandError, CommandReader, CommandReaderBuilder};
|
||||
pub use wtr::{
|
||||
StandardStream,
|
||||
stdout, stdout_buffered_line, stdout_buffered_block,
|
||||
pub use crate::process::{CommandError, CommandReader, CommandReaderBuilder};
|
||||
pub use crate::wtr::{
|
||||
stdout, stdout_buffered_block, stdout_buffered_line, StandardStream,
|
||||
};
|
||||
|
||||
/// Returns true if and only if stdin is believed to be readable.
|
||||
@@ -204,14 +190,14 @@ pub use wtr::{
|
||||
pub fn is_readable_stdin() -> bool {
|
||||
#[cfg(unix)]
|
||||
fn imp() -> bool {
|
||||
use std::os::unix::fs::FileTypeExt;
|
||||
use same_file::Handle;
|
||||
use std::os::unix::fs::FileTypeExt;
|
||||
|
||||
let ft = match Handle::stdin().and_then(|h| h.as_file().metadata()) {
|
||||
Err(_) => return false,
|
||||
Ok(md) => md.file_type(),
|
||||
};
|
||||
ft.is_file() || ft.is_fifo()
|
||||
ft.is_file() || ft.is_fifo() || ft.is_socket()
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
@@ -226,13 +212,13 @@ pub fn is_readable_stdin() -> bool {
|
||||
!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.
|
||||
pub fn is_tty_stdin() -> bool {
|
||||
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.
|
||||
///
|
||||
/// This is useful for when you want your command line program to produce
|
||||
@@ -244,7 +230,7 @@ pub fn is_tty_stdout() -> bool {
|
||||
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.
|
||||
pub fn is_tty_stderr() -> bool {
|
||||
atty::is(atty::Stream::Stderr)
|
||||
@@ -2,11 +2,13 @@ use std::error;
|
||||
use std::ffi::OsStr;
|
||||
use std::fmt;
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufRead};
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
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.
|
||||
///
|
||||
@@ -27,18 +29,19 @@ impl InvalidPatternError {
|
||||
}
|
||||
|
||||
impl error::Error for InvalidPatternError {
|
||||
fn description(&self) -> &str { "invalid pattern" }
|
||||
fn description(&self) -> &str {
|
||||
"invalid pattern"
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for InvalidPatternError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"found invalid UTF-8 in pattern at byte offset {} \
|
||||
(use hex escape sequences to match arbitrary bytes \
|
||||
in a pattern, e.g., \\xFF): '{}'",
|
||||
self.valid_up_to,
|
||||
self.original,
|
||||
"found invalid UTF-8 in pattern at byte offset {}: {} \
|
||||
(disable Unicode mode and use hex escape sequences to match \
|
||||
arbitrary bytes in a pattern, e.g., '(?-u)\\xFF')",
|
||||
self.valid_up_to, self.original,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -61,10 +64,7 @@ pub fn pattern_from_os(pattern: &OsStr) -> Result<&str, InvalidPatternError> {
|
||||
.to_string_lossy()
|
||||
.find('\u{FFFD}')
|
||||
.expect("a Unicode replacement codepoint for invalid UTF-8");
|
||||
InvalidPatternError {
|
||||
original: escape_os(pattern),
|
||||
valid_up_to: valid_up_to,
|
||||
}
|
||||
InvalidPatternError { original: escape_os(pattern), valid_up_to }
|
||||
})
|
||||
}
|
||||
|
||||
@@ -77,11 +77,9 @@ pub fn pattern_from_os(pattern: &OsStr) -> Result<&str, InvalidPatternError> {
|
||||
pub fn pattern_from_bytes(
|
||||
pattern: &[u8],
|
||||
) -> Result<&str, InvalidPatternError> {
|
||||
str::from_utf8(pattern).map_err(|err| {
|
||||
InvalidPatternError {
|
||||
original: escape(pattern),
|
||||
valid_up_to: err.valid_up_to(),
|
||||
}
|
||||
str::from_utf8(pattern).map_err(|err| InvalidPatternError {
|
||||
original: escape(pattern),
|
||||
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 locked = stdin.lock();
|
||||
patterns_from_reader(locked).map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("<stdin>:{}", err),
|
||||
)
|
||||
io::Error::new(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>> {
|
||||
let mut patterns = vec![];
|
||||
let mut bufrdr = io::BufReader::new(rdr);
|
||||
let mut line = vec![];
|
||||
let mut line_number = 0;
|
||||
while {
|
||||
line.clear();
|
||||
io::BufReader::new(rdr).for_byte_line(|line| {
|
||||
line_number += 1;
|
||||
bufrdr.read_until(b'\n', &mut line)? > 0
|
||||
} {
|
||||
line.pop().unwrap(); // remove trailing '\n'
|
||||
if line.last() == Some(&b'\r') {
|
||||
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),
|
||||
));
|
||||
match pattern_from_bytes(line) {
|
||||
Ok(pattern) => {
|
||||
patterns.push(pattern.to_string());
|
||||
Ok(true)
|
||||
}
|
||||
Err(err) => Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("{}: {}", line_number, err),
|
||||
)),
|
||||
}
|
||||
}
|
||||
})?;
|
||||
Ok(patterns)
|
||||
}
|
||||
|
||||
@@ -195,8 +182,8 @@ mod tests {
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn os() {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::ffi::OsStr;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
let pat = OsStr::from_bytes(b"abc\xFFxyz");
|
||||
let err = pattern_from_os(pat).unwrap_err();
|
||||
@@ -30,14 +30,24 @@ impl CommandError {
|
||||
pub(crate) fn stderr(bytes: Vec<u8>) -> CommandError {
|
||||
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 {
|
||||
fn description(&self) -> &str { "command error" }
|
||||
fn description(&self) -> &str {
|
||||
"command error"
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
CommandErrorKind::Io(ref e) => e.fmt(f),
|
||||
CommandErrorKind::Stderr(ref bytes) => {
|
||||
@@ -46,7 +56,12 @@ impl fmt::Display for CommandError {
|
||||
write!(f, "<stderr is empty>")
|
||||
} else {
|
||||
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())
|
||||
.stderr(process::Stdio::piped())
|
||||
.spawn()?;
|
||||
let stdout = child.stdout.take().unwrap();
|
||||
let stderr =
|
||||
if self.async_stderr {
|
||||
StderrReader::async(child.stderr.take().unwrap())
|
||||
} else {
|
||||
StderrReader::sync(child.stderr.take().unwrap())
|
||||
};
|
||||
Ok(CommandReader {
|
||||
child: child,
|
||||
stdout: stdout,
|
||||
stderr: stderr,
|
||||
done: false,
|
||||
})
|
||||
let stderr = if self.async_stderr {
|
||||
StderrReader::r#async(child.stderr.take().unwrap())
|
||||
} else {
|
||||
StderrReader::sync(child.stderr.take().unwrap())
|
||||
};
|
||||
Ok(CommandReader { child, stderr, eof: false })
|
||||
}
|
||||
|
||||
/// When enabled, the reader will asynchronously read the contents of the
|
||||
@@ -169,9 +177,11 @@ impl CommandReaderBuilder {
|
||||
#[derive(Debug)]
|
||||
pub struct CommandReader {
|
||||
child: process::Child,
|
||||
stdout: process::ChildStdout,
|
||||
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 {
|
||||
@@ -195,23 +205,73 @@ impl CommandReader {
|
||||
) -> Result<CommandReader, CommandError> {
|
||||
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 {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
if self.done {
|
||||
return Ok(0);
|
||||
}
|
||||
let nread = self.stdout.read(buf)?;
|
||||
let stdout = match self.child.stdout {
|
||||
None => return Ok(0),
|
||||
Some(ref mut stdout) => stdout,
|
||||
};
|
||||
let nread = stdout.read(buf)?;
|
||||
if nread == 0 {
|
||||
self.done = true;
|
||||
// Reap the child now that we're done reading. If the command
|
||||
// failed, report stderr as an error.
|
||||
if !self.child.wait()?.success() {
|
||||
return Err(io::Error::from(self.stderr.read_to_end()));
|
||||
}
|
||||
self.eof = true;
|
||||
self.close().map(|_| 0)
|
||||
} else {
|
||||
Ok(nread)
|
||||
}
|
||||
Ok(nread)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,10 +285,9 @@ enum StderrReader {
|
||||
|
||||
impl StderrReader {
|
||||
/// Create a reader for stderr that reads contents asynchronously.
|
||||
fn async(mut stderr: process::ChildStderr) -> StderrReader {
|
||||
let handle = thread::spawn(move || {
|
||||
stderr_to_command_error(&mut stderr)
|
||||
});
|
||||
fn r#async(mut stderr: process::ChildStderr) -> StderrReader {
|
||||
let handle =
|
||||
thread::spawn(move || stderr_to_command_error(&mut stderr));
|
||||
StderrReader::Async(Some(handle))
|
||||
}
|
||||
|
||||
@@ -247,9 +306,7 @@ impl StderrReader {
|
||||
let handle = handle
|
||||
.take()
|
||||
.expect("read_to_end cannot be called more than once");
|
||||
handle
|
||||
.join()
|
||||
.expect("stderr reading thread does not panic")
|
||||
handle.join().expect("stderr reading thread does not panic")
|
||||
}
|
||||
StderrReader::Sync(ref mut stderr) => {
|
||||
stderr_to_command_error(stderr)
|
||||
@@ -2,7 +2,7 @@ use std::io;
|
||||
|
||||
use termcolor;
|
||||
|
||||
use is_tty_stdout;
|
||||
use crate::is_tty_stdout;
|
||||
|
||||
/// A writer that supports coloring with either line or block buffering.
|
||||
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
File diff suppressed because it is too large
Load Diff
@@ -4,12 +4,15 @@
|
||||
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufRead};
|
||||
use std::ffi::OsString;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use Result;
|
||||
use bstr::{io::BufReadExt, ByteSlice};
|
||||
use log;
|
||||
|
||||
use crate::Result;
|
||||
|
||||
/// Return a sequence of arguments derived from ripgrep rc configuration files.
|
||||
pub fn args() -> Vec<OsString> {
|
||||
@@ -25,7 +28,10 @@ pub fn args() -> Vec<OsString> {
|
||||
let (args, errs) = match parse(&config_path) {
|
||||
Ok((args, errs)) => (args, errs),
|
||||
Err(err) => {
|
||||
message!("{}", err);
|
||||
message!(
|
||||
"failed to read the file specified in RIPGREP_CONFIG_PATH: {}",
|
||||
err
|
||||
);
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
@@ -34,7 +40,7 @@ pub fn args() -> Vec<OsString> {
|
||||
message!("{}:{}", config_path.display(), err);
|
||||
}
|
||||
}
|
||||
debug!(
|
||||
log::debug!(
|
||||
"{}: arguments loaded from config file: {:?}",
|
||||
config_path.display(),
|
||||
args
|
||||
@@ -52,7 +58,7 @@ pub fn args() -> Vec<OsString> {
|
||||
/// for each line in addition to successfully parsed arguments.
|
||||
fn parse<P: AsRef<Path>>(
|
||||
path: P,
|
||||
) -> Result<(Vec<OsString>, Vec<Box<Error>>)> {
|
||||
) -> Result<(Vec<OsString>, Vec<Box<dyn Error>>)> {
|
||||
let path = path.as_ref();
|
||||
match File::open(&path) {
|
||||
Ok(file) => parse_reader(file),
|
||||
@@ -73,71 +79,39 @@ fn parse<P: AsRef<Path>>(
|
||||
/// in addition to successfully parsed arguments.
|
||||
fn parse_reader<R: io::Read>(
|
||||
rdr: R,
|
||||
) -> Result<(Vec<OsString>, Vec<Box<Error>>)> {
|
||||
) -> Result<(Vec<OsString>, Vec<Box<dyn Error>>)> {
|
||||
let mut bufrdr = io::BufReader::new(rdr);
|
||||
let (mut args, mut errs) = (vec![], vec![]);
|
||||
let mut line = vec![];
|
||||
let mut line_number = 0;
|
||||
while {
|
||||
line.clear();
|
||||
bufrdr.for_byte_line_with_terminator(|line| {
|
||||
line_number += 1;
|
||||
bufrdr.read_until(b'\n', &mut line)? > 0
|
||||
} {
|
||||
trim(&mut line);
|
||||
|
||||
let line = line.trim();
|
||||
if line.is_empty() || line[0] == b'#' {
|
||||
continue;
|
||||
return Ok(true);
|
||||
}
|
||||
match bytes_to_os_string(&line) {
|
||||
match line.to_os_str() {
|
||||
Ok(osstr) => {
|
||||
args.push(osstr);
|
||||
args.push(osstr.to_os_string());
|
||||
}
|
||||
Err(err) => {
|
||||
errs.push(format!("{}: {}", line_number, err).into());
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(true)
|
||||
})?;
|
||||
Ok((args, errs))
|
||||
}
|
||||
|
||||
/// Trim the given bytes of whitespace according to the ASCII definition.
|
||||
fn trim(x: &mut Vec<u8>) {
|
||||
let upto = x.iter().take_while(|b| is_space(**b)).count();
|
||||
x.drain(..upto);
|
||||
let revto = x.len() - x.iter().rev().take_while(|b| is_space(**b)).count();
|
||||
x.drain(revto..);
|
||||
}
|
||||
|
||||
/// Returns true if and only if the given byte is an ASCII space character.
|
||||
fn is_space(b: u8) -> bool {
|
||||
b == b'\t'
|
||||
|| b == b'\n'
|
||||
|| b == b'\x0B'
|
||||
|| b == b'\x0C'
|
||||
|| b == b'\r'
|
||||
|| b == b' '
|
||||
}
|
||||
|
||||
/// On Unix, get an OsString from raw bytes.
|
||||
#[cfg(unix)]
|
||||
fn bytes_to_os_string(bytes: &[u8]) -> Result<OsString> {
|
||||
use std::os::unix::ffi::OsStringExt;
|
||||
Ok(OsString::from_vec(bytes.to_vec()))
|
||||
}
|
||||
|
||||
/// On non-Unix (like Windows), require UTF-8.
|
||||
#[cfg(not(unix))]
|
||||
fn bytes_to_os_string(bytes: &[u8]) -> Result<OsString> {
|
||||
String::from_utf8(bytes.to_vec()).map(OsString::from).map_err(From::from)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::ffi::OsString;
|
||||
use super::parse_reader;
|
||||
use std::ffi::OsString;
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
let (args, errs) = parse_reader(&b"\
|
||||
let (args, errs) = parse_reader(
|
||||
&b"\
|
||||
# Test
|
||||
--context=0
|
||||
--smart-case
|
||||
@@ -146,13 +120,13 @@ mod tests {
|
||||
|
||||
# --bar
|
||||
--foo
|
||||
"[..]).unwrap();
|
||||
"[..],
|
||||
)
|
||||
.unwrap();
|
||||
assert!(errs.is_empty());
|
||||
let args: Vec<String> =
|
||||
args.into_iter().map(|s| s.into_string().unwrap()).collect();
|
||||
assert_eq!(args, vec![
|
||||
"--context=0", "--smart-case", "-u", "--foo",
|
||||
]);
|
||||
assert_eq!(args, vec!["--context=0", "--smart-case", "-u", "--foo",]);
|
||||
}
|
||||
|
||||
// We test that we can handle invalid UTF-8 on Unix-like systems.
|
||||
@@ -161,32 +135,38 @@ mod tests {
|
||||
fn error() {
|
||||
use std::os::unix::ffi::OsStringExt;
|
||||
|
||||
let (args, errs) = parse_reader(&b"\
|
||||
let (args, errs) = parse_reader(
|
||||
&b"\
|
||||
quux
|
||||
foo\xFFbar
|
||||
baz
|
||||
"[..]).unwrap();
|
||||
"[..],
|
||||
)
|
||||
.unwrap();
|
||||
assert!(errs.is_empty());
|
||||
assert_eq!(args, vec![
|
||||
OsString::from("quux"),
|
||||
OsString::from_vec(b"foo\xFFbar".to_vec()),
|
||||
OsString::from("baz"),
|
||||
]);
|
||||
assert_eq!(
|
||||
args,
|
||||
vec![
|
||||
OsString::from("quux"),
|
||||
OsString::from_vec(b"foo\xFFbar".to_vec()),
|
||||
OsString::from("baz"),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
// ... but test that invalid UTF-8 fails on Windows.
|
||||
#[test]
|
||||
#[cfg(not(unix))]
|
||||
fn error() {
|
||||
let (args, errs) = parse_reader(&b"\
|
||||
let (args, errs) = parse_reader(
|
||||
&b"\
|
||||
quux
|
||||
foo\xFFbar
|
||||
baz
|
||||
"[..]).unwrap();
|
||||
"[..],
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(errs.len(), 1);
|
||||
assert_eq!(args, vec![
|
||||
OsString::from("quux"),
|
||||
OsString::from("baz"),
|
||||
]);
|
||||
assert_eq!(args, vec![OsString::from("quux"), OsString::from("baz"),]);
|
||||
}
|
||||
}
|
||||
@@ -24,13 +24,13 @@ impl 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
|
||||
// implement filtering here.
|
||||
true
|
||||
}
|
||||
|
||||
fn log(&self, record: &log::Record) {
|
||||
fn log(&self, record: &log::Record<'_>) {
|
||||
match (record.file(), record.line()) {
|
||||
(Some(file), Some(line)) => {
|
||||
eprintln!(
|
||||
@@ -1,20 +1,7 @@
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
extern crate grep;
|
||||
extern crate ignore;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate num_cpus;
|
||||
extern crate regex;
|
||||
#[macro_use]
|
||||
extern crate serde_json;
|
||||
extern crate termcolor;
|
||||
|
||||
use std::error;
|
||||
use std::io::{self, Write};
|
||||
use std::process;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::Mutex;
|
||||
use std::time::Instant;
|
||||
|
||||
use ignore::WalkState;
|
||||
@@ -33,48 +20,77 @@ mod path_printer;
|
||||
mod search;
|
||||
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() {
|
||||
match Args::parse().and_then(try_main) {
|
||||
Ok(true) => process::exit(0),
|
||||
Ok(false) => process::exit(1),
|
||||
Err(err) => {
|
||||
eprintln!("{}", err);
|
||||
process::exit(2);
|
||||
}
|
||||
if let Err(err) = Args::parse().and_then(try_main) {
|
||||
eprintln!("{}", err);
|
||||
process::exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
fn try_main(args: Args) -> Result<bool> {
|
||||
fn try_main(args: Args) -> Result<()> {
|
||||
use args::Command::*;
|
||||
|
||||
match args.command()? {
|
||||
Search => search(args),
|
||||
SearchParallel => search_parallel(args),
|
||||
let matched = match args.command() {
|
||||
Search => search(&args),
|
||||
SearchParallel => search_parallel(&args),
|
||||
SearchNever => Ok(false),
|
||||
Files => files(args),
|
||||
FilesParallel => files_parallel(args),
|
||||
Types => types(args),
|
||||
Files => files(&args),
|
||||
FilesParallel => files_parallel(&args),
|
||||
Types => types(&args),
|
||||
PCRE2Version => pcre2_version(&args),
|
||||
}?;
|
||||
if matched && (args.quiet() || !messages::errored()) {
|
||||
process::exit(0)
|
||||
} else if messages::errored() {
|
||||
process::exit(2)
|
||||
} else {
|
||||
process::exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
/// The top-level entry point for single-threaded search. This recursively
|
||||
/// steps through the file list (current directory by default) and searches
|
||||
/// each file sequentially.
|
||||
fn search(args: Args) -> Result<bool> {
|
||||
fn search(args: &Args) -> Result<bool> {
|
||||
let started_at = Instant::now();
|
||||
let quit_after_match = args.quit_after_match()?;
|
||||
let subject_builder = args.subject_builder();
|
||||
let mut stats = args.stats()?;
|
||||
let mut searcher = args.search_worker(args.stdout())?;
|
||||
let mut matched = false;
|
||||
let mut searched = false;
|
||||
|
||||
for result in args.walker()? {
|
||||
let subject = match subject_builder.build_from_result(result) {
|
||||
Some(subject) => subject,
|
||||
None => continue,
|
||||
};
|
||||
searched = true;
|
||||
let search_result = match searcher.search(&subject) {
|
||||
Ok(search_result) => search_result,
|
||||
Err(err) => {
|
||||
@@ -82,7 +98,7 @@ fn search(args: Args) -> Result<bool> {
|
||||
if err.kind() == io::ErrorKind::BrokenPipe {
|
||||
break;
|
||||
}
|
||||
message!("{}: {}", subject.path().display(), err);
|
||||
err_message!("{}: {}", subject.path().display(), err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
@@ -94,6 +110,9 @@ fn search(args: Args) -> Result<bool> {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if args.using_default_path() && !searched {
|
||||
eprint_nothing_searched();
|
||||
}
|
||||
if let Some(ref stats) = stats {
|
||||
let elapsed = Instant::now().duration_since(started_at);
|
||||
// We don't care if we couldn't print this successfully.
|
||||
@@ -105,30 +124,29 @@ fn search(args: Args) -> Result<bool> {
|
||||
/// The top-level entry point for multi-threaded search. The parallelism is
|
||||
/// itself achieved by the recursive directory traversal. All we need to do is
|
||||
/// feed it a worker for performing a search on each file.
|
||||
fn search_parallel(args: Args) -> Result<bool> {
|
||||
fn search_parallel(args: &Args) -> Result<bool> {
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::Ordering::SeqCst;
|
||||
|
||||
let quit_after_match = args.quit_after_match()?;
|
||||
let started_at = Instant::now();
|
||||
let subject_builder = Arc::new(args.subject_builder());
|
||||
let bufwtr = Arc::new(args.buffer_writer()?);
|
||||
let stats = Arc::new(args.stats()?.map(Mutex::new));
|
||||
let matched = Arc::new(AtomicBool::new(false));
|
||||
let subject_builder = args.subject_builder();
|
||||
let bufwtr = args.buffer_writer()?;
|
||||
let stats = args.stats()?.map(Mutex::new);
|
||||
let matched = AtomicBool::new(false);
|
||||
let searched = AtomicBool::new(false);
|
||||
let mut searcher_err = None;
|
||||
args.walker_parallel()?.run(|| {
|
||||
let args = args.clone();
|
||||
let bufwtr = Arc::clone(&bufwtr);
|
||||
let stats = Arc::clone(&stats);
|
||||
let matched = Arc::clone(&matched);
|
||||
let subject_builder = Arc::clone(&subject_builder);
|
||||
let bufwtr = &bufwtr;
|
||||
let stats = &stats;
|
||||
let matched = &matched;
|
||||
let searched = &searched;
|
||||
let subject_builder = &subject_builder;
|
||||
let mut searcher = match args.search_worker(bufwtr.buffer()) {
|
||||
Ok(searcher) => searcher,
|
||||
Err(err) => {
|
||||
searcher_err = Some(err);
|
||||
return Box::new(move |_| {
|
||||
WalkState::Quit
|
||||
});
|
||||
return Box::new(move |_| WalkState::Quit);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -137,11 +155,12 @@ fn search_parallel(args: Args) -> Result<bool> {
|
||||
Some(subject) => subject,
|
||||
None => return WalkState::Continue,
|
||||
};
|
||||
searched.store(true, SeqCst);
|
||||
searcher.printer().get_mut().clear();
|
||||
let search_result = match searcher.search(&subject) {
|
||||
Ok(search_result) => search_result,
|
||||
Err(err) => {
|
||||
message!("{}: {}", subject.path().display(), err);
|
||||
err_message!("{}: {}", subject.path().display(), err);
|
||||
return WalkState::Continue;
|
||||
}
|
||||
};
|
||||
@@ -158,7 +177,7 @@ fn search_parallel(args: Args) -> Result<bool> {
|
||||
return WalkState::Quit;
|
||||
}
|
||||
// Otherwise, we continue on our merry way.
|
||||
message!("{}: {}", subject.path().display(), err);
|
||||
err_message!("{}: {}", subject.path().display(), err);
|
||||
}
|
||||
if matched.load(SeqCst) && quit_after_match {
|
||||
WalkState::Quit
|
||||
@@ -170,7 +189,10 @@ fn search_parallel(args: Args) -> Result<bool> {
|
||||
if let Some(err) = searcher_err.take() {
|
||||
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 stats = locked_stats.lock().unwrap();
|
||||
let mut searcher = args.search_worker(args.stdout())?;
|
||||
@@ -180,10 +202,18 @@ fn search_parallel(args: Args) -> Result<bool> {
|
||||
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
|
||||
/// recursively steps through the file list (current directory by default) and
|
||||
/// prints each path sequentially using a single thread.
|
||||
fn files(args: Args) -> Result<bool> {
|
||||
fn files(args: &Args) -> Result<bool> {
|
||||
let quit_after_match = args.quit_after_match()?;
|
||||
let subject_builder = args.subject_builder();
|
||||
let mut matched = false;
|
||||
@@ -213,16 +243,16 @@ fn files(args: Args) -> Result<bool> {
|
||||
/// The top-level entry point for listing files without searching them. This
|
||||
/// recursively steps through the file list (current directory by default) and
|
||||
/// prints each path sequentially using multiple threads.
|
||||
fn files_parallel(args: Args) -> Result<bool> {
|
||||
fn files_parallel(args: &Args) -> Result<bool> {
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::Ordering::SeqCst;
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
|
||||
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 matched = Arc::new(AtomicBool::new(false));
|
||||
let matched = AtomicBool::new(false);
|
||||
let (tx, rx) = mpsc::channel::<Subject>();
|
||||
|
||||
let print_thread = thread::spawn(move || -> io::Result<()> {
|
||||
@@ -232,8 +262,8 @@ fn files_parallel(args: Args) -> Result<bool> {
|
||||
Ok(())
|
||||
});
|
||||
args.walker_parallel()?.run(|| {
|
||||
let subject_builder = Arc::clone(&subject_builder);
|
||||
let matched = Arc::clone(&matched);
|
||||
let subject_builder = &subject_builder;
|
||||
let matched = &matched;
|
||||
let tx = tx.clone();
|
||||
|
||||
Box::new(move |result| {
|
||||
@@ -265,7 +295,7 @@ fn files_parallel(args: Args) -> Result<bool> {
|
||||
}
|
||||
|
||||
/// The top-level entry point for --type-list.
|
||||
fn types(args: Args) -> Result<bool> {
|
||||
fn types(args: &Args) -> Result<bool> {
|
||||
let mut count = 0;
|
||||
let mut stdout = args.stdout();
|
||||
for def in args.type_defs()? {
|
||||
@@ -285,3 +315,30 @@ fn types(args: Args) -> Result<bool> {
|
||||
}
|
||||
Ok(count > 0)
|
||||
}
|
||||
|
||||
/// The top-level entry point for --pcre2-version.
|
||||
fn pcre2_version(args: &Args) -> Result<bool> {
|
||||
#[cfg(feature = "pcre2")]
|
||||
fn imp(args: &Args) -> Result<bool> {
|
||||
use grep::pcre2;
|
||||
|
||||
let mut stdout = args.stdout();
|
||||
|
||||
let (major, minor) = pcre2::version();
|
||||
writeln!(stdout, "PCRE2 {}.{} is available", major, minor)?;
|
||||
|
||||
if cfg!(target_pointer_width = "64") && pcre2::is_jit_available() {
|
||||
writeln!(stdout, "JIT is available")?;
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "pcre2"))]
|
||||
fn imp(args: &Args) -> Result<bool> {
|
||||
let mut stdout = args.stdout();
|
||||
writeln!(stdout, "PCRE2 is not available in this build of ripgrep.")?;
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
imp(args)
|
||||
}
|
||||
@@ -1,21 +1,35 @@
|
||||
use std::sync::atomic::{ATOMIC_BOOL_INIT, AtomicBool, Ordering};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
static MESSAGES: AtomicBool = ATOMIC_BOOL_INIT;
|
||||
static IGNORE_MESSAGES: AtomicBool = ATOMIC_BOOL_INIT;
|
||||
static MESSAGES: AtomicBool = AtomicBool::new(false);
|
||||
static IGNORE_MESSAGES: AtomicBool = AtomicBool::new(false);
|
||||
static ERRORED: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
/// Emit a non-fatal error message, unless messages were disabled.
|
||||
#[macro_export]
|
||||
macro_rules! message {
|
||||
($($tt:tt)*) => {
|
||||
if ::messages::messages() {
|
||||
if crate::messages::messages() {
|
||||
eprintln!($($tt)*);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Like message, but sets ripgrep's "errored" flag, which controls the exit
|
||||
/// status.
|
||||
#[macro_export]
|
||||
macro_rules! err_message {
|
||||
($($tt:tt)*) => {
|
||||
crate::messages::set_errored();
|
||||
message!($($tt)*);
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit a non-fatal ignore-related error message (like a parse error), unless
|
||||
/// ignore-messages were disabled.
|
||||
#[macro_export]
|
||||
macro_rules! ignore_message {
|
||||
($($tt:tt)*) => {
|
||||
if ::messages::messages() && ::messages::ignore_messages() {
|
||||
if crate::messages::messages() && crate::messages::ignore_messages() {
|
||||
eprintln!($($tt)*);
|
||||
}
|
||||
}
|
||||
@@ -48,3 +62,13 @@ pub fn ignore_messages() -> bool {
|
||||
pub fn set_ignore_messages(yes: bool) {
|
||||
IGNORE_MESSAGES.store(yes, Ordering::SeqCst)
|
||||
}
|
||||
|
||||
/// Returns true if and only if ripgrep came across a non-fatal error.
|
||||
pub fn errored() -> bool {
|
||||
ERRORED.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
/// Indicate that ripgrep has come across a non-fatal error.
|
||||
pub fn set_errored() {
|
||||
ERRORED.store(true, Ordering::SeqCst);
|
||||
}
|
||||
@@ -37,10 +37,7 @@ impl PathPrinterBuilder {
|
||||
/// Create a new path printer with the current configuration that writes
|
||||
/// paths to the given writer.
|
||||
pub fn build<W: WriteColor>(&self, wtr: W) -> PathPrinter<W> {
|
||||
PathPrinter {
|
||||
config: self.config.clone(),
|
||||
wtr: wtr,
|
||||
}
|
||||
PathPrinter { config: self.config.clone(), wtr }
|
||||
}
|
||||
|
||||
/// Set the color specification for this printer.
|
||||
@@ -7,15 +7,16 @@ use std::time::Duration;
|
||||
use grep::cli;
|
||||
use grep::matcher::Matcher;
|
||||
#[cfg(feature = "pcre2")]
|
||||
use grep::pcre2::{RegexMatcher as PCRE2RegexMatcher};
|
||||
use grep::printer::{JSON, Standard, Summary, Stats};
|
||||
use grep::regex::{RegexMatcher as RustRegexMatcher};
|
||||
use grep::searcher::Searcher;
|
||||
use grep::pcre2::RegexMatcher as PCRE2RegexMatcher;
|
||||
use grep::printer::{Standard, Stats, Summary, JSON};
|
||||
use grep::regex::RegexMatcher as RustRegexMatcher;
|
||||
use grep::searcher::{BinaryDetection, Searcher};
|
||||
use ignore::overrides::Override;
|
||||
use serde_json as json;
|
||||
use serde_json::json;
|
||||
use termcolor::WriteColor;
|
||||
|
||||
use subject::Subject;
|
||||
use crate::subject::Subject;
|
||||
|
||||
/// The configuration for the search worker. Among a few other things, the
|
||||
/// configuration primarily controls the way we show search results to users
|
||||
@@ -26,6 +27,8 @@ struct Config {
|
||||
preprocessor: Option<PathBuf>,
|
||||
preprocessor_globs: Override,
|
||||
search_zip: bool,
|
||||
binary_implicit: BinaryDetection,
|
||||
binary_explicit: BinaryDetection,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
@@ -35,6 +38,8 @@ impl Default for Config {
|
||||
preprocessor: None,
|
||||
preprocessor_globs: Override::empty(),
|
||||
search_zip: false,
|
||||
binary_implicit: BinaryDetection::none(),
|
||||
binary_explicit: BinaryDetection::none(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,7 +70,7 @@ impl SearchWorkerBuilder {
|
||||
SearchWorkerBuilder {
|
||||
config: Config::default(),
|
||||
command_builder: cmd_builder,
|
||||
decomp_builder: decomp_builder,
|
||||
decomp_builder,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,8 +86,12 @@ impl SearchWorkerBuilder {
|
||||
let command_builder = self.command_builder.clone();
|
||||
let decomp_builder = self.decomp_builder.clone();
|
||||
SearchWorker {
|
||||
config, command_builder, decomp_builder,
|
||||
matcher, searcher, printer,
|
||||
config,
|
||||
command_builder,
|
||||
decomp_builder,
|
||||
matcher,
|
||||
searcher,
|
||||
printer,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,9 +115,14 @@ impl SearchWorkerBuilder {
|
||||
pub fn preprocessor(
|
||||
&mut self,
|
||||
cmd: Option<PathBuf>,
|
||||
) -> &mut SearchWorkerBuilder {
|
||||
self.config.preprocessor = cmd;
|
||||
self
|
||||
) -> crate::Result<&mut SearchWorkerBuilder> {
|
||||
if let Some(ref prog) = cmd {
|
||||
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
|
||||
@@ -133,6 +147,37 @@ impl SearchWorkerBuilder {
|
||||
self.config.search_zip = yes;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the binary detection that should be used when searching files
|
||||
/// found via a recursive directory search.
|
||||
///
|
||||
/// Generally, this binary detection may be `BinaryDetection::quit` if
|
||||
/// we want to skip binary files completely.
|
||||
///
|
||||
/// By default, no binary detection is performed.
|
||||
pub fn binary_detection_implicit(
|
||||
&mut self,
|
||||
detection: BinaryDetection,
|
||||
) -> &mut SearchWorkerBuilder {
|
||||
self.config.binary_implicit = detection;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the binary detection that should be used when searching files
|
||||
/// explicitly supplied by an end user.
|
||||
///
|
||||
/// Generally, this binary detection should NOT be `BinaryDetection::quit`,
|
||||
/// since we never want to automatically filter files supplied by the end
|
||||
/// user.
|
||||
///
|
||||
/// By default, no binary detection is performed.
|
||||
pub fn binary_detection_explicit(
|
||||
&mut self,
|
||||
detection: BinaryDetection,
|
||||
) -> &mut SearchWorkerBuilder {
|
||||
self.config.binary_explicit = detection;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// The result of executing a search.
|
||||
@@ -191,9 +236,7 @@ impl<W: WriteColor> Printer<W> {
|
||||
stats: &Stats,
|
||||
) -> io::Result<()> {
|
||||
match *self {
|
||||
Printer::JSON(_) => {
|
||||
self.print_stats_json(total_duration, stats)
|
||||
}
|
||||
Printer::JSON(_) => self.print_stats_json(total_duration, stats),
|
||||
Printer::Standard(_) | Printer::Summary(_) => {
|
||||
self.print_stats_human(total_duration, stats)
|
||||
}
|
||||
@@ -237,17 +280,20 @@ impl<W: WriteColor> Printer<W> {
|
||||
// the grep-printer crate. We simply "extend" it with the 'summary'
|
||||
// message type.
|
||||
let fractional = fractional_seconds(total_duration);
|
||||
json::to_writer(self.get_mut(), &json!({
|
||||
"type": "summary",
|
||||
"data": {
|
||||
"stats": stats,
|
||||
"elapsed_total": {
|
||||
"secs": total_duration.as_secs(),
|
||||
"nanos": total_duration.subsec_nanos(),
|
||||
"human": format!("{:0.6}s", fractional),
|
||||
},
|
||||
}
|
||||
}))?;
|
||||
json::to_writer(
|
||||
self.get_mut(),
|
||||
&json!({
|
||||
"type": "summary",
|
||||
"data": {
|
||||
"stats": stats,
|
||||
"elapsed_total": {
|
||||
"secs": total_duration.as_secs(),
|
||||
"nanos": total_duration.subsec_nanos(),
|
||||
"human": format!("{:0.6}s", fractional),
|
||||
},
|
||||
}
|
||||
}),
|
||||
)?;
|
||||
write!(self.get_mut(), "\n")
|
||||
}
|
||||
|
||||
@@ -279,7 +325,24 @@ pub struct SearchWorker<W> {
|
||||
impl<W: WriteColor> SearchWorker<W> {
|
||||
/// Execute a search over the given subject.
|
||||
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.
|
||||
@@ -305,22 +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 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
|
||||
/// decompressed before searching.
|
||||
fn should_decompress(&self, path: &Path) -> bool {
|
||||
@@ -348,28 +395,41 @@ impl<W: WriteColor> SearchWorker<W> {
|
||||
&mut self,
|
||||
path: &Path,
|
||||
) -> io::Result<SearchResult> {
|
||||
let bin = self.config.preprocessor.clone().unwrap();
|
||||
let mut cmd = Command::new(&bin);
|
||||
let bin = self.config.preprocessor.as_ref().unwrap();
|
||||
let mut cmd = Command::new(bin);
|
||||
cmd.arg(path).stdin(Stdio::from(File::open(path)?));
|
||||
|
||||
let rdr = self.command_builder.build(&mut cmd)?;
|
||||
self.search_reader(path, rdr).map_err(|err| {
|
||||
let mut rdr = self.command_builder.build(&mut cmd).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::ErrorKind::Other,
|
||||
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
|
||||
/// result. If the given file path isn't recognized as a compressed file,
|
||||
/// then search it without doing any decompression.
|
||||
fn search_decompress(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
) -> io::Result<SearchResult> {
|
||||
let rdr = self.decomp_builder.build(path)?;
|
||||
self.search_reader(path, rdr)
|
||||
fn search_decompress(&mut self, path: &Path) -> io::Result<SearchResult> {
|
||||
let mut rdr = self.decomp_builder.build(path)?;
|
||||
let result = self.search_reader(path, &mut rdr);
|
||||
let close_result = rdr.close();
|
||||
let search_result = result?;
|
||||
close_result?;
|
||||
Ok(search_result)
|
||||
}
|
||||
|
||||
/// Search the contents of the given file path.
|
||||
@@ -396,7 +456,7 @@ impl<W: WriteColor> SearchWorker<W> {
|
||||
fn search_reader<R: io::Read>(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
rdr: R,
|
||||
rdr: &mut R,
|
||||
) -> io::Result<SearchResult> {
|
||||
use self::PatternMatcher::*;
|
||||
|
||||
@@ -452,12 +512,12 @@ fn search_reader<M: Matcher, R: io::Read, W: WriteColor>(
|
||||
searcher: &mut Searcher,
|
||||
printer: &mut Printer<W>,
|
||||
path: &Path,
|
||||
rdr: R,
|
||||
mut rdr: R,
|
||||
) -> io::Result<SearchResult> {
|
||||
match *printer {
|
||||
Printer::Standard(ref mut p) => {
|
||||
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 {
|
||||
has_match: sink.has_match(),
|
||||
stats: sink.stats().map(|s| s.clone()),
|
||||
@@ -465,7 +525,7 @@ fn search_reader<M: Matcher, R: io::Read, W: WriteColor>(
|
||||
}
|
||||
Printer::Summary(ref mut p) => {
|
||||
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 {
|
||||
has_match: sink.has_match(),
|
||||
stats: sink.stats().map(|s| s.clone()),
|
||||
@@ -473,7 +533,7 @@ fn search_reader<M: Matcher, R: io::Read, W: WriteColor>(
|
||||
}
|
||||
Printer::JSON(ref mut p) => {
|
||||
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 {
|
||||
has_match: sink.has_match(),
|
||||
stats: Some(sink.stats().clone()),
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::path::Path;
|
||||
|
||||
use ignore::{self, DirEntry};
|
||||
use log;
|
||||
|
||||
/// A configuration for describing how subjects should be built.
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -10,9 +11,7 @@ struct Config {
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Config {
|
||||
Config {
|
||||
strip_dot_prefix: false,
|
||||
}
|
||||
Config { strip_dot_prefix: false }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +39,7 @@ impl SubjectBuilder {
|
||||
match result {
|
||||
Ok(dent) => self.build(dent),
|
||||
Err(err) => {
|
||||
message!("{}", err);
|
||||
err_message!("{}", err);
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -51,40 +50,33 @@ impl SubjectBuilder {
|
||||
/// If a subject could not be created or should otherwise not be searched,
|
||||
/// then this returns `None` after emitting any relevant log messages.
|
||||
pub fn build(&self, dent: DirEntry) -> Option<Subject> {
|
||||
let subj = Subject {
|
||||
dent: dent,
|
||||
strip_dot_prefix: self.config.strip_dot_prefix,
|
||||
};
|
||||
let subj =
|
||||
Subject { dent, strip_dot_prefix: self.config.strip_dot_prefix };
|
||||
if let Some(ignore_err) = subj.dent.error() {
|
||||
ignore_message!("{}", ignore_err);
|
||||
}
|
||||
// If this entry represents stdin, then we always search it.
|
||||
if subj.dent.is_stdin() {
|
||||
// If this entry was explicitly provided by an end user, then we always
|
||||
// want to search it.
|
||||
if subj.is_explicit() {
|
||||
return Some(subj);
|
||||
}
|
||||
// If this subject has a depth of 0, then it was provided explicitly
|
||||
// by an end user (or via a shell glob). In this case, we always want
|
||||
// to search it if it even smells like a file (e.g., a symlink).
|
||||
if subj.dent.depth() == 0 && !subj.is_dir() {
|
||||
return Some(subj);
|
||||
}
|
||||
// At this point, we only want to search something it's explicitly a
|
||||
// At this point, we only want to search something if it's explicitly a
|
||||
// file. This omits symlinks. (If ripgrep was configured to follow
|
||||
// symlinks, then they have already been followed by the directory
|
||||
// traversal.)
|
||||
if subj.is_file() {
|
||||
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
|
||||
// noisy.
|
||||
if !subj.is_dir() {
|
||||
debug!(
|
||||
log::debug!(
|
||||
"ignoring {}: failed to pass subject filter: \
|
||||
file type: {:?}, metadata: {:?}",
|
||||
subj.dent.path().display(),
|
||||
subj.dent.file_type(),
|
||||
subj.dent.metadata()
|
||||
subj.dent.path().display(),
|
||||
subj.dent.file_type(),
|
||||
subj.dent.metadata()
|
||||
);
|
||||
}
|
||||
None
|
||||
@@ -126,9 +118,39 @@ impl Subject {
|
||||
self.dent.is_stdin()
|
||||
}
|
||||
|
||||
/// Returns true if and only if this subject points to a directory.
|
||||
/// Returns true if and only if this entry corresponds to a subject to
|
||||
/// search that was explicitly supplied by an end user.
|
||||
///
|
||||
/// Generally, this corresponds to either stdin or an explicit file path
|
||||
/// argument. e.g., in `rg foo some-file ./some-dir/`, `some-file` is
|
||||
/// an explicit subject, but, e.g., `./some-dir/some-other-file` is not.
|
||||
///
|
||||
/// However, note that ripgrep does not see through shell globbing. e.g.,
|
||||
/// in `rg foo ./some-dir/*`, `./some-dir/some-other-file` will be treated
|
||||
/// as an explicit subject.
|
||||
pub fn is_explicit(&self) -> bool {
|
||||
// stdin is obvious. When an entry has a depth of 0, that means it
|
||||
// was explicitly provided to our directory iterator, which means it
|
||||
// was in turn explicitly provided by the end user. The !is_dir check
|
||||
// means that we want to search files even if their symlinks, again,
|
||||
// because they were explicitly provided. (And we never want to try
|
||||
// to search a directory.)
|
||||
self.is_stdin() || (self.dent.depth() == 0 && !self.is_dir())
|
||||
}
|
||||
|
||||
/// Returns true if and only if this subject points to a directory after
|
||||
/// following symbolic links.
|
||||
fn is_dir(&self) -> bool {
|
||||
self.dent.file_type().map_or(false, |ft| ft.is_dir())
|
||||
let ft = match self.dent.file_type() {
|
||||
None => return false,
|
||||
Some(ft) => ft,
|
||||
};
|
||||
if ft.is_dir() {
|
||||
return true;
|
||||
}
|
||||
// If this is a symlink, then we want to follow it to determine
|
||||
// whether it's a directory or not.
|
||||
self.dent.path_is_symlink() && self.dent.path().is_dir()
|
||||
}
|
||||
|
||||
/// Returns true if and only if this subject points to a file.
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "globset"
|
||||
version = "0.4.2" #:version
|
||||
version = "0.4.10" #:version
|
||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||
description = """
|
||||
Cross platform single glob and glob set matching. Glob set matching is the
|
||||
@@ -8,25 +8,31 @@ process of matching one or more glob patterns against a single candidate path
|
||||
simultaneously, and returning all of the globs that matched.
|
||||
"""
|
||||
documentation = "https://docs.rs/globset"
|
||||
homepage = "https://github.com/BurntSushi/ripgrep/tree/master/globset"
|
||||
repository = "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/crates/globset"
|
||||
readme = "README.md"
|
||||
keywords = ["regex", "glob", "multiple", "set", "pattern"]
|
||||
license = "Unlicense/MIT"
|
||||
license = "Unlicense OR MIT"
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
name = "globset"
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
aho-corasick = "0.6.8"
|
||||
aho-corasick = "0.7.3"
|
||||
bstr = { version = "1.1.0", default-features = false, features = ["std"] }
|
||||
fnv = "1.0.6"
|
||||
log = "0.4.5"
|
||||
memchr = "2.0.2"
|
||||
regex = "1.0.5"
|
||||
log = { version = "0.4.5", optional = true }
|
||||
regex = { version = "1.1.5", default-features = false, features = ["perf", "std"] }
|
||||
serde = { version = "1.0.104", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
glob = "0.2.11"
|
||||
glob = "0.3.0"
|
||||
lazy_static = "1"
|
||||
serde_json = "1.0.45"
|
||||
|
||||
[features]
|
||||
default = ["log"]
|
||||
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
|
||||
simultaneously, and returning all of the globs that matched.
|
||||
|
||||
[](https://travis-ci.org/BurntSushi/ripgrep)
|
||||
[](https://ci.appveyor.com/project/BurntSushi/ripgrep)
|
||||
[](https://github.com/BurntSushi/ripgrep/actions)
|
||||
[](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
|
||||
|
||||
@@ -20,14 +19,12 @@ Add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
globset = "0.3"
|
||||
globset = "0.4"
|
||||
```
|
||||
|
||||
and this to your crate root:
|
||||
### Features
|
||||
|
||||
```rust
|
||||
extern crate globset;
|
||||
```
|
||||
* `serde1`: Enables implementing Serde traits on the `Glob` type.
|
||||
|
||||
### 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
|
||||
executing them with the
|
||||
[`regex`](https://github.com/rust-lang-nursery/regex)
|
||||
[`regex`](https://github.com/rust-lang/regex)
|
||||
crate.
|
||||
|
||||
For single glob matching, performance of this crate should be roughly on par
|
||||
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`
|
||||
correspond to benchmarks for the `glob` library.)
|
||||
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)
|
||||
```
|
||||
|
||||
### 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}`.
|
||||
* Can match non-UTF-8 file paths correctly.
|
||||
@@ -4,16 +4,8 @@ tool itself, see the benchsuite directory.
|
||||
*/
|
||||
#![feature(test)]
|
||||
|
||||
extern crate glob;
|
||||
extern crate globset;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate regex;
|
||||
extern crate test;
|
||||
|
||||
use std::ffi::OsStr;
|
||||
use std::path::Path;
|
||||
|
||||
use globset::{Candidate, Glob, GlobMatcher, GlobSet, GlobSetBuilder};
|
||||
|
||||
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::iter;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::path::{Path, is_separator};
|
||||
use std::path::{is_separator, Path};
|
||||
use std::str;
|
||||
|
||||
use 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.
|
||||
///
|
||||
@@ -85,24 +85,32 @@ pub struct Glob {
|
||||
}
|
||||
|
||||
impl PartialEq for Glob {
|
||||
fn eq(&self, other: &Glob) -> bool {
|
||||
self.glob == other.glob && self.opts == other.opts
|
||||
}
|
||||
fn eq(&self, other: &Glob) -> bool {
|
||||
self.glob == other.glob && self.opts == other.opts
|
||||
}
|
||||
}
|
||||
|
||||
impl hash::Hash for Glob {
|
||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||
self.glob.hash(state);
|
||||
self.opts.hash(state);
|
||||
}
|
||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||
self.glob.hash(state);
|
||||
self.opts.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GlobMatcher {
|
||||
@@ -119,9 +127,14 @@ impl GlobMatcher {
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
|
||||
/// Returns the `Glob` used to compile this matcher.
|
||||
pub fn glob(&self) -> &Glob {
|
||||
&self.pat
|
||||
}
|
||||
}
|
||||
|
||||
/// A strategic matcher for a single pattern.
|
||||
@@ -130,8 +143,6 @@ impl GlobMatcher {
|
||||
struct GlobStrategic {
|
||||
/// The match strategy to use.
|
||||
strategy: MatchStrategy,
|
||||
/// The underlying pattern.
|
||||
pat: Glob,
|
||||
/// The pattern, as a compiled regex.
|
||||
re: Regex,
|
||||
}
|
||||
@@ -144,7 +155,7 @@ impl GlobStrategic {
|
||||
}
|
||||
|
||||
/// 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;
|
||||
|
||||
match self.strategy {
|
||||
@@ -214,11 +225,15 @@ struct Tokens(Vec<Token>);
|
||||
|
||||
impl Deref for Tokens {
|
||||
type Target = Vec<Token>;
|
||||
fn deref(&self) -> &Vec<Token> { &self.0 }
|
||||
fn deref(&self) -> &Vec<Token> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
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)]
|
||||
@@ -229,10 +244,7 @@ enum Token {
|
||||
RecursivePrefix,
|
||||
RecursiveSuffix,
|
||||
RecursiveZeroOrMore,
|
||||
Class {
|
||||
negated: bool,
|
||||
ranges: Vec<(char, char)>,
|
||||
},
|
||||
Class { negated: bool, ranges: Vec<(char, char)> },
|
||||
Alternates(Vec<Tokens>),
|
||||
}
|
||||
|
||||
@@ -244,12 +256,9 @@ impl Glob {
|
||||
|
||||
/// Returns a matcher for this pattern.
|
||||
pub fn compile_matcher(&self) -> GlobMatcher {
|
||||
let re = new_regex(&self.re)
|
||||
.expect("regex compilation shouldn't fail");
|
||||
GlobMatcher {
|
||||
pat: self.clone(),
|
||||
re: re,
|
||||
}
|
||||
let re =
|
||||
new_regex(&self.re).expect("regex compilation shouldn't fail");
|
||||
GlobMatcher { pat: self.clone(), re: re }
|
||||
}
|
||||
|
||||
/// Returns a strategic matcher.
|
||||
@@ -260,13 +269,9 @@ impl Glob {
|
||||
#[cfg(test)]
|
||||
fn compile_strategic_matcher(&self) -> GlobStrategic {
|
||||
let strategy = MatchStrategy::new(self);
|
||||
let re = new_regex(&self.re)
|
||||
.expect("regex compilation shouldn't fail");
|
||||
GlobStrategic {
|
||||
strategy: strategy,
|
||||
pat: self.clone(),
|
||||
re: re,
|
||||
}
|
||||
let re =
|
||||
new_regex(&self.re).expect("regex compilation shouldn't fail");
|
||||
GlobStrategic { strategy: strategy, re: re }
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// necessary but not sufficient for a match.
|
||||
fn required_ext(&self) -> Option<String> {
|
||||
@@ -396,7 +401,7 @@ impl Glob {
|
||||
if self.opts.case_insensitive {
|
||||
return None;
|
||||
}
|
||||
let end = match self.tokens.last() {
|
||||
let (end, need_sep) = match self.tokens.last() {
|
||||
Some(&Token::ZeroOrMore) => {
|
||||
if self.opts.literal_separator {
|
||||
// If a trailing `*` can't match a `/`, then we can't
|
||||
@@ -407,9 +412,10 @@ impl Glob {
|
||||
// literal prefix.
|
||||
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();
|
||||
for t in &self.tokens[0..end] {
|
||||
@@ -418,6 +424,9 @@ impl Glob {
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
if need_sep {
|
||||
lit.push('/');
|
||||
}
|
||||
if lit.is_empty() {
|
||||
None
|
||||
} else {
|
||||
@@ -524,7 +533,7 @@ impl Glob {
|
||||
| Token::RecursiveZeroOrMore => {
|
||||
return None;
|
||||
}
|
||||
Token::Class{..} | Token::Alternates(..) => {
|
||||
Token::Class { .. } | Token::Alternates(..) => {
|
||||
// We *could* be a little smarter here, but either one
|
||||
// of these is going to prevent our literal optimizations
|
||||
// anyway, so give up.
|
||||
@@ -561,10 +570,7 @@ impl<'a> GlobBuilder<'a> {
|
||||
///
|
||||
/// The pattern is not compiled until `build` is called.
|
||||
pub fn new(glob: &'a str) -> GlobBuilder<'a> {
|
||||
GlobBuilder {
|
||||
glob: glob,
|
||||
opts: GlobOptions::default(),
|
||||
}
|
||||
GlobBuilder { glob: glob, opts: GlobOptions::default() }
|
||||
}
|
||||
|
||||
/// Parses and builds the pattern.
|
||||
@@ -608,6 +614,8 @@ impl<'a> GlobBuilder<'a> {
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
self.opts.literal_separator = yes;
|
||||
self
|
||||
@@ -679,7 +687,7 @@ impl Tokens {
|
||||
re.push_str("(?:/?|.*/)");
|
||||
}
|
||||
Token::RecursiveSuffix => {
|
||||
re.push_str("(?:/?|/.*)");
|
||||
re.push_str("/.*");
|
||||
}
|
||||
Token::RecursiveZeroOrMore => {
|
||||
re.push_str("(?:/|/.*/)");
|
||||
@@ -837,40 +845,63 @@ impl<'a> Parser<'a> {
|
||||
|
||||
fn parse_star(&mut self) -> Result<(), Error> {
|
||||
let prev = self.prev;
|
||||
if self.chars.peek() != Some(&'*') {
|
||||
if self.peek() != Some('*') {
|
||||
self.push_token(Token::ZeroOrMore)?;
|
||||
return Ok(());
|
||||
}
|
||||
assert!(self.bump() == Some('*'));
|
||||
if !self.have_tokens()? {
|
||||
self.push_token(Token::RecursivePrefix)?;
|
||||
let next = self.bump();
|
||||
if !next.map(is_separator).unwrap_or(true) {
|
||||
return Err(self.error(ErrorKind::InvalidRecursive));
|
||||
if !self.peek().map_or(true, is_separator) {
|
||||
self.push_token(Token::ZeroOrMore)?;
|
||||
self.push_token(Token::ZeroOrMore)?;
|
||||
} else {
|
||||
self.push_token(Token::RecursivePrefix)?;
|
||||
assert!(self.bump().map_or(true, is_separator));
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
self.pop_token()?;
|
||||
|
||||
if !prev.map(is_separator).unwrap_or(false) {
|
||||
if self.stack.len() <= 1
|
||||
|| (prev != Some(',') && prev != Some('{')) {
|
||||
return Err(self.error(ErrorKind::InvalidRecursive));
|
||||
|| (prev != Some(',') && prev != Some('{'))
|
||||
{
|
||||
self.push_token(Token::ZeroOrMore)?;
|
||||
self.push_token(Token::ZeroOrMore)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
match self.chars.peek() {
|
||||
let is_suffix = match self.peek() {
|
||||
None => {
|
||||
assert!(self.bump().is_none());
|
||||
self.push_token(Token::RecursiveSuffix)
|
||||
true
|
||||
}
|
||||
Some(&',') | Some(&'}') if self.stack.len() >= 2 => {
|
||||
self.push_token(Token::RecursiveSuffix)
|
||||
}
|
||||
Some(&c) if is_separator(c) => {
|
||||
Some(',') | Some('}') if self.stack.len() >= 2 => true,
|
||||
Some(c) if is_separator(c) => {
|
||||
assert!(self.bump().map(is_separator).unwrap_or(false));
|
||||
self.push_token(Token::RecursiveZeroOrMore)
|
||||
false
|
||||
}
|
||||
_ => {
|
||||
self.push_token(Token::ZeroOrMore)?;
|
||||
self.push_token(Token::ZeroOrMore)?;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
match self.pop_token()? {
|
||||
Token::RecursivePrefix => {
|
||||
self.push_token(Token::RecursivePrefix)?;
|
||||
}
|
||||
Token::RecursiveSuffix => {
|
||||
self.push_token(Token::RecursiveSuffix)?;
|
||||
}
|
||||
_ => {
|
||||
if is_suffix {
|
||||
self.push_token(Token::RecursiveSuffix)?;
|
||||
} else {
|
||||
self.push_token(Token::RecursiveZeroOrMore)?;
|
||||
}
|
||||
}
|
||||
_ => Err(self.error(ErrorKind::InvalidRecursive)),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_class(&mut self) -> Result<(), Error> {
|
||||
@@ -934,7 +965,10 @@ impl<'a> Parser<'a> {
|
||||
// invariant: in_range is only set when there is
|
||||
// already at least one character seen.
|
||||
add_to_last_range(
|
||||
&self.glob, ranges.last_mut().unwrap(), c)?;
|
||||
&self.glob,
|
||||
ranges.last_mut().unwrap(),
|
||||
c,
|
||||
)?;
|
||||
} else {
|
||||
ranges.push((c, c));
|
||||
}
|
||||
@@ -948,10 +982,7 @@ impl<'a> Parser<'a> {
|
||||
// it as a literal.
|
||||
ranges.push(('-', '-'));
|
||||
}
|
||||
self.push_token(Token::Class {
|
||||
negated: negated,
|
||||
ranges: ranges,
|
||||
})
|
||||
self.push_token(Token::Class { negated: negated, ranges: ranges })
|
||||
}
|
||||
|
||||
fn bump(&mut self) -> Option<char> {
|
||||
@@ -959,6 +990,10 @@ impl<'a> Parser<'a> {
|
||||
self.cur = self.chars.next();
|
||||
self.cur
|
||||
}
|
||||
|
||||
fn peek(&mut self) -> Option<char> {
|
||||
self.chars.peek().map(|&ch| ch)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -976,9 +1011,9 @@ fn ends_with(needle: &[u8], haystack: &[u8]) -> bool {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use {GlobSetBuilder, ErrorKind};
|
||||
use super::{Glob, GlobBuilder, Token};
|
||||
use super::Token::*;
|
||||
use super::{Glob, GlobBuilder, Token};
|
||||
use crate::{ErrorKind, GlobSetBuilder};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
struct Options {
|
||||
@@ -994,7 +1029,7 @@ mod tests {
|
||||
let pat = Glob::new($pat).unwrap();
|
||||
assert_eq!($tokens, pat.tokens.0);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! syntaxerr {
|
||||
@@ -1004,7 +1039,7 @@ mod tests {
|
||||
let err = Glob::new($pat).unwrap_err();
|
||||
assert_eq!(&$err, err.kind());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! toregex {
|
||||
@@ -1086,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 {
|
||||
Class { negated: false, ranges: vec![(s, e)] }
|
||||
@@ -1110,16 +1147,20 @@ mod tests {
|
||||
syntax!(any2, "a?b", vec![Literal('a'), Any, Literal('b')]);
|
||||
syntax!(seq1, "*", vec![ZeroOrMore]);
|
||||
syntax!(seq2, "a*b", vec![Literal('a'), ZeroOrMore, Literal('b')]);
|
||||
syntax!(seq3, "*a*b*", vec![
|
||||
ZeroOrMore, Literal('a'), ZeroOrMore, Literal('b'), ZeroOrMore,
|
||||
]);
|
||||
syntax!(
|
||||
seq3,
|
||||
"*a*b*",
|
||||
vec![ZeroOrMore, Literal('a'), ZeroOrMore, Literal('b'), ZeroOrMore,]
|
||||
);
|
||||
syntax!(rseq1, "**", vec![RecursivePrefix]);
|
||||
syntax!(rseq2, "**/", vec![RecursivePrefix]);
|
||||
syntax!(rseq3, "/**", vec![RecursiveSuffix]);
|
||||
syntax!(rseq4, "/**/", vec![RecursiveZeroOrMore]);
|
||||
syntax!(rseq5, "a/**/b", vec![
|
||||
Literal('a'), RecursiveZeroOrMore, Literal('b'),
|
||||
]);
|
||||
syntax!(
|
||||
rseq5,
|
||||
"a/**/b",
|
||||
vec![Literal('a'), RecursiveZeroOrMore, Literal('b'),]
|
||||
);
|
||||
syntax!(cls1, "[a]", vec![class('a', 'a')]);
|
||||
syntax!(cls2, "[!a]", vec![classn('a', 'a')]);
|
||||
syntax!(cls3, "[a-z]", vec![class('a', 'z')]);
|
||||
@@ -1131,9 +1172,11 @@ mod tests {
|
||||
syntax!(cls9, "[a-]", vec![rclass(&[('a', 'a'), ('-', '-')])]);
|
||||
syntax!(cls10, "[-a-z]", vec![rclass(&[('-', '-'), ('a', 'z')])]);
|
||||
syntax!(cls11, "[a-z-]", vec![rclass(&[('a', 'z'), ('-', '-')])]);
|
||||
syntax!(cls12, "[-a-z-]", vec![
|
||||
rclass(&[('-', '-'), ('a', 'z'), ('-', '-')]),
|
||||
]);
|
||||
syntax!(
|
||||
cls12,
|
||||
"[-a-z-]",
|
||||
vec![rclass(&[('-', '-'), ('a', 'z'), ('-', '-')]),]
|
||||
);
|
||||
syntax!(cls13, "[]-z]", vec![class(']', 'z')]);
|
||||
syntax!(cls14, "[--z]", vec![class('-', 'z')]);
|
||||
syntax!(cls15, "[ --]", vec![class(' ', '-')]);
|
||||
@@ -1144,13 +1187,6 @@ mod tests {
|
||||
syntax!(cls20, "[^a]", vec![classn('a', 'a')]);
|
||||
syntax!(cls21, "[^a-z]", vec![classn('a', 'z')]);
|
||||
|
||||
syntaxerr!(err_rseq1, "a**", ErrorKind::InvalidRecursive);
|
||||
syntaxerr!(err_rseq2, "**a", ErrorKind::InvalidRecursive);
|
||||
syntaxerr!(err_rseq3, "a**b", ErrorKind::InvalidRecursive);
|
||||
syntaxerr!(err_rseq4, "***", ErrorKind::InvalidRecursive);
|
||||
syntaxerr!(err_rseq5, "/a**", ErrorKind::InvalidRecursive);
|
||||
syntaxerr!(err_rseq6, "/**a", ErrorKind::InvalidRecursive);
|
||||
syntaxerr!(err_rseq7, "/a**b", ErrorKind::InvalidRecursive);
|
||||
syntaxerr!(err_unclosed1, "[", ErrorKind::UnclosedClass);
|
||||
syntaxerr!(err_unclosed2, "[]", ErrorKind::UnclosedClass);
|
||||
syntaxerr!(err_unclosed3, "[!", ErrorKind::UnclosedClass);
|
||||
@@ -1158,26 +1194,14 @@ mod tests {
|
||||
syntaxerr!(err_range1, "[z-a]", ErrorKind::InvalidRange('z', 'a'));
|
||||
syntaxerr!(err_range2, "[z--]", ErrorKind::InvalidRange('z', '-'));
|
||||
|
||||
const CASEI: Options = Options {
|
||||
casei: Some(true),
|
||||
litsep: None,
|
||||
bsesc: None,
|
||||
};
|
||||
const SLASHLIT: Options = Options {
|
||||
casei: None,
|
||||
litsep: 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),
|
||||
};
|
||||
const CASEI: Options =
|
||||
Options { casei: Some(true), litsep: None, bsesc: None };
|
||||
const SLASHLIT: Options =
|
||||
Options { casei: None, litsep: 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);
|
||||
|
||||
@@ -1194,8 +1218,30 @@ mod tests {
|
||||
toregex!(re8, "[*]", r"^[\*]$");
|
||||
toregex!(re9, "[+]", r"^[\+]$");
|
||||
toregex!(re10, "+", r"^\+$");
|
||||
toregex!(re11, "**", r"^.*$");
|
||||
toregex!(re12, "☃", r"^\xe2\x98\x83$");
|
||||
toregex!(re11, "☃", r"^\xe2\x98\x83$");
|
||||
toregex!(re12, "**", r"^.*$");
|
||||
toregex!(re13, "**/", r"^.*$");
|
||||
toregex!(re14, "**/*", r"^(?:/?|.*/).*$");
|
||||
toregex!(re15, "**/**", r"^.*$");
|
||||
toregex!(re16, "**/**/*", r"^(?:/?|.*/).*$");
|
||||
toregex!(re17, "**/**/**", r"^.*$");
|
||||
toregex!(re18, "**/**/**/*", r"^(?:/?|.*/).*$");
|
||||
toregex!(re19, "a/**", r"^a/.*$");
|
||||
toregex!(re20, "a/**/**", r"^a/.*$");
|
||||
toregex!(re21, "a/**/**/**", r"^a/.*$");
|
||||
toregex!(re22, "a/**/b", r"^a(?:/|/.*/)b$");
|
||||
toregex!(re23, "a/**/**/b", r"^a(?:/|/.*/)b$");
|
||||
toregex!(re24, "a/**/**/**/b", r"^a(?:/|/.*/)b$");
|
||||
toregex!(re25, "**/b", r"^(?:/?|.*/)b$");
|
||||
toregex!(re26, "**/**/b", r"^(?:/?|.*/)b$");
|
||||
toregex!(re27, "**/**/**/b", r"^(?:/?|.*/)b$");
|
||||
toregex!(re28, "a**", r"^a.*.*$");
|
||||
toregex!(re29, "**a", r"^.*.*a$");
|
||||
toregex!(re30, "a**b", r"^a.*.*b$");
|
||||
toregex!(re31, "***", r"^.*.*.*$");
|
||||
toregex!(re32, "/a**", r"^/a.*.*$");
|
||||
toregex!(re33, "/**a", r"^/.*.*a$");
|
||||
toregex!(re34, "/a**b", r"^/a.*.*b$");
|
||||
|
||||
matches!(match1, "a", "a");
|
||||
matches!(match2, "a*b", "a_b");
|
||||
@@ -1228,11 +1274,12 @@ mod tests {
|
||||
matches!(matchrec18, "/**/test", "/test");
|
||||
matches!(matchrec19, "**/.*", ".abc");
|
||||
matches!(matchrec20, "**/.*", "abc/.abc");
|
||||
matches!(matchrec21, ".*/**", ".abc");
|
||||
matches!(matchrec21, "**/foo/bar", "foo/bar");
|
||||
matches!(matchrec22, ".*/**", ".abc/abc");
|
||||
matches!(matchrec23, "foo/**", "foo");
|
||||
matches!(matchrec24, "**/foo/bar", "foo/bar");
|
||||
matches!(matchrec25, "some/*/needle.txt", "some/one/needle.txt");
|
||||
matches!(matchrec23, "test/**", "test/");
|
||||
matches!(matchrec24, "test/**", "test/one");
|
||||
matches!(matchrec25, "test/**", "test/one/two");
|
||||
matches!(matchrec26, "some/*/needle.txt", "some/one/needle.txt");
|
||||
|
||||
matches!(matchrange1, "a[0-9]b", "a0b");
|
||||
matches!(matchrange2, "a[0-9]b", "a9b");
|
||||
@@ -1253,8 +1300,11 @@ mod tests {
|
||||
matches!(matchpat4, "*hello.txt", "some\\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!(matchpat7, "*some/path/to/hello.txt",
|
||||
"a/bigger/some/path/to/hello.txt");
|
||||
matches!(
|
||||
matchpat7,
|
||||
"*some/path/to/hello.txt",
|
||||
"a/bigger/some/path/to/hello.txt"
|
||||
);
|
||||
|
||||
matches!(matchescape, "_[[]_[]]_[?]_[*]_!_", "_[_]_?_*_!_");
|
||||
|
||||
@@ -1317,28 +1367,46 @@ mod tests {
|
||||
nmatches!(matchnot15, "[!-]", "-");
|
||||
nmatches!(matchnot16, "*hello.txt", "hello.txt-and-then-some");
|
||||
nmatches!(matchnot17, "*hello.txt", "goodbye.txt");
|
||||
nmatches!(matchnot18, "*some/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!(
|
||||
matchnot18,
|
||||
"*some/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!(matchnot21, "./foo", "foo");
|
||||
nmatches!(matchnot22, "**/foo", "foofoo");
|
||||
nmatches!(matchnot23, "**/foo/bar", "foofoo/bar");
|
||||
nmatches!(matchnot24, "/*.c", "mozilla-sha1/sha1.c");
|
||||
nmatches!(matchnot25, "*.c", "mozilla-sha1/sha1.c", SLASHLIT);
|
||||
nmatches!(matchnot26, "**/m4/ltoptions.m4",
|
||||
"csharp/src/packages/repositories.config", SLASHLIT);
|
||||
nmatches!(
|
||||
matchnot26,
|
||||
"**/m4/ltoptions.m4",
|
||||
"csharp/src/packages/repositories.config",
|
||||
SLASHLIT
|
||||
);
|
||||
nmatches!(matchnot27, "a[^0-9]b", "a0b");
|
||||
nmatches!(matchnot28, "a[^0-9]b", "a9b");
|
||||
nmatches!(matchnot29, "[^-]", "-");
|
||||
nmatches!(matchnot30, "some/*/needle.txt", "some/needle.txt");
|
||||
nmatches!(
|
||||
matchrec31,
|
||||
"some/*/needle.txt", "some/one/two/needle.txt", SLASHLIT);
|
||||
"some/*/needle.txt",
|
||||
"some/one/two/needle.txt",
|
||||
SLASHLIT
|
||||
);
|
||||
nmatches!(
|
||||
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 {
|
||||
($which:ident, $name:ident, $pat:expr, $expect:expr) => {
|
||||
@@ -1400,19 +1468,27 @@ mod tests {
|
||||
literal!(extract_lit7, "foo/bar", Some(s("foo/bar")));
|
||||
literal!(extract_lit8, "**/foo/bar", None);
|
||||
|
||||
basetokens!(extract_basetoks1, "**/foo", Some(&*vec![
|
||||
Literal('f'), Literal('o'), Literal('o'),
|
||||
]));
|
||||
basetokens!(
|
||||
extract_basetoks1,
|
||||
"**/foo",
|
||||
Some(&*vec![Literal('f'), Literal('o'), Literal('o'),])
|
||||
);
|
||||
basetokens!(extract_basetoks2, "**/foo", None, CASEI);
|
||||
basetokens!(extract_basetoks3, "**/foo", Some(&*vec![
|
||||
Literal('f'), Literal('o'), Literal('o'),
|
||||
]), SLASHLIT);
|
||||
basetokens!(
|
||||
extract_basetoks3,
|
||||
"**/foo",
|
||||
Some(&*vec![Literal('f'), Literal('o'), Literal('o'),]),
|
||||
SLASHLIT
|
||||
);
|
||||
basetokens!(extract_basetoks4, "*foo", None, SLASHLIT);
|
||||
basetokens!(extract_basetoks5, "*foo", None);
|
||||
basetokens!(extract_basetoks6, "**/fo*o", None);
|
||||
basetokens!(extract_basetoks7, "**/fo*o", Some(&*vec![
|
||||
Literal('f'), Literal('o'), ZeroOrMore, Literal('o'),
|
||||
]), SLASHLIT);
|
||||
basetokens!(
|
||||
extract_basetoks7,
|
||||
"**/fo*o",
|
||||
Some(&*vec![Literal('f'), Literal('o'), ZeroOrMore, Literal('o'),]),
|
||||
SLASHLIT
|
||||
);
|
||||
|
||||
ext!(extract_ext1, "**/*.rs", Some(s(".rs")));
|
||||
ext!(extract_ext2, "**/*.rs.bak", None);
|
||||
@@ -1435,7 +1511,7 @@ mod tests {
|
||||
prefix!(extract_prefix1, "/foo", Some(s("/foo")));
|
||||
prefix!(extract_prefix2, "/foo/*", Some(s("/foo/")));
|
||||
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_suffix2, "*/foo/bar", Some((s("/foo/bar"), false)));
|
||||
@@ -103,34 +103,38 @@ or to enable case insensitive matching.
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
extern crate aho_corasick;
|
||||
extern crate fnv;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate memchr;
|
||||
extern crate regex;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::error::Error as StdError;
|
||||
use std::ffi::OsStr;
|
||||
use std::fmt;
|
||||
use std::hash;
|
||||
use std::path::Path;
|
||||
use std::str;
|
||||
|
||||
use aho_corasick::{Automaton, AcAutomaton, FullAcAutomaton};
|
||||
use aho_corasick::AhoCorasick;
|
||||
use bstr::{ByteSlice, ByteVec, B};
|
||||
use regex::bytes::{Regex, RegexBuilder, RegexSet};
|
||||
|
||||
use pathutil::{
|
||||
file_name, file_name_ext, normalize_path, os_str_bytes, path_bytes,
|
||||
};
|
||||
use glob::MatchStrategy;
|
||||
pub use glob::{Glob, GlobBuilder, GlobMatcher};
|
||||
use crate::glob::MatchStrategy;
|
||||
pub use crate::glob::{Glob, GlobBuilder, GlobMatcher};
|
||||
use crate::pathutil::{file_name, file_name_ext, normalize_path};
|
||||
|
||||
mod glob;
|
||||
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.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Error {
|
||||
@@ -143,8 +147,13 @@ pub struct Error {
|
||||
/// The kind of error that can occur when parsing a glob pattern.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum ErrorKind {
|
||||
/// Occurs when a use of `**` is invalid. Namely, `**` can only appear
|
||||
/// adjacent to a path separator, or the beginning/end of a glob.
|
||||
/// **DEPRECATED**.
|
||||
///
|
||||
/// This error used to occur for consistency with git's glob specification,
|
||||
/// but the specification now accepts all uses of `**`. When `**` does not
|
||||
/// appear adjacent to a path separator or at the beginning/end of a glob,
|
||||
/// it is now treated as two consecutive `*` patterns. As such, this error
|
||||
/// is no longer used.
|
||||
InvalidRecursive,
|
||||
/// Occurs when a character class (e.g., `[abc]`) is not closed.
|
||||
UnclosedClass,
|
||||
@@ -199,9 +208,7 @@ impl ErrorKind {
|
||||
ErrorKind::UnclosedClass => {
|
||||
"unclosed character class; missing ']'"
|
||||
}
|
||||
ErrorKind::InvalidRange(_, _) => {
|
||||
"invalid character range"
|
||||
}
|
||||
ErrorKind::InvalidRange(_, _) => "invalid character range",
|
||||
ErrorKind::UnopenedAlternates => {
|
||||
"unopened alternate group; missing '{' \
|
||||
(maybe escape '}' with '[}]'?)"
|
||||
@@ -213,9 +220,7 @@ impl ErrorKind {
|
||||
ErrorKind::NestedAlternates => {
|
||||
"nested alternate groups are not allowed"
|
||||
}
|
||||
ErrorKind::DanglingEscape => {
|
||||
"dangling '\\'"
|
||||
}
|
||||
ErrorKind::DanglingEscape => "dangling '\\'",
|
||||
ErrorKind::Regex(ref err) => err,
|
||||
ErrorKind::__Nonexhaustive => unreachable!(),
|
||||
}
|
||||
@@ -223,7 +228,7 @@ impl ErrorKind {
|
||||
}
|
||||
|
||||
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 {
|
||||
None => self.kind.fmt(f),
|
||||
Some(ref glob) => {
|
||||
@@ -234,7 +239,7 @@ impl fmt::Display for Error {
|
||||
}
|
||||
|
||||
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 {
|
||||
ErrorKind::InvalidRecursive
|
||||
| ErrorKind::UnclosedClass
|
||||
@@ -242,9 +247,7 @@ impl fmt::Display for ErrorKind {
|
||||
| ErrorKind::UnclosedAlternates
|
||||
| ErrorKind::NestedAlternates
|
||||
| ErrorKind::DanglingEscape
|
||||
| ErrorKind::Regex(_) => {
|
||||
write!(f, "{}", self.description())
|
||||
}
|
||||
| ErrorKind::Regex(_) => write!(f, "{}", self.description()),
|
||||
ErrorKind::InvalidRange(s, e) => {
|
||||
write!(f, "invalid range; '{}' > '{}'", s, e)
|
||||
}
|
||||
@@ -259,21 +262,20 @@ fn new_regex(pat: &str) -> Result<Regex, Error> {
|
||||
.size_limit(10 * (1 << 20))
|
||||
.dfa_size_limit(10 * (1 << 20))
|
||||
.build()
|
||||
.map_err(|err| {
|
||||
Error {
|
||||
glob: Some(pat.to_string()),
|
||||
kind: ErrorKind::Regex(err.to_string()),
|
||||
}
|
||||
.map_err(|err| Error {
|
||||
glob: Some(pat.to_string()),
|
||||
kind: ErrorKind::Regex(err.to_string()),
|
||||
})
|
||||
}
|
||||
|
||||
fn new_regex_set<I, S>(pats: I) -> Result<RegexSet, Error>
|
||||
where S: AsRef<str>, I: IntoIterator<Item=S> {
|
||||
RegexSet::new(pats).map_err(|err| {
|
||||
Error {
|
||||
glob: None,
|
||||
kind: ErrorKind::Regex(err.to_string()),
|
||||
}
|
||||
where
|
||||
S: AsRef<str>,
|
||||
I: IntoIterator<Item = S>,
|
||||
{
|
||||
RegexSet::new(pats).map_err(|err| Error {
|
||||
glob: None,
|
||||
kind: ErrorKind::Regex(err.to_string()),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -289,19 +291,19 @@ pub struct GlobSet {
|
||||
|
||||
impl GlobSet {
|
||||
/// Create an empty `GlobSet`. An empty set matches nothing.
|
||||
#[inline]
|
||||
pub fn empty() -> GlobSet {
|
||||
GlobSet {
|
||||
len: 0,
|
||||
strats: vec![],
|
||||
}
|
||||
GlobSet { len: 0, strats: vec![] }
|
||||
}
|
||||
|
||||
/// Returns true if this set is empty, and therefore matches nothing.
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len == 0
|
||||
}
|
||||
|
||||
/// Returns the number of globs in this set.
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
@@ -315,7 +317,7 @@ impl GlobSet {
|
||||
///
|
||||
/// This takes a Candidate as input, which can be used to amortize the
|
||||
/// 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() {
|
||||
return false;
|
||||
}
|
||||
@@ -338,7 +340,7 @@ impl GlobSet {
|
||||
///
|
||||
/// This takes a Candidate as input, which can be used to amortize the
|
||||
/// 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![];
|
||||
if self.is_empty() {
|
||||
return into;
|
||||
@@ -350,7 +352,7 @@ impl GlobSet {
|
||||
/// Adds the sequence number of every glob pattern that matches the 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
|
||||
/// were matched, then `into` will be empty.
|
||||
pub fn matches_into<P: AsRef<Path>>(
|
||||
@@ -364,7 +366,7 @@ impl GlobSet {
|
||||
/// Adds the sequence number of every glob pattern that matches the 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
|
||||
/// were matched, then `into` will be empty.
|
||||
///
|
||||
@@ -372,7 +374,7 @@ impl GlobSet {
|
||||
/// cost of preparing a path for matching.
|
||||
pub fn matches_candidate_into(
|
||||
&self,
|
||||
path: &Candidate,
|
||||
path: &Candidate<'_>,
|
||||
into: &mut Vec<usize>,
|
||||
) {
|
||||
into.clear();
|
||||
@@ -426,11 +428,17 @@ impl GlobSet {
|
||||
}
|
||||
}
|
||||
}
|
||||
debug!("built glob set; {} literals, {} basenames, {} extensions, \
|
||||
debug!(
|
||||
"built glob set; {} literals, {} basenames, {} extensions, \
|
||||
{} prefixes, {} suffixes, {} required extensions, {} regexes",
|
||||
lits.0.len(), base_lits.0.len(), exts.0.len(),
|
||||
prefixes.literals.len(), suffixes.literals.len(),
|
||||
required_exts.0.len(), regexes.literals.len());
|
||||
lits.0.len(),
|
||||
base_lits.0.len(),
|
||||
exts.0.len(),
|
||||
prefixes.literals.len(),
|
||||
suffixes.literals.len(),
|
||||
required_exts.0.len(),
|
||||
regexes.literals.len()
|
||||
);
|
||||
Ok(GlobSet {
|
||||
len: pats.len(),
|
||||
strats: vec![
|
||||
@@ -440,13 +448,21 @@ impl GlobSet {
|
||||
GlobSetMatchStrategy::Suffix(suffixes.suffix()),
|
||||
GlobSetMatchStrategy::Prefix(prefixes.prefix()),
|
||||
GlobSetMatchStrategy::RequiredExtension(
|
||||
required_exts.build()?),
|
||||
required_exts.build()?,
|
||||
),
|
||||
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
|
||||
/// simultaneously match a file path.
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -492,13 +508,10 @@ pub struct Candidate<'a> {
|
||||
impl<'a> Candidate<'a> {
|
||||
/// Create a new candidate for matching from the given path.
|
||||
pub fn new<P: AsRef<Path> + ?Sized>(path: &'a P) -> Candidate<'a> {
|
||||
let path = path.as_ref();
|
||||
let basename = file_name(path).unwrap_or(OsStr::new(""));
|
||||
Candidate {
|
||||
path: normalize_path(path_bytes(path)),
|
||||
basename: os_str_bytes(basename),
|
||||
ext: file_name_ext(basename).unwrap_or(Cow::Borrowed(b"")),
|
||||
}
|
||||
let path = normalize_path(Vec::from_path_lossy(path.as_ref()));
|
||||
let basename = file_name(&path).unwrap_or(Cow::Borrowed(B("")));
|
||||
let ext = file_name_ext(&basename).unwrap_or(Cow::Borrowed(B("")));
|
||||
Candidate { path: path, basename: basename, ext: ext }
|
||||
}
|
||||
|
||||
fn path_prefix(&self, max: usize) -> &[u8] {
|
||||
@@ -530,7 +543,7 @@ enum GlobSetMatchStrategy {
|
||||
}
|
||||
|
||||
impl GlobSetMatchStrategy {
|
||||
fn is_match(&self, candidate: &Candidate) -> bool {
|
||||
fn is_match(&self, candidate: &Candidate<'_>) -> bool {
|
||||
use self::GlobSetMatchStrategy::*;
|
||||
match *self {
|
||||
Literal(ref s) => s.is_match(candidate),
|
||||
@@ -543,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::*;
|
||||
match *self {
|
||||
Literal(ref s) => s.matches_into(candidate, matches),
|
||||
@@ -569,13 +586,17 @@ impl LiteralStrategy {
|
||||
self.0.entry(lit.into_bytes()).or_insert(vec![]).push(global_index);
|
||||
}
|
||||
|
||||
fn is_match(&self, candidate: &Candidate) -> bool {
|
||||
self.0.contains_key(&*candidate.path)
|
||||
fn is_match(&self, candidate: &Candidate<'_>) -> bool {
|
||||
self.0.contains_key(candidate.path.as_bytes())
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn matches_into(&self, candidate: &Candidate, matches: &mut Vec<usize>) {
|
||||
if let Some(hits) = self.0.get(&*candidate.path) {
|
||||
fn matches_into(
|
||||
&self,
|
||||
candidate: &Candidate<'_>,
|
||||
matches: &mut Vec<usize>,
|
||||
) {
|
||||
if let Some(hits) = self.0.get(candidate.path.as_bytes()) {
|
||||
matches.extend(hits);
|
||||
}
|
||||
}
|
||||
@@ -593,19 +614,23 @@ impl BasenameLiteralStrategy {
|
||||
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() {
|
||||
return false;
|
||||
}
|
||||
self.0.contains_key(&*candidate.basename)
|
||||
self.0.contains_key(candidate.basename.as_bytes())
|
||||
}
|
||||
|
||||
#[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() {
|
||||
return;
|
||||
}
|
||||
if let Some(hits) = self.0.get(&*candidate.basename) {
|
||||
if let Some(hits) = self.0.get(candidate.basename.as_bytes()) {
|
||||
matches.extend(hits);
|
||||
}
|
||||
}
|
||||
@@ -623,19 +648,23 @@ impl ExtensionStrategy {
|
||||
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() {
|
||||
return false;
|
||||
}
|
||||
self.0.contains_key(&*candidate.ext)
|
||||
self.0.contains_key(candidate.ext.as_bytes())
|
||||
}
|
||||
|
||||
#[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() {
|
||||
return;
|
||||
}
|
||||
if let Some(hits) = self.0.get(&*candidate.ext) {
|
||||
if let Some(hits) = self.0.get(candidate.ext.as_bytes()) {
|
||||
matches.extend(hits);
|
||||
}
|
||||
}
|
||||
@@ -643,27 +672,31 @@ impl ExtensionStrategy {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct PrefixStrategy {
|
||||
matcher: FullAcAutomaton<Vec<u8>>,
|
||||
matcher: AhoCorasick,
|
||||
map: Vec<usize>,
|
||||
longest: usize,
|
||||
}
|
||||
|
||||
impl PrefixStrategy {
|
||||
fn is_match(&self, candidate: &Candidate) -> bool {
|
||||
fn is_match(&self, candidate: &Candidate<'_>) -> bool {
|
||||
let path = candidate.path_prefix(self.longest);
|
||||
for m in self.matcher.find_overlapping(path) {
|
||||
if m.start == 0 {
|
||||
for m in self.matcher.find_overlapping_iter(path) {
|
||||
if m.start() == 0 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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);
|
||||
for m in self.matcher.find_overlapping(path) {
|
||||
if m.start == 0 {
|
||||
matches.push(self.map[m.pati]);
|
||||
for m in self.matcher.find_overlapping_iter(path) {
|
||||
if m.start() == 0 {
|
||||
matches.push(self.map[m.pattern()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -671,27 +704,31 @@ impl PrefixStrategy {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct SuffixStrategy {
|
||||
matcher: FullAcAutomaton<Vec<u8>>,
|
||||
matcher: AhoCorasick,
|
||||
map: Vec<usize>,
|
||||
longest: usize,
|
||||
}
|
||||
|
||||
impl SuffixStrategy {
|
||||
fn is_match(&self, candidate: &Candidate) -> bool {
|
||||
fn is_match(&self, candidate: &Candidate<'_>) -> bool {
|
||||
let path = candidate.path_suffix(self.longest);
|
||||
for m in self.matcher.find_overlapping(path) {
|
||||
if m.end == path.len() {
|
||||
for m in self.matcher.find_overlapping_iter(path) {
|
||||
if m.end() == path.len() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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);
|
||||
for m in self.matcher.find_overlapping(path) {
|
||||
if m.end == path.len() {
|
||||
matches.push(self.map[m.pati]);
|
||||
for m in self.matcher.find_overlapping_iter(path) {
|
||||
if m.end() == path.len() {
|
||||
matches.push(self.map[m.pattern()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -701,15 +738,15 @@ impl SuffixStrategy {
|
||||
struct RequiredExtensionStrategy(HashMap<Vec<u8>, Vec<(usize, Regex)>, Fnv>);
|
||||
|
||||
impl RequiredExtensionStrategy {
|
||||
fn is_match(&self, candidate: &Candidate) -> bool {
|
||||
fn is_match(&self, candidate: &Candidate<'_>) -> bool {
|
||||
if candidate.ext.is_empty() {
|
||||
return false;
|
||||
}
|
||||
match self.0.get(&*candidate.ext) {
|
||||
match self.0.get(candidate.ext.as_bytes()) {
|
||||
None => false,
|
||||
Some(regexes) => {
|
||||
for &(_, ref re) in regexes {
|
||||
if re.is_match(&*candidate.path) {
|
||||
if re.is_match(candidate.path.as_bytes()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -719,13 +756,17 @@ impl RequiredExtensionStrategy {
|
||||
}
|
||||
|
||||
#[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() {
|
||||
return;
|
||||
}
|
||||
if let Some(regexes) = self.0.get(&*candidate.ext) {
|
||||
if let Some(regexes) = self.0.get(candidate.ext.as_bytes()) {
|
||||
for &(global_index, ref re) in regexes {
|
||||
if re.is_match(&*candidate.path) {
|
||||
if re.is_match(candidate.path.as_bytes()) {
|
||||
matches.push(global_index);
|
||||
}
|
||||
}
|
||||
@@ -740,12 +781,16 @@ struct RegexSetStrategy {
|
||||
}
|
||||
|
||||
impl RegexSetStrategy {
|
||||
fn is_match(&self, candidate: &Candidate) -> bool {
|
||||
self.matcher.is_match(&*candidate.path)
|
||||
fn is_match(&self, candidate: &Candidate<'_>) -> bool {
|
||||
self.matcher.is_match(candidate.path.as_bytes())
|
||||
}
|
||||
|
||||
fn matches_into(&self, candidate: &Candidate, matches: &mut Vec<usize>) {
|
||||
for i in self.matcher.matches(&*candidate.path) {
|
||||
fn matches_into(
|
||||
&self,
|
||||
candidate: &Candidate<'_>,
|
||||
matches: &mut Vec<usize>,
|
||||
) {
|
||||
for i in self.matcher.matches(candidate.path.as_bytes()) {
|
||||
matches.push(self.map[i]);
|
||||
}
|
||||
}
|
||||
@@ -760,11 +805,7 @@ struct MultiStrategyBuilder {
|
||||
|
||||
impl MultiStrategyBuilder {
|
||||
fn new() -> MultiStrategyBuilder {
|
||||
MultiStrategyBuilder {
|
||||
literals: vec![],
|
||||
map: vec![],
|
||||
longest: 0,
|
||||
}
|
||||
MultiStrategyBuilder { literals: vec![], map: vec![], longest: 0 }
|
||||
}
|
||||
|
||||
fn add(&mut self, global_index: usize, literal: String) {
|
||||
@@ -776,18 +817,16 @@ impl MultiStrategyBuilder {
|
||||
}
|
||||
|
||||
fn prefix(self) -> PrefixStrategy {
|
||||
let it = self.literals.into_iter().map(|s| s.into_bytes());
|
||||
PrefixStrategy {
|
||||
matcher: AcAutomaton::new(it).into_full(),
|
||||
matcher: AhoCorasick::new_auto_configured(&self.literals),
|
||||
map: self.map,
|
||||
longest: self.longest,
|
||||
}
|
||||
}
|
||||
|
||||
fn suffix(self) -> SuffixStrategy {
|
||||
let it = self.literals.into_iter().map(|s| s.into_bytes());
|
||||
SuffixStrategy {
|
||||
matcher: AcAutomaton::new(it).into_full(),
|
||||
matcher: AhoCorasick::new_auto_configured(&self.literals),
|
||||
map: self.map,
|
||||
longest: self.longest,
|
||||
}
|
||||
@@ -833,8 +872,8 @@ impl RequiredExtensionStrategyBuilder {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::GlobSetBuilder;
|
||||
use glob::Glob;
|
||||
use super::{GlobSet, GlobSetBuilder};
|
||||
use crate::glob::Glob;
|
||||
|
||||
#[test]
|
||||
fn set_works() {
|
||||
@@ -863,4 +902,11 @@ mod tests {
|
||||
assert!(!set.is_match(""));
|
||||
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,41 +1,26 @@
|
||||
use std::borrow::Cow;
|
||||
use std::ffi::OsStr;
|
||||
use std::path::Path;
|
||||
|
||||
use bstr::{ByteSlice, ByteVec};
|
||||
|
||||
/// 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,
|
||||
/// file_name will return None.
|
||||
#[cfg(unix)]
|
||||
pub fn file_name<'a, P: AsRef<Path> + ?Sized>(
|
||||
path: &'a P,
|
||||
) -> Option<&'a OsStr> {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use memchr::memrchr;
|
||||
|
||||
let path = path.as_ref().as_os_str().as_bytes();
|
||||
pub fn file_name<'a>(path: &Cow<'a, [u8]>) -> Option<Cow<'a, [u8]>> {
|
||||
if path.is_empty() {
|
||||
return None;
|
||||
} else if path.len() == 1 && path[0] == b'.' {
|
||||
return None;
|
||||
} else if path.last() == Some(&b'.') {
|
||||
return None;
|
||||
} else if path.len() >= 2 && &path[path.len() - 2..] == &b".."[..] {
|
||||
} else if path.last_byte() == Some(b'.') {
|
||||
return None;
|
||||
}
|
||||
let last_slash = memrchr(b'/', path).map(|i| i + 1).unwrap_or(0);
|
||||
Some(OsStr::from_bytes(&path[last_slash..]))
|
||||
}
|
||||
|
||||
/// 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,
|
||||
/// file_name will return None.
|
||||
#[cfg(not(unix))]
|
||||
pub fn file_name<'a, P: AsRef<Path> + ?Sized>(
|
||||
path: &'a P,
|
||||
) -> Option<&'a OsStr> {
|
||||
path.as_ref().file_name()
|
||||
let last_slash = path.rfind_byte(b'/').map(|i| i + 1).unwrap_or(0);
|
||||
Some(match *path {
|
||||
Cow::Borrowed(path) => Cow::Borrowed(&path[last_slash..]),
|
||||
Cow::Owned(ref path) => {
|
||||
let mut path = path.clone();
|
||||
path.drain_bytes(..last_slash);
|
||||
Cow::Owned(path)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Return a file extension given a path's file name.
|
||||
@@ -54,59 +39,28 @@ pub fn file_name<'a, P: AsRef<Path> + ?Sized>(
|
||||
/// a pattern like `*.rs` is obviously trying to match files with a `rs`
|
||||
/// extension, but it also matches files like `.rs`, which doesn't have an
|
||||
/// extension according to std::path::Path::extension.
|
||||
pub fn file_name_ext(name: &OsStr) -> Option<Cow<[u8]>> {
|
||||
pub fn file_name_ext<'a>(name: &Cow<'a, [u8]>) -> Option<Cow<'a, [u8]>> {
|
||||
if name.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let name = os_str_bytes(name);
|
||||
let last_dot_at = {
|
||||
let result = name
|
||||
.iter().enumerate().rev()
|
||||
.find(|&(_, &b)| b == b'.')
|
||||
.map(|(i, _)| i);
|
||||
match result {
|
||||
None => return None,
|
||||
Some(i) => i,
|
||||
}
|
||||
let last_dot_at = match name.rfind_byte(b'.') {
|
||||
None => return None,
|
||||
Some(i) => i,
|
||||
};
|
||||
Some(match name {
|
||||
Some(match *name {
|
||||
Cow::Borrowed(name) => Cow::Borrowed(&name[last_dot_at..]),
|
||||
Cow::Owned(mut name) => {
|
||||
name.drain(..last_dot_at);
|
||||
Cow::Owned(ref name) => {
|
||||
let mut name = name.clone();
|
||||
name.drain_bytes(..last_dot_at);
|
||||
Cow::Owned(name)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Return raw bytes of a path, transcoded to UTF-8 if necessary.
|
||||
pub fn path_bytes(path: &Path) -> Cow<[u8]> {
|
||||
os_str_bytes(path.as_os_str())
|
||||
}
|
||||
|
||||
/// Return the raw bytes of the given OS string, possibly transcoded to UTF-8.
|
||||
#[cfg(unix)]
|
||||
pub fn os_str_bytes(s: &OsStr) -> Cow<[u8]> {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
Cow::Borrowed(s.as_bytes())
|
||||
}
|
||||
|
||||
/// Return the raw bytes of the given OS string, possibly transcoded to UTF-8.
|
||||
#[cfg(not(unix))]
|
||||
pub fn os_str_bytes(s: &OsStr) -> Cow<[u8]> {
|
||||
// TODO(burntsushi): On Windows, OS strings are WTF-8, which is a superset
|
||||
// of UTF-8, so even if we could get at the raw bytes, they wouldn't
|
||||
// be useful. We *must* convert to UTF-8 before doing path matching.
|
||||
// Unfortunate, but necessary.
|
||||
match s.to_string_lossy() {
|
||||
Cow::Owned(s) => Cow::Owned(s.into_bytes()),
|
||||
Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Normalizes a path to use `/` as a separator everywhere, even on platforms
|
||||
/// that recognize other characters as separators.
|
||||
#[cfg(unix)]
|
||||
pub fn normalize_path(path: Cow<[u8]>) -> Cow<[u8]> {
|
||||
pub fn normalize_path(path: Cow<'_, [u8]>) -> Cow<'_, [u8]> {
|
||||
// UNIX only uses /, so we're good.
|
||||
path
|
||||
}
|
||||
@@ -129,7 +83,8 @@ pub fn normalize_path(mut path: Cow<[u8]>) -> Cow<[u8]> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::borrow::Cow;
|
||||
use std::ffi::OsStr;
|
||||
|
||||
use bstr::{ByteVec, B};
|
||||
|
||||
use super::{file_name_ext, normalize_path};
|
||||
|
||||
@@ -137,8 +92,9 @@ mod tests {
|
||||
($name:ident, $file_name:expr, $ext:expr) => {
|
||||
#[test]
|
||||
fn $name() {
|
||||
let got = file_name_ext(OsStr::new($file_name));
|
||||
assert_eq!($ext.map(|s| Cow::Borrowed(s.as_bytes())), got);
|
||||
let bs = Vec::from($file_name);
|
||||
let got = file_name_ext(&Cow::Owned(bs));
|
||||
assert_eq!($ext.map(|s| Cow::Borrowed(B(s))), got);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -153,7 +109,8 @@ mod tests {
|
||||
($name:ident, $path:expr, $expected:expr) => {
|
||||
#[test]
|
||||
fn $name() {
|
||||
let got = normalize_path(Cow::Owned($path.to_vec()));
|
||||
let bs = Vec::from_slice($path);
|
||||
let got = normalize_path(Cow::Owned(bs));
|
||||
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.6", path = "../cli" }
|
||||
grep-matcher = { version = "0.1.5", path = "../matcher" }
|
||||
grep-pcre2 = { version = "0.1.5", path = "../pcre2", optional = true }
|
||||
grep-printer = { version = "0.1.6", path = "../printer" }
|
||||
grep-regex = { version = "0.1.10", 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.
|
||||
|
||||
[](https://travis-ci.org/BurntSushi/ripgrep)
|
||||
[](https://ci.appveyor.com/project/BurntSushi/ripgrep)
|
||||
[](https://github.com/BurntSushi/ripgrep/actions)
|
||||
[](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
|
||||
@@ -27,12 +26,6 @@ Add this to your `Cargo.toml`:
|
||||
grep = "0.2"
|
||||
```
|
||||
|
||||
and this to your crate root:
|
||||
|
||||
```rust
|
||||
extern crate grep;
|
||||
```
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
extern crate grep;
|
||||
extern crate termcolor;
|
||||
extern crate walkdir;
|
||||
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
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();
|
||||
if args.len() < 2 {
|
||||
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..])
|
||||
}
|
||||
|
||||
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 mut searcher = SearcherBuilder::new()
|
||||
.binary_detection(BinaryDetection::quit(b'\x00'))
|
||||
@@ -40,13 +36,11 @@ fn search(pattern: &str, paths: &[OsString]) -> Result<(), Box<Error>> {
|
||||
.build();
|
||||
let mut printer = StandardBuilder::new()
|
||||
.color_specs(ColorSpecs::default_with_color())
|
||||
.build(cli::stdout(
|
||||
if cli::is_tty_stdout() {
|
||||
ColorChoice::Auto
|
||||
} else {
|
||||
ColorChoice::Never
|
||||
}
|
||||
));
|
||||
.build(cli::stdout(if cli::is_tty_stdout() {
|
||||
ColorChoice::Auto
|
||||
} else {
|
||||
ColorChoice::Never
|
||||
}));
|
||||
|
||||
for path in paths {
|
||||
for result in WalkDir::new(path) {
|
||||
@@ -1,38 +1,38 @@
|
||||
[package]
|
||||
name = "ignore"
|
||||
version = "0.4.4" #:version
|
||||
version = "0.4.19" #:version
|
||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||
description = """
|
||||
A fast library for efficiently matching ignore files such as `.gitignore`
|
||||
against file paths.
|
||||
"""
|
||||
documentation = "https://docs.rs/ignore"
|
||||
homepage = "https://github.com/BurntSushi/ripgrep/tree/master/ignore"
|
||||
repository = "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/crates/ignore"
|
||||
readme = "README.md"
|
||||
keywords = ["glob", "ignore", "gitignore", "pattern", "file"]
|
||||
license = "Unlicense/MIT"
|
||||
license = "Unlicense OR MIT"
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
name = "ignore"
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
crossbeam-channel = "0.2.4"
|
||||
globset = { version = "0.4.2", path = "../globset" }
|
||||
lazy_static = "1.1.0"
|
||||
globset = { version = "0.4.10", path = "../globset" }
|
||||
lazy_static = "1.1"
|
||||
log = "0.4.5"
|
||||
memchr = "2.0.2"
|
||||
regex = "1.0.5"
|
||||
same-file = "1.0.3"
|
||||
thread_local = "0.3.6"
|
||||
walkdir = "2.2.5"
|
||||
memchr = "2.1"
|
||||
regex = "1.1"
|
||||
same-file = "1.0.4"
|
||||
thread_local = "1"
|
||||
walkdir = "2.2.7"
|
||||
|
||||
[target.'cfg(windows)'.dependencies.winapi-util]
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
|
||||
[dev-dependencies]
|
||||
tempdir = "0.3.7"
|
||||
crossbeam-channel = "0.5.0"
|
||||
|
||||
[features]
|
||||
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
|
||||
also provides lower level direct access to gitignore and file type matchers.
|
||||
|
||||
[](https://travis-ci.org/BurntSushi/ripgrep)
|
||||
[](https://ci.appveyor.com/project/BurntSushi/ripgrep)
|
||||
[](https://github.com/BurntSushi/ripgrep/actions)
|
||||
[](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
|
||||
|
||||
@@ -23,12 +22,6 @@ Add this to your `Cargo.toml`:
|
||||
ignore = "0.4"
|
||||
```
|
||||
|
||||
and this to your crate root:
|
||||
|
||||
```rust
|
||||
extern crate ignore;
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
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::io::{self, Write};
|
||||
use std::path::Path;
|
||||
@@ -14,7 +10,7 @@ fn main() {
|
||||
let mut path = env::args().nth(1).unwrap();
|
||||
let mut parallel = false;
|
||||
let mut simple = false;
|
||||
let (tx, rx) = channel::bounded::<DirEntry>(100);
|
||||
let (tx, rx) = crossbeam_channel::bounded::<DirEntry>(100);
|
||||
if path == "parallel" {
|
||||
path = env::args().nth(2).unwrap();
|
||||
parallel = true;
|
||||
@@ -37,19 +33,19 @@ fn main() {
|
||||
Box::new(move |result| {
|
||||
use ignore::WalkState::*;
|
||||
|
||||
tx.send(DirEntry::Y(result.unwrap()));
|
||||
tx.send(DirEntry::Y(result.unwrap())).unwrap();
|
||||
Continue
|
||||
})
|
||||
});
|
||||
} else if simple {
|
||||
let walker = WalkDir::new(path);
|
||||
for result in walker {
|
||||
tx.send(DirEntry::X(result.unwrap()));
|
||||
tx.send(DirEntry::X(result.unwrap())).unwrap();
|
||||
}
|
||||
} else {
|
||||
let walker = WalkBuilder::new(path).build();
|
||||
for result in walker {
|
||||
tx.send(DirEntry::Y(result.unwrap()));
|
||||
tx.send(DirEntry::Y(result.unwrap())).unwrap();
|
||||
}
|
||||
}
|
||||
drop(tx);
|
||||
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,15 +14,18 @@
|
||||
// well.
|
||||
|
||||
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::sync::{Arc, RwLock};
|
||||
|
||||
use gitignore::{self, Gitignore, GitignoreBuilder};
|
||||
use pathutil::{is_hidden, strip_prefix};
|
||||
use overrides::{self, Override};
|
||||
use types::{self, Types};
|
||||
use {Error, Match, PartialErrorBuilder};
|
||||
use crate::gitignore::{self, Gitignore, GitignoreBuilder};
|
||||
use crate::overrides::{self, Override};
|
||||
use crate::pathutil::{is_hidden, strip_prefix};
|
||||
use crate::types::{self, Types};
|
||||
use crate::walk::DirEntry;
|
||||
use crate::{Error, Match, PartialErrorBuilder};
|
||||
|
||||
/// IgnoreMatch represents information about where a match came from when using
|
||||
/// the `Ignore` matcher.
|
||||
@@ -73,6 +76,11 @@ struct IgnoreOptions {
|
||||
git_ignore: bool,
|
||||
/// Whether to read .git/info/exclude files.
|
||||
git_exclude: bool,
|
||||
/// Whether to ignore files case insensitively
|
||||
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.
|
||||
@@ -194,7 +202,12 @@ impl Ignore {
|
||||
errs.maybe_push(err);
|
||||
igtmp.is_absolute_parent = true;
|
||||
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));
|
||||
compiled.insert(parent.as_os_str().to_os_string(), ig.clone());
|
||||
}
|
||||
@@ -219,40 +232,72 @@ impl Ignore {
|
||||
|
||||
/// Like add_child, but takes a full path and returns an IgnoreInner.
|
||||
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 custom_ig_matcher =
|
||||
if self.0.custom_ignore_filenames.is_empty() {
|
||||
Gitignore::empty()
|
||||
} else {
|
||||
let (m, err) =
|
||||
create_gitignore(&dir, &self.0.custom_ignore_filenames);
|
||||
errs.maybe_push(err);
|
||||
m
|
||||
};
|
||||
let ig_matcher =
|
||||
if !self.0.opts.ignore {
|
||||
Gitignore::empty()
|
||||
} else {
|
||||
let (m, err) = create_gitignore(&dir, &[".ignore"]);
|
||||
errs.maybe_push(err);
|
||||
m
|
||||
};
|
||||
let gi_matcher =
|
||||
if !self.0.opts.git_ignore {
|
||||
Gitignore::empty()
|
||||
} else {
|
||||
let (m, err) = create_gitignore(&dir, &[".gitignore"]);
|
||||
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"]);
|
||||
errs.maybe_push(err);
|
||||
m
|
||||
};
|
||||
let custom_ig_matcher = if self.0.custom_ignore_filenames.is_empty() {
|
||||
Gitignore::empty()
|
||||
} else {
|
||||
let (m, err) = create_gitignore(
|
||||
&dir,
|
||||
&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,
|
||||
&git_dir,
|
||||
&["info/exclude"],
|
||||
self.0.opts.ignore_case_insensitive,
|
||||
);
|
||||
errs.maybe_push(err);
|
||||
m
|
||||
}
|
||||
Err(err) => {
|
||||
errs.maybe_push(err);
|
||||
Gitignore::empty()
|
||||
}
|
||||
}
|
||||
};
|
||||
let ig = IgnoreInner {
|
||||
compiled: self.0.compiled.clone(),
|
||||
dir: dir.to_path_buf(),
|
||||
@@ -268,7 +313,7 @@ impl Ignore {
|
||||
git_global_matcher: self.0.git_global_matcher.clone(),
|
||||
git_ignore_matcher: gi_matcher,
|
||||
git_exclude_matcher: gi_exclude_matcher,
|
||||
has_git: dir.join(".git").exists(),
|
||||
has_git,
|
||||
opts: self.0.opts,
|
||||
};
|
||||
(ig, errs.into_error_option())
|
||||
@@ -277,19 +322,35 @@ impl Ignore {
|
||||
/// Returns true if at least one type of ignore rule should be matched.
|
||||
fn has_any_ignore_rules(&self) -> bool {
|
||||
let opts = self.0.opts;
|
||||
let has_custom_ignore_files = !self.0.custom_ignore_filenames.is_empty();
|
||||
let has_custom_ignore_files =
|
||||
!self.0.custom_ignore_filenames.is_empty();
|
||||
let has_explicit_ignores = !self.0.explicit_ignores.is_empty();
|
||||
|
||||
opts.ignore || opts.git_global || opts.git_ignore
|
||||
|| opts.git_exclude || has_custom_ignore_files
|
||||
|| has_explicit_ignores
|
||||
opts.ignore
|
||||
|| opts.git_global
|
||||
|| opts.git_ignore
|
||||
|| opts.git_exclude
|
||||
|| has_custom_ignore_files
|
||||
|| has_explicit_ignores
|
||||
}
|
||||
|
||||
/// Like `matched`, but works with a directory entry instead.
|
||||
pub fn matched_dir_entry<'a>(
|
||||
&'a self,
|
||||
dent: &DirEntry,
|
||||
) -> Match<IgnoreMatch<'a>> {
|
||||
let m = self.matched(dent.path(), dent.is_dir());
|
||||
if m.is_none() && self.0.opts.hidden && is_hidden(dent) {
|
||||
return Match::Ignore(IgnoreMatch::hidden());
|
||||
}
|
||||
m
|
||||
}
|
||||
|
||||
/// Returns a match indicating whether the given file path should be
|
||||
/// ignored or not.
|
||||
///
|
||||
/// The match contains information about its origin.
|
||||
pub fn matched<'a, P: AsRef<Path>>(
|
||||
fn matched<'a, P: AsRef<Path>>(
|
||||
&'a self,
|
||||
path: P,
|
||||
is_dir: bool,
|
||||
@@ -305,9 +366,11 @@ impl Ignore {
|
||||
// return that result immediately. Overrides have the highest
|
||||
// precedence.
|
||||
if !self.0.overrides.is_empty() {
|
||||
let mat =
|
||||
self.0.overrides.matched(path, is_dir)
|
||||
.map(IgnoreMatch::overrides);
|
||||
let mat = self
|
||||
.0
|
||||
.overrides
|
||||
.matched(path, is_dir)
|
||||
.map(IgnoreMatch::overrides);
|
||||
if !mat.is_none() {
|
||||
return mat;
|
||||
}
|
||||
@@ -330,9 +393,6 @@ impl Ignore {
|
||||
whitelisted = mat;
|
||||
}
|
||||
}
|
||||
if whitelisted.is_none() && self.0.opts.hidden && is_hidden(path) {
|
||||
return Match::Ignore(IgnoreMatch::hidden());
|
||||
}
|
||||
whitelisted
|
||||
}
|
||||
|
||||
@@ -343,56 +403,72 @@ impl Ignore {
|
||||
path: &Path,
|
||||
is_dir: bool,
|
||||
) -> Match<IgnoreMatch<'a>> {
|
||||
let (mut m_custom_ignore, 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.parents().any(|ig| ig.0.has_git);
|
||||
let (
|
||||
mut m_custom_ignore,
|
||||
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;
|
||||
for ig in self.parents().take_while(|ig| !ig.0.is_absolute_parent) {
|
||||
if m_custom_ignore.is_none() {
|
||||
m_custom_ignore =
|
||||
ig.0.custom_ignore_matcher.matched(path, is_dir)
|
||||
.map(IgnoreMatch::gitignore);
|
||||
ig.0.custom_ignore_matcher
|
||||
.matched(path, is_dir)
|
||||
.map(IgnoreMatch::gitignore);
|
||||
}
|
||||
if m_ignore.is_none() {
|
||||
m_ignore =
|
||||
ig.0.ignore_matcher.matched(path, is_dir)
|
||||
.map(IgnoreMatch::gitignore);
|
||||
ig.0.ignore_matcher
|
||||
.matched(path, is_dir)
|
||||
.map(IgnoreMatch::gitignore);
|
||||
}
|
||||
if any_git && !saw_git && m_gi.is_none() {
|
||||
m_gi =
|
||||
ig.0.git_ignore_matcher.matched(path, is_dir)
|
||||
.map(IgnoreMatch::gitignore);
|
||||
ig.0.git_ignore_matcher
|
||||
.matched(path, is_dir)
|
||||
.map(IgnoreMatch::gitignore);
|
||||
}
|
||||
if any_git && !saw_git && m_gi_exclude.is_none() {
|
||||
m_gi_exclude =
|
||||
ig.0.git_exclude_matcher.matched(path, is_dir)
|
||||
.map(IgnoreMatch::gitignore);
|
||||
ig.0.git_exclude_matcher
|
||||
.matched(path, is_dir)
|
||||
.map(IgnoreMatch::gitignore);
|
||||
}
|
||||
saw_git = saw_git || ig.0.has_git;
|
||||
}
|
||||
if self.0.opts.parents {
|
||||
if let Some(abs_parent_path) = self.absolute_base() {
|
||||
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() {
|
||||
m_custom_ignore =
|
||||
ig.0.custom_ignore_matcher.matched(&path, is_dir)
|
||||
.map(IgnoreMatch::gitignore);
|
||||
ig.0.custom_ignore_matcher
|
||||
.matched(&path, is_dir)
|
||||
.map(IgnoreMatch::gitignore);
|
||||
}
|
||||
if m_ignore.is_none() {
|
||||
m_ignore =
|
||||
ig.0.ignore_matcher.matched(&path, is_dir)
|
||||
.map(IgnoreMatch::gitignore);
|
||||
ig.0.ignore_matcher
|
||||
.matched(&path, is_dir)
|
||||
.map(IgnoreMatch::gitignore);
|
||||
}
|
||||
if any_git && !saw_git && m_gi.is_none() {
|
||||
m_gi =
|
||||
ig.0.git_ignore_matcher.matched(&path, is_dir)
|
||||
.map(IgnoreMatch::gitignore);
|
||||
ig.0.git_ignore_matcher
|
||||
.matched(&path, is_dir)
|
||||
.map(IgnoreMatch::gitignore);
|
||||
}
|
||||
if any_git && !saw_git && m_gi_exclude.is_none() {
|
||||
m_gi_exclude =
|
||||
ig.0.git_exclude_matcher.matched(&path, is_dir)
|
||||
.map(IgnoreMatch::gitignore);
|
||||
ig.0.git_exclude_matcher
|
||||
.matched(&path, is_dir)
|
||||
.map(IgnoreMatch::gitignore);
|
||||
}
|
||||
saw_git = saw_git || ig.0.has_git;
|
||||
}
|
||||
@@ -404,20 +480,25 @@ impl Ignore {
|
||||
}
|
||||
m_explicit = gi.matched(&path, is_dir).map(IgnoreMatch::gitignore);
|
||||
}
|
||||
let m_global =
|
||||
if any_git {
|
||||
self.0.git_global_matcher
|
||||
.matched(&path, is_dir)
|
||||
.map(IgnoreMatch::gitignore)
|
||||
} else {
|
||||
Match::None
|
||||
};
|
||||
let m_global = if any_git {
|
||||
self.0
|
||||
.git_global_matcher
|
||||
.matched(&path, is_dir)
|
||||
.map(IgnoreMatch::gitignore)
|
||||
} else {
|
||||
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.
|
||||
pub fn parents(&self) -> Parents {
|
||||
pub fn parents(&self) -> Parents<'_> {
|
||||
Parents(Some(self))
|
||||
}
|
||||
|
||||
@@ -483,6 +564,8 @@ impl IgnoreBuilder {
|
||||
git_global: true,
|
||||
git_ignore: true,
|
||||
git_exclude: true,
|
||||
ignore_case_insensitive: false,
|
||||
require_git: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -492,16 +575,19 @@ impl IgnoreBuilder {
|
||||
/// The matcher returned won't match anything until ignore rules from
|
||||
/// directories are added to it.
|
||||
pub fn build(&self) -> Ignore {
|
||||
let git_global_matcher =
|
||||
if !self.opts.git_global {
|
||||
Gitignore::empty()
|
||||
} else {
|
||||
let (gi, err) = Gitignore::global();
|
||||
if let Some(err) = err {
|
||||
debug!("{}", err);
|
||||
}
|
||||
gi
|
||||
};
|
||||
let git_global_matcher = if !self.opts.git_global {
|
||||
Gitignore::empty()
|
||||
} else {
|
||||
let mut builder = GitignoreBuilder::new("");
|
||||
builder
|
||||
.case_insensitive(self.opts.ignore_case_insensitive)
|
||||
.unwrap();
|
||||
let (gi, err) = builder.build_global();
|
||||
if let Some(err) = err {
|
||||
log::debug!("{}", err);
|
||||
}
|
||||
gi
|
||||
};
|
||||
|
||||
Ignore(Arc::new(IgnoreInner {
|
||||
compiled: Arc::new(RwLock::new(HashMap::new())),
|
||||
@@ -512,7 +598,9 @@ impl IgnoreBuilder {
|
||||
is_absolute_parent: true,
|
||||
absolute_base: None,
|
||||
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(),
|
||||
ignore_matcher: Gitignore::empty(),
|
||||
git_global_matcher: Arc::new(git_global_matcher),
|
||||
@@ -557,7 +645,7 @@ impl IgnoreBuilder {
|
||||
/// later names.
|
||||
pub fn add_custom_ignore_filename<S: AsRef<OsStr>>(
|
||||
&mut self,
|
||||
file_name: S
|
||||
file_name: S,
|
||||
) -> &mut IgnoreBuilder {
|
||||
self.custom_ignore_filenames.push(file_name.as_ref().to_os_string());
|
||||
self
|
||||
@@ -627,23 +715,63 @@ impl IgnoreBuilder {
|
||||
self.opts.git_exclude = yes;
|
||||
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
|
||||
///
|
||||
/// This is disabled by default.
|
||||
pub fn ignore_case_insensitive(
|
||||
&mut self,
|
||||
yes: bool,
|
||||
) -> &mut IgnoreBuilder {
|
||||
self.opts.ignore_case_insensitive = yes;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new gitignore matcher for the directory given.
|
||||
///
|
||||
/// Ignore globs are extracted from each of the file names in `dir` in the
|
||||
/// order given (earlier names have lower precedence than later names).
|
||||
/// The matcher is meant to match files below `dir`.
|
||||
/// 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.
|
||||
pub fn create_gitignore<T: AsRef<OsStr>>(
|
||||
dir: &Path,
|
||||
dir_for_ignorefile: &Path,
|
||||
names: &[T],
|
||||
case_insensitive: bool,
|
||||
) -> (Gitignore, Option<Error>) {
|
||||
let mut builder = GitignoreBuilder::new(dir);
|
||||
let mut errs = PartialErrorBuilder::default();
|
||||
builder.case_insensitive(case_insensitive).unwrap();
|
||||
for name in names {
|
||||
let gipath = dir.join(name.as_ref());
|
||||
errs.maybe_push_ignore_io(builder.add(gipath));
|
||||
let gipath = dir_for_ignorefile.join(name.as_ref());
|
||||
// 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() {
|
||||
Ok(gi) => gi,
|
||||
@@ -655,17 +783,70 @@ pub fn create_gitignore<T: AsRef<OsStr>>(
|
||||
(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)]
|
||||
mod tests {
|
||||
use std::fs::{self, File};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
use tempdir::TempDir;
|
||||
|
||||
use dir::IgnoreBuilder;
|
||||
use gitignore::Gitignore;
|
||||
use Error;
|
||||
use crate::dir::IgnoreBuilder;
|
||||
use crate::gitignore::Gitignore;
|
||||
use crate::tests::TempDir;
|
||||
use crate::Error;
|
||||
|
||||
fn wfile<P: AsRef<Path>>(path: P, contents: &str) {
|
||||
let mut file = File::create(path).unwrap();
|
||||
@@ -683,15 +864,19 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn tmpdir() -> TempDir {
|
||||
TempDir::new().unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn explicit_ignore() {
|
||||
let td = TempDir::new("ignore-test-").unwrap();
|
||||
let td = tmpdir();
|
||||
wfile(td.path().join("not-an-ignore"), "foo\n!bar");
|
||||
|
||||
let (gi, err) = Gitignore::new(td.path().join("not-an-ignore"));
|
||||
assert!(err.is_none());
|
||||
let (ig, err) = IgnoreBuilder::new()
|
||||
.add_ignore(gi).build().add_child(td.path());
|
||||
let (ig, err) =
|
||||
IgnoreBuilder::new().add_ignore(gi).build().add_child(td.path());
|
||||
assert!(err.is_none());
|
||||
assert!(ig.matched("foo", false).is_ignore());
|
||||
assert!(ig.matched("bar", false).is_whitelist());
|
||||
@@ -700,7 +885,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn git_exclude() {
|
||||
let td = TempDir::new("ignore-test-").unwrap();
|
||||
let td = tmpdir();
|
||||
mkdirp(td.path().join(".git/info"));
|
||||
wfile(td.path().join(".git/info/exclude"), "foo\n!bar");
|
||||
|
||||
@@ -713,7 +898,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn gitignore() {
|
||||
let td = TempDir::new("ignore-test-").unwrap();
|
||||
let td = tmpdir();
|
||||
mkdirp(td.path().join(".git"));
|
||||
wfile(td.path().join(".gitignore"), "foo\n!bar");
|
||||
|
||||
@@ -726,7 +911,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn gitignore_no_git() {
|
||||
let td = TempDir::new("ignore-test-").unwrap();
|
||||
let td = tmpdir();
|
||||
wfile(td.path().join(".gitignore"), "foo\n!bar");
|
||||
|
||||
let (ig, err) = IgnoreBuilder::new().build().add_child(td.path());
|
||||
@@ -736,9 +921,24 @@ mod tests {
|
||||
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]
|
||||
fn ignore() {
|
||||
let td = TempDir::new("ignore-test-").unwrap();
|
||||
let td = tmpdir();
|
||||
wfile(td.path().join(".ignore"), "foo\n!bar");
|
||||
|
||||
let (ig, err) = IgnoreBuilder::new().build().add_child(td.path());
|
||||
@@ -750,13 +950,14 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn custom_ignore() {
|
||||
let td = TempDir::new("ignore-test-").unwrap();
|
||||
let td = tmpdir();
|
||||
let custom_ignore = ".customignore";
|
||||
wfile(td.path().join(custom_ignore), "foo\n!bar");
|
||||
|
||||
let (ig, err) = IgnoreBuilder::new()
|
||||
.add_custom_ignore_filename(custom_ignore)
|
||||
.build().add_child(td.path());
|
||||
.build()
|
||||
.add_child(td.path());
|
||||
assert!(err.is_none());
|
||||
assert!(ig.matched("foo", false).is_ignore());
|
||||
assert!(ig.matched("bar", false).is_whitelist());
|
||||
@@ -766,14 +967,15 @@ mod tests {
|
||||
// Tests that a custom ignore file will override an .ignore.
|
||||
#[test]
|
||||
fn custom_ignore_over_ignore() {
|
||||
let td = TempDir::new("ignore-test-").unwrap();
|
||||
let td = tmpdir();
|
||||
let custom_ignore = ".customignore";
|
||||
wfile(td.path().join(".ignore"), "foo");
|
||||
wfile(td.path().join(custom_ignore), "!foo");
|
||||
|
||||
let (ig, err) = IgnoreBuilder::new()
|
||||
.add_custom_ignore_filename(custom_ignore)
|
||||
.build().add_child(td.path());
|
||||
.build()
|
||||
.add_child(td.path());
|
||||
assert!(err.is_none());
|
||||
assert!(ig.matched("foo", false).is_whitelist());
|
||||
}
|
||||
@@ -781,7 +983,7 @@ mod tests {
|
||||
// Tests that earlier custom ignore files have lower precedence than later.
|
||||
#[test]
|
||||
fn custom_ignore_precedence() {
|
||||
let td = TempDir::new("ignore-test-").unwrap();
|
||||
let td = tmpdir();
|
||||
let custom_ignore1 = ".customignore1";
|
||||
let custom_ignore2 = ".customignore2";
|
||||
wfile(td.path().join(custom_ignore1), "foo");
|
||||
@@ -790,7 +992,8 @@ mod tests {
|
||||
let (ig, err) = IgnoreBuilder::new()
|
||||
.add_custom_ignore_filename(custom_ignore1)
|
||||
.add_custom_ignore_filename(custom_ignore2)
|
||||
.build().add_child(td.path());
|
||||
.build()
|
||||
.add_child(td.path());
|
||||
assert!(err.is_none());
|
||||
assert!(ig.matched("foo", false).is_whitelist());
|
||||
}
|
||||
@@ -798,7 +1001,7 @@ mod tests {
|
||||
// Tests that an .ignore will override a .gitignore.
|
||||
#[test]
|
||||
fn ignore_over_gitignore() {
|
||||
let td = TempDir::new("ignore-test-").unwrap();
|
||||
let td = tmpdir();
|
||||
wfile(td.path().join(".gitignore"), "foo");
|
||||
wfile(td.path().join(".ignore"), "!foo");
|
||||
|
||||
@@ -810,7 +1013,7 @@ mod tests {
|
||||
// Tests that exclude has lower precedent than both .ignore and .gitignore.
|
||||
#[test]
|
||||
fn exclude_lowest() {
|
||||
let td = TempDir::new("ignore-test-").unwrap();
|
||||
let td = tmpdir();
|
||||
wfile(td.path().join(".gitignore"), "!foo");
|
||||
wfile(td.path().join(".ignore"), "!bar");
|
||||
mkdirp(td.path().join(".git/info"));
|
||||
@@ -825,8 +1028,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn errored() {
|
||||
let td = TempDir::new("ignore-test-").unwrap();
|
||||
wfile(td.path().join(".gitignore"), "f**oo");
|
||||
let td = tmpdir();
|
||||
wfile(td.path().join(".gitignore"), "{foo");
|
||||
|
||||
let (_, err) = IgnoreBuilder::new().build().add_child(td.path());
|
||||
assert!(err.is_some());
|
||||
@@ -834,9 +1037,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn errored_both() {
|
||||
let td = TempDir::new("ignore-test-").unwrap();
|
||||
wfile(td.path().join(".gitignore"), "f**oo");
|
||||
wfile(td.path().join(".ignore"), "fo**o");
|
||||
let td = tmpdir();
|
||||
wfile(td.path().join(".gitignore"), "{foo");
|
||||
wfile(td.path().join(".ignore"), "{bar");
|
||||
|
||||
let (_, err) = IgnoreBuilder::new().build().add_child(td.path());
|
||||
assert_eq!(2, partial(err.expect("an error")).len());
|
||||
@@ -844,9 +1047,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn errored_partial() {
|
||||
let td = TempDir::new("ignore-test-").unwrap();
|
||||
let td = tmpdir();
|
||||
mkdirp(td.path().join(".git"));
|
||||
wfile(td.path().join(".gitignore"), "f**oo\nbar");
|
||||
wfile(td.path().join(".gitignore"), "{foo\nbar");
|
||||
|
||||
let (ig, err) = IgnoreBuilder::new().build().add_child(td.path());
|
||||
assert!(err.is_some());
|
||||
@@ -855,8 +1058,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn errored_partial_and_ignore() {
|
||||
let td = TempDir::new("ignore-test-").unwrap();
|
||||
wfile(td.path().join(".gitignore"), "f**oo\nbar");
|
||||
let td = tmpdir();
|
||||
wfile(td.path().join(".gitignore"), "{foo\nbar");
|
||||
wfile(td.path().join(".ignore"), "!bar");
|
||||
|
||||
let (ig, err) = IgnoreBuilder::new().build().add_child(td.path());
|
||||
@@ -866,7 +1069,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn not_present_empty() {
|
||||
let td = TempDir::new("ignore-test-").unwrap();
|
||||
let td = tmpdir();
|
||||
|
||||
let (_, err) = IgnoreBuilder::new().build().add_child(td.path());
|
||||
assert!(err.is_none());
|
||||
@@ -876,7 +1079,7 @@ mod tests {
|
||||
fn stops_at_git_dir() {
|
||||
// This tests that .gitignore files beyond a .git barrier aren't
|
||||
// matched, but .ignore files are.
|
||||
let td = TempDir::new("ignore-test-").unwrap();
|
||||
let td = tmpdir();
|
||||
mkdirp(td.path().join(".git"));
|
||||
mkdirp(td.path().join("foo/.git"));
|
||||
wfile(td.path().join(".gitignore"), "foo");
|
||||
@@ -897,7 +1100,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn absolute_parent() {
|
||||
let td = TempDir::new("ignore-test-").unwrap();
|
||||
let td = tmpdir();
|
||||
mkdirp(td.path().join(".git"));
|
||||
mkdirp(td.path().join("foo"));
|
||||
wfile(td.path().join(".gitignore"), "bar");
|
||||
@@ -920,7 +1123,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn absolute_parent_anchored() {
|
||||
let td = TempDir::new("ignore-test-").unwrap();
|
||||
let td = tmpdir();
|
||||
mkdirp(td.path().join(".git"));
|
||||
mkdirp(td.path().join("src/llvm"));
|
||||
wfile(td.path().join(".gitignore"), "/llvm/\nfoo");
|
||||
@@ -937,4 +1140,49 @@ mod tests {
|
||||
assert!(ig2.matched("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 thread_local::ThreadLocal;
|
||||
|
||||
use pathutil::{is_file_name, strip_prefix};
|
||||
use {Error, Match, PartialErrorBuilder};
|
||||
use crate::pathutil::{is_file_name, strip_prefix};
|
||||
use crate::{Error, Match, PartialErrorBuilder};
|
||||
|
||||
/// Glob represents a single glob in a gitignore file.
|
||||
///
|
||||
@@ -69,8 +69,7 @@ impl Glob {
|
||||
|
||||
/// Returns true if and only if this glob has a `**/` prefix.
|
||||
fn has_doublestar_prefix(&self) -> bool {
|
||||
self.actual.starts_with("**/")
|
||||
|| (self.actual == "**" && self.is_only_dir)
|
||||
self.actual.starts_with("**/") || self.actual == "**"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,16 +126,7 @@ impl Gitignore {
|
||||
/// `$XDG_CONFIG_HOME/git/ignore` is read. If `$XDG_CONFIG_HOME` is not
|
||||
/// set or is empty, then `$HOME/.config/git/ignore` is used instead.
|
||||
pub fn global() -> (Gitignore, Option<Error>) {
|
||||
match gitconfig_excludes_path() {
|
||||
None => (Gitignore::empty(), None),
|
||||
Some(path) => {
|
||||
if !path.is_file() {
|
||||
(Gitignore::empty(), None)
|
||||
} else {
|
||||
Gitignore::new(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
GitignoreBuilder::new("").build_global()
|
||||
}
|
||||
|
||||
/// Creates a new empty gitignore matcher that never matches anything.
|
||||
@@ -259,7 +249,7 @@ impl Gitignore {
|
||||
return Match::None;
|
||||
}
|
||||
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 candidate = Candidate::new(path);
|
||||
self.set.matches_candidate_into(&candidate, &mut *matches);
|
||||
@@ -342,13 +332,10 @@ impl GitignoreBuilder {
|
||||
pub fn build(&self) -> Result<Gitignore, Error> {
|
||||
let nignore = self.globs.iter().filter(|g| !g.is_whitelist()).count();
|
||||
let nwhite = self.globs.iter().filter(|g| g.is_whitelist()).count();
|
||||
let set =
|
||||
self.builder.build().map_err(|err| {
|
||||
Error::Glob {
|
||||
glob: None,
|
||||
err: err.to_string(),
|
||||
}
|
||||
})?;
|
||||
let set = self
|
||||
.builder
|
||||
.build()
|
||||
.map_err(|err| Error::Glob { glob: None, err: err.to_string() })?;
|
||||
Ok(Gitignore {
|
||||
set: set,
|
||||
root: self.root.clone(),
|
||||
@@ -359,6 +346,36 @@ impl GitignoreBuilder {
|
||||
})
|
||||
}
|
||||
|
||||
/// Build a global gitignore matcher using the configuration in this
|
||||
/// builder.
|
||||
///
|
||||
/// This consumes ownership of the builder unlike `build` because it
|
||||
/// must mutate the builder to add the global gitignore globs.
|
||||
///
|
||||
/// Note that this ignores the path given to this builder's constructor
|
||||
/// and instead derives the path automatically from git's global
|
||||
/// configuration.
|
||||
pub fn build_global(mut self) -> (Gitignore, Option<Error>) {
|
||||
match gitconfig_excludes_path() {
|
||||
None => (Gitignore::empty(), None),
|
||||
Some(path) => {
|
||||
if !path.is_file() {
|
||||
(Gitignore::empty(), None)
|
||||
} else {
|
||||
let mut errs = PartialErrorBuilder::default();
|
||||
errs.maybe_push_ignore_io(self.add(path));
|
||||
match self.build() {
|
||||
Ok(gi) => (gi, errs.into_error_option()),
|
||||
Err(err) => {
|
||||
errs.push(err);
|
||||
(Gitignore::empty(), errs.into_error_option())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Add each glob from the file path given.
|
||||
///
|
||||
/// The file given should be formatted as a `gitignore` file.
|
||||
@@ -419,6 +436,8 @@ impl GitignoreBuilder {
|
||||
from: Option<PathBuf>,
|
||||
mut line: &str,
|
||||
) -> Result<&mut GitignoreBuilder, Error> {
|
||||
#![allow(deprecated)]
|
||||
|
||||
if line.starts_with("#") {
|
||||
return Ok(self);
|
||||
}
|
||||
@@ -435,7 +454,6 @@ impl GitignoreBuilder {
|
||||
is_whitelist: false,
|
||||
is_only_dir: false,
|
||||
};
|
||||
let mut literal_separator = false;
|
||||
let mut is_absolute = false;
|
||||
if line.starts_with("\\!") || line.starts_with("\\#") {
|
||||
line = &line[1..];
|
||||
@@ -450,29 +468,26 @@ impl GitignoreBuilder {
|
||||
// then the glob can only match the beginning of a path
|
||||
// (relative to the location of gitignore). We achieve this by
|
||||
// simply banning wildcards from matching /.
|
||||
literal_separator = true;
|
||||
line = &line[1..];
|
||||
is_absolute = true;
|
||||
}
|
||||
}
|
||||
// If it ends with a slash, then this should only match directories,
|
||||
// but the slash should otherwise not be used while globbing.
|
||||
if let Some((i, c)) = line.char_indices().rev().nth(0) {
|
||||
if c == '/' {
|
||||
glob.is_only_dir = true;
|
||||
line = &line[..i];
|
||||
if line.as_bytes().last() == Some(&b'/') {
|
||||
glob.is_only_dir = true;
|
||||
line = &line[..line.len() - 1];
|
||||
// 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];
|
||||
}
|
||||
}
|
||||
// If there is a literal slash, then we note that so that globbing
|
||||
// doesn't let wildcards match slashes.
|
||||
glob.actual = line.to_string();
|
||||
if is_absolute || line.chars().any(|c| c == '/') {
|
||||
literal_separator = true;
|
||||
}
|
||||
// If there was a slash, then this is a glob that must match the entire
|
||||
// path name. Otherwise, we should let it match anywhere, so use a **/
|
||||
// prefix.
|
||||
if !literal_separator {
|
||||
// If there is a literal slash, then this is a glob that must match the
|
||||
// entire path name. Otherwise, we should let it match anywhere, so use
|
||||
// a **/ prefix.
|
||||
if !is_absolute && !line.chars().any(|c| c == '/') {
|
||||
// ... but only if we don't already have a **/ prefix.
|
||||
if !glob.has_doublestar_prefix() {
|
||||
glob.actual = format!("**/{}", glob.actual);
|
||||
@@ -484,18 +499,15 @@ impl GitignoreBuilder {
|
||||
if glob.actual.ends_with("/**") {
|
||||
glob.actual = format!("{}/*", glob.actual);
|
||||
}
|
||||
let parsed =
|
||||
GlobBuilder::new(&glob.actual)
|
||||
.literal_separator(literal_separator)
|
||||
.case_insensitive(self.case_insensitive)
|
||||
.backslash_escape(true)
|
||||
.build()
|
||||
.map_err(|err| {
|
||||
Error::Glob {
|
||||
glob: Some(glob.original.clone()),
|
||||
err: err.kind().to_string(),
|
||||
}
|
||||
})?;
|
||||
let parsed = GlobBuilder::new(&glob.actual)
|
||||
.literal_separator(true)
|
||||
.case_insensitive(self.case_insensitive)
|
||||
.backslash_escape(true)
|
||||
.build()
|
||||
.map_err(|err| Error::Glob {
|
||||
glob: Some(glob.original.clone()),
|
||||
err: err.kind().to_string(),
|
||||
})?;
|
||||
self.builder.add(parsed);
|
||||
self.globs.push(glob);
|
||||
Ok(self)
|
||||
@@ -503,12 +515,16 @@ impl GitignoreBuilder {
|
||||
|
||||
/// Toggle whether the globs should be matched case insensitively or not.
|
||||
///
|
||||
/// When this option is changed, only globs added after the change will be affected.
|
||||
/// When this option is changed, only globs added after the change will be
|
||||
/// affected.
|
||||
///
|
||||
/// This is disabled by default.
|
||||
pub fn case_insensitive(
|
||||
&mut self, yes: bool
|
||||
&mut self,
|
||||
yes: bool,
|
||||
) -> Result<&mut GitignoreBuilder, Error> {
|
||||
// TODO: This should not return a `Result`. Fix this in the next semver
|
||||
// release.
|
||||
self.case_insensitive = yes;
|
||||
Ok(self)
|
||||
}
|
||||
@@ -518,7 +534,7 @@ impl GitignoreBuilder {
|
||||
///
|
||||
/// Note that the file path returned may not exist.
|
||||
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
|
||||
// precedent. So if $HOME/.gitconfig defines a `core.excludesFile`, then
|
||||
// we're done.
|
||||
@@ -549,7 +565,7 @@ fn gitconfig_home_contents() -> Option<Vec<u8>> {
|
||||
}
|
||||
|
||||
/// 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>> {
|
||||
let path = env::var_os("XDG_CONFIG_HOME")
|
||||
.and_then(|x| if x.is_empty() { None } else { Some(PathBuf::from(x)) })
|
||||
@@ -579,10 +595,9 @@ fn parse_excludes_file(data: &[u8]) -> Option<PathBuf> {
|
||||
// N.B. This is the lazy approach, and isn't technically correct, but
|
||||
// probably works in more circumstances. I guess we would ideally have
|
||||
// a full INI parser. Yuck.
|
||||
lazy_static! {
|
||||
static ref RE: Regex = Regex::new(
|
||||
r"(?im)^\s*excludesfile\s*=\s*(.+)\s*$"
|
||||
).unwrap();
|
||||
lazy_static::lazy_static! {
|
||||
static ref RE: Regex =
|
||||
Regex::new(r"(?im)^\s*excludesfile\s*=\s*(.+)\s*$").unwrap();
|
||||
};
|
||||
let caps = match RE.captures(data) {
|
||||
None => return None,
|
||||
@@ -611,8 +626,8 @@ fn home_dir() -> Option<PathBuf> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::path::Path;
|
||||
use super::{Gitignore, GitignoreBuilder};
|
||||
use std::path::Path;
|
||||
|
||||
fn gi_from_str<P: AsRef<Path>>(root: P, s: &str) -> Gitignore {
|
||||
let mut builder = GitignoreBuilder::new(root);
|
||||
@@ -689,6 +704,9 @@ mod tests {
|
||||
ignored!(ig39, ROOT, "\\?", "?");
|
||||
ignored!(ig40, ROOT, "\\*", "*");
|
||||
ignored!(ig41, ROOT, "\\a", "a");
|
||||
ignored!(ig42, ROOT, "s*.rs", "sfoo.rs");
|
||||
ignored!(ig43, ROOT, "**", "foo.rs");
|
||||
ignored!(ig44, ROOT, "**/**/*", "a/foo.rs");
|
||||
|
||||
not_ignored!(ignot1, ROOT, "amonths", "months");
|
||||
not_ignored!(ignot2, ROOT, "monthsa", "months");
|
||||
@@ -704,12 +722,16 @@ mod tests {
|
||||
not_ignored!(ignot12, ROOT, "\n\n\n", "foo");
|
||||
not_ignored!(ignot13, ROOT, "foo/**", "foo", true);
|
||||
not_ignored!(
|
||||
ignot14, "./third_party/protobuf", "m4/ltoptions.m4",
|
||||
"./third_party/protobuf/csharp/src/packages/repositories.config");
|
||||
ignot14,
|
||||
"./third_party/protobuf",
|
||||
"m4/ltoptions.m4",
|
||||
"./third_party/protobuf/csharp/src/packages/repositories.config"
|
||||
);
|
||||
not_ignored!(ignot15, ROOT, "!/bar", "foo/bar");
|
||||
not_ignored!(ignot16, ROOT, "*\n!**/", "foo", true);
|
||||
not_ignored!(ignot17, ROOT, "src/*.rs", "src/grep/src/main.rs");
|
||||
not_ignored!(ignot18, ROOT, "path1/*", "path2/path1/foo");
|
||||
not_ignored!(ignot19, ROOT, "s*.rs", "src/foo.rs");
|
||||
|
||||
fn bytes(s: &str) -> Vec<u8> {
|
||||
s.to_string().into_bytes()
|
||||
@@ -748,9 +770,12 @@ mod tests {
|
||||
#[test]
|
||||
fn case_insensitive() {
|
||||
let gi = GitignoreBuilder::new(ROOT)
|
||||
.case_insensitive(true).unwrap()
|
||||
.add_str(None, "*.html").unwrap()
|
||||
.build().unwrap();
|
||||
.case_insensitive(true)
|
||||
.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.htm", false).is_ignore());
|
||||
@@ -46,33 +46,21 @@ See the documentation for `WalkBuilder` for many other options.
|
||||
|
||||
#![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 tempdir;
|
||||
extern crate thread_local;
|
||||
extern crate walkdir;
|
||||
#[cfg(windows)]
|
||||
extern crate winapi_util;
|
||||
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
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;
|
||||
pub mod gitignore;
|
||||
mod pathutil;
|
||||
pub mod overrides;
|
||||
mod pathutil;
|
||||
pub mod types;
|
||||
mod walk;
|
||||
|
||||
@@ -145,20 +133,14 @@ impl Clone for Error {
|
||||
Error::WithDepth { depth, ref err } => {
|
||||
Error::WithDepth { depth: depth, err: err.clone() }
|
||||
}
|
||||
Error::Loop { ref ancestor, ref child } => {
|
||||
Error::Loop {
|
||||
ancestor: ancestor.clone(),
|
||||
child: child.clone()
|
||||
}
|
||||
}
|
||||
Error::Io(ref err) => {
|
||||
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::Loop { ref ancestor, ref child } => Error::Loop {
|
||||
ancestor: ancestor.clone(),
|
||||
child: child.clone(),
|
||||
},
|
||||
Error::Io(ref err) => 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 { 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
|
||||
/// this error was generated from a recursive directory iterator).
|
||||
pub fn depth(&self) -> Option<usize> {
|
||||
@@ -221,19 +268,14 @@ impl Error {
|
||||
|
||||
/// Turn an error into a tagged error with the given depth.
|
||||
fn with_depth(self, depth: usize) -> Error {
|
||||
Error::WithDepth {
|
||||
depth: depth,
|
||||
err: Box::new(self),
|
||||
}
|
||||
Error::WithDepth { depth: depth, err: Box::new(self) }
|
||||
}
|
||||
|
||||
/// 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.
|
||||
fn tagged<P: AsRef<Path>>(self, path: P, lineno: u64) -> Error {
|
||||
let errline = Error::WithLineNumber {
|
||||
line: lineno,
|
||||
err: Box::new(self),
|
||||
};
|
||||
let errline =
|
||||
Error::WithLineNumber { line: lineno, err: Box::new(self) };
|
||||
if path.as_ref().as_os_str().is_empty() {
|
||||
return errline;
|
||||
}
|
||||
@@ -255,16 +297,14 @@ impl Error {
|
||||
let path = err.path().map(|p| p.to_path_buf());
|
||||
let mut ig_err = Error::Io(io::Error::from(err));
|
||||
if let Some(path) = path {
|
||||
ig_err = Error::WithPath {
|
||||
path: path,
|
||||
err: Box::new(ig_err),
|
||||
};
|
||||
ig_err = Error::WithPath { path: path, err: Box::new(ig_err) };
|
||||
}
|
||||
ig_err
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for Error {
|
||||
#[allow(deprecated)]
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
Error::Partial(_) => "partial error",
|
||||
@@ -281,7 +321,7 @@ impl error::Error 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 {
|
||||
Error::Partial(ref errs) => {
|
||||
let msgs: Vec<String> =
|
||||
@@ -295,11 +335,13 @@ impl fmt::Display for Error {
|
||||
write!(f, "{}: {}", path.display(), err)
|
||||
}
|
||||
Error::WithDepth { ref err, .. } => err.fmt(f),
|
||||
Error::Loop { ref ancestor, ref child } => {
|
||||
write!(f, "File system loop found: \
|
||||
Error::Loop { ref ancestor, ref child } => write!(
|
||||
f,
|
||||
"File system loop found: \
|
||||
{} points to an ancestor {}",
|
||||
child.display(), ancestor.display())
|
||||
}
|
||||
child.display(),
|
||||
ancestor.display()
|
||||
),
|
||||
Error::Io(ref err) => err.fmt(f),
|
||||
Error::Glob { glob: None, ref err } => write!(f, "{}", err),
|
||||
Error::Glob { glob: Some(ref glob), ref err } => {
|
||||
@@ -308,10 +350,11 @@ impl fmt::Display for Error {
|
||||
Error::UnrecognizedFileType(ref ty) => {
|
||||
write!(f, "unrecognized file type: {}", ty)
|
||||
}
|
||||
Error::InvalidDefinition => {
|
||||
write!(f, "invalid definition (format is type:glob, e.g., \
|
||||
html:*.html)")
|
||||
}
|
||||
Error::InvalidDefinition => write!(
|
||||
f,
|
||||
"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 gitignore::{self, Gitignore, GitignoreBuilder};
|
||||
use {Error, Match};
|
||||
use crate::gitignore::{self, Gitignore, GitignoreBuilder};
|
||||
use crate::{Error, Match};
|
||||
|
||||
/// Glob represents a single glob in an override matcher.
|
||||
///
|
||||
@@ -115,9 +115,7 @@ impl OverrideBuilder {
|
||||
///
|
||||
/// Matching is done relative to the directory path provided.
|
||||
pub fn new<P: AsRef<Path>>(path: P) -> OverrideBuilder {
|
||||
OverrideBuilder {
|
||||
builder: GitignoreBuilder::new(path),
|
||||
}
|
||||
OverrideBuilder { builder: GitignoreBuilder::new(path) }
|
||||
}
|
||||
|
||||
/// Builds a new override matcher from the globs added so far.
|
||||
@@ -139,13 +137,16 @@ impl OverrideBuilder {
|
||||
}
|
||||
|
||||
/// Toggle whether the globs should be matched case insensitively or not.
|
||||
///
|
||||
///
|
||||
/// When this option is changed, only globs added after the change will be affected.
|
||||
///
|
||||
/// This is disabled by default.
|
||||
pub fn case_insensitive(
|
||||
&mut self, yes: bool
|
||||
&mut self,
|
||||
yes: bool,
|
||||
) -> Result<&mut OverrideBuilder, Error> {
|
||||
// TODO: This should not return a `Result`. Fix this in the next semver
|
||||
// release.
|
||||
self.builder.case_insensitive(yes)?;
|
||||
Ok(self)
|
||||
}
|
||||
@@ -237,9 +238,12 @@ mod tests {
|
||||
#[test]
|
||||
fn case_insensitive() {
|
||||
let ov = OverrideBuilder::new(ROOT)
|
||||
.case_insensitive(true).unwrap()
|
||||
.add("*.html").unwrap()
|
||||
.build().unwrap();
|
||||
.case_insensitive(true)
|
||||
.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.htm", false).is_ignore());
|
||||
@@ -248,9 +252,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn default_case_sensitive() {
|
||||
let ov = OverrideBuilder::new(ROOT)
|
||||
.add("*.html").unwrap()
|
||||
.build().unwrap();
|
||||
let ov =
|
||||
OverrideBuilder::new(ROOT).add("*.html").unwrap().build().unwrap();
|
||||
assert!(ov.matched("foo.html", false).is_whitelist());
|
||||
assert!(ov.matched("foo.HTML", false).is_ignore());
|
||||
assert!(ov.matched("foo.htm", false).is_ignore());
|
||||
@@ -1,22 +1,56 @@
|
||||
use std::ffi::OsStr;
|
||||
use std::path::Path;
|
||||
|
||||
/// Returns true if and only if this file path is considered to be hidden.
|
||||
use crate::walk::DirEntry;
|
||||
|
||||
/// Returns true if and only if this entry is considered to be hidden.
|
||||
///
|
||||
/// This only returns true if the base name of the path starts with a `.`.
|
||||
///
|
||||
/// On Unix, this implements a more optimized check.
|
||||
#[cfg(unix)]
|
||||
pub fn is_hidden<P: AsRef<Path>>(path: P) -> bool {
|
||||
pub fn is_hidden(dent: &DirEntry) -> bool {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
if let Some(name) = file_name(path.as_ref()) {
|
||||
if let Some(name) = file_name(dent.path()) {
|
||||
name.as_bytes().get(0) == Some(&b'.')
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if and only if this file path is considered to be hidden.
|
||||
#[cfg(not(unix))]
|
||||
pub fn is_hidden<P: AsRef<Path>>(path: P) -> bool {
|
||||
if let Some(name) = file_name(path.as_ref()) {
|
||||
/// Returns true if and only if this entry is considered to be hidden.
|
||||
///
|
||||
/// On Windows, this returns true if one of the following is true:
|
||||
///
|
||||
/// * The base name of the path starts with a `.`.
|
||||
/// * The file attributes have the `HIDDEN` property set.
|
||||
#[cfg(windows)]
|
||||
pub fn is_hidden(dent: &DirEntry) -> bool {
|
||||
use std::os::windows::fs::MetadataExt;
|
||||
use winapi_util::file;
|
||||
|
||||
// This looks like we're doing an extra stat call, but on Windows, the
|
||||
// directory traverser reuses the metadata retrieved from each directory
|
||||
// entry and stores it on the DirEntry itself. So this is "free."
|
||||
if let Ok(md) = dent.metadata() {
|
||||
if file::is_hidden(md.file_attributes() as u64) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if let Some(name) = file_name(dent.path()) {
|
||||
name.to_str().map(|s| s.starts_with(".")).unwrap_or(false)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if and only if this entry is considered to be hidden.
|
||||
///
|
||||
/// This only returns true if the base name of the path starts with a `.`.
|
||||
#[cfg(not(any(unix, windows)))]
|
||||
pub fn is_hidden(dent: &DirEntry) -> bool {
|
||||
if let Some(name) = file_name(dent.path()) {
|
||||
name.to_str().map(|s| s.starts_with(".")).unwrap_or(false)
|
||||
} else {
|
||||
false
|
||||
@@ -57,8 +91,8 @@ pub fn strip_prefix<'a, P: AsRef<Path> + ?Sized>(
|
||||
/// the empty string.
|
||||
#[cfg(unix)]
|
||||
pub fn is_file_name<P: AsRef<Path>>(path: P) -> bool {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use memchr::memchr;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
let path = path.as_ref().as_os_str().as_bytes();
|
||||
memchr(b'/', path).is_none()
|
||||
@@ -79,8 +113,8 @@ pub fn is_file_name<P: AsRef<Path>>(path: P) -> bool {
|
||||
pub fn file_name<'a, P: AsRef<Path> + ?Sized>(
|
||||
path: &'a P,
|
||||
) -> Option<&'a OsStr> {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use memchr::memrchr;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
let path = path.as_ref().as_os_str().as_bytes();
|
||||
if path.is_empty() {
|
||||
@@ -93,219 +93,9 @@ use globset::{GlobBuilder, GlobSet, GlobSetBuilder};
|
||||
use regex::Regex;
|
||||
use thread_local::ThreadLocal;
|
||||
|
||||
use pathutil::file_name;
|
||||
use {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"]),
|
||||
("avro", &["*.avdl", "*.avpr", "*.avsc"]),
|
||||
("awk", &["*.awk"]),
|
||||
("bazel", &["*.bzl", "WORKSPACE", "BUILD"]),
|
||||
("bitbake", &["*.bb", "*.bbappend", "*.bbclass", "*.conf", "*.inc"]),
|
||||
("bzip2", &["*.bz2"]),
|
||||
("c", &["*.c", "*.h", "*.H", "*.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", &[
|
||||
"*.C", "*.cc", "*.cpp", "*.cxx",
|
||||
"*.h", "*.H", "*.hh", "*.hpp", "*.hxx", "*.inl",
|
||||
]),
|
||||
("crystal", &["Projectfile", "*.cr"]),
|
||||
("cs", &["*.cs"]),
|
||||
("csharp", &["*.cs"]),
|
||||
("cshtml", &["*.cshtml"]),
|
||||
("css", &["*.css", "*.scss"]),
|
||||
("csv", &["*.csv"]),
|
||||
("cython", &["*.pyx"]),
|
||||
("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"]),
|
||||
("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"]),
|
||||
("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"]),
|
||||
("log", &["*.log"]),
|
||||
("lua", &["*.lua"]),
|
||||
("lzma", &["*.lzma"]),
|
||||
("lz4", &["*.lz4"]),
|
||||
("m4", &["*.ac", "*.m4"]),
|
||||
("make", &[
|
||||
"gnumakefile", "Gnumakefile", "GNUmakefile",
|
||||
"makefile", "Makefile",
|
||||
"*.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"]),
|
||||
("protobuf", &["*.proto"]),
|
||||
("ps", &["*.cdxml", "*.ps1", "*.ps1xml", "*.psd1", "*.psm1"]),
|
||||
("puppet", &["*.erb", "*.pp", "*.rb"]),
|
||||
("purs", &["*.purs"]),
|
||||
("py", &["*.py"]),
|
||||
("qmake", &["*.pro", "*.pri", "*.prf"]),
|
||||
("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"]),
|
||||
("textile", &["*.textile"]),
|
||||
("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"]),
|
||||
("xz", &["*.xz"]),
|
||||
("yacc", &["*.y"]),
|
||||
("yaml", &["*.yaml", "*.yml"]),
|
||||
("zsh", &[
|
||||
".zshenv", "zshenv",
|
||||
".zlogin", "zlogin",
|
||||
".zlogout", "zlogout",
|
||||
".zprofile", "zprofile",
|
||||
".zshrc", "zshrc",
|
||||
"*.zsh",
|
||||
]),
|
||||
];
|
||||
use crate::default_types::DEFAULT_TYPES;
|
||||
use crate::pathutil::file_name;
|
||||
use crate::{Error, Match};
|
||||
|
||||
/// Glob represents a single glob in a set of file type definitions.
|
||||
///
|
||||
@@ -332,17 +122,23 @@ enum GlobInner<'a> {
|
||||
Matched {
|
||||
/// The file type definition which provided the glob.
|
||||
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> {
|
||||
fn unmatched() -> Glob<'a> {
|
||||
Glob(GlobInner::UnmatchedIgnore)
|
||||
}
|
||||
|
||||
/// Return the file type definition that matched, if one exists. A file type
|
||||
/// definition always exists when a specific definition matches a file
|
||||
/// path.
|
||||
pub fn file_type_def(&self) -> Option<&FileTypeDef> {
|
||||
match self {
|
||||
Glob(GlobInner::UnmatchedIgnore) => None,
|
||||
Glob(GlobInner::Matched { def, .. }) => Some(def),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A single file type definition.
|
||||
@@ -487,17 +283,13 @@ impl Types {
|
||||
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);
|
||||
// The highest precedent match is the last one.
|
||||
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 glob = Glob(GlobInner::Matched {
|
||||
def: sel.inner(),
|
||||
which: iglob,
|
||||
negated: sel.is_negated(),
|
||||
});
|
||||
let glob = Glob(GlobInner::Matched { def: sel.inner() });
|
||||
return if sel.is_negated() {
|
||||
Match::Ignore(glob)
|
||||
} else {
|
||||
@@ -526,10 +318,7 @@ impl TypesBuilder {
|
||||
/// of default type definitions can be added with `add_defaults`, and
|
||||
/// additional type definitions can be added with `select` and `negate`.
|
||||
pub fn new() -> TypesBuilder {
|
||||
TypesBuilder {
|
||||
types: HashMap::new(),
|
||||
selections: vec![],
|
||||
}
|
||||
TypesBuilder { types: HashMap::new(), selections: vec![] }
|
||||
}
|
||||
|
||||
/// Build the current set of file type definitions *and* selections into
|
||||
@@ -554,19 +343,18 @@ impl TypesBuilder {
|
||||
GlobBuilder::new(glob)
|
||||
.literal_separator(true)
|
||||
.build()
|
||||
.map_err(|err| {
|
||||
Error::Glob {
|
||||
glob: Some(glob.to_string()),
|
||||
err: err.kind().to_string(),
|
||||
}
|
||||
})?);
|
||||
.map_err(|err| Error::Glob {
|
||||
glob: Some(glob.to_string()),
|
||||
err: err.kind().to_string(),
|
||||
})?,
|
||||
);
|
||||
glob_to_selection.push((isel, iglob));
|
||||
}
|
||||
selections.push(selection.clone().map(move |_| def));
|
||||
}
|
||||
let set = build_set.build().map_err(|err| {
|
||||
Error::Glob { glob: None, err: err.to_string() }
|
||||
})?;
|
||||
let set = build_set
|
||||
.build()
|
||||
.map_err(|err| Error::Glob { glob: None, err: err.to_string() })?;
|
||||
Ok(Types {
|
||||
defs: defs,
|
||||
selections: selections,
|
||||
@@ -631,16 +419,21 @@ impl TypesBuilder {
|
||||
/// If `name` is `all` or otherwise contains any character that is not a
|
||||
/// Unicode letter or number, then an error is returned.
|
||||
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();
|
||||
};
|
||||
if name == "all" || !RE.is_match(name) {
|
||||
return Err(Error::InvalidDefinition);
|
||||
}
|
||||
let (key, glob) = (name.to_string(), glob.to_string());
|
||||
self.types.entry(key).or_insert_with(|| {
|
||||
FileTypeDef { name: name.to_string(), globs: vec![] }
|
||||
}).globs.push(glob);
|
||||
self.types
|
||||
.entry(key)
|
||||
.or_insert_with(|| FileTypeDef {
|
||||
name: name.to_string(),
|
||||
globs: vec![],
|
||||
})
|
||||
.globs
|
||||
.push(glob);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -667,7 +460,10 @@ impl TypesBuilder {
|
||||
3 => {
|
||||
let name = parts[0];
|
||||
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);
|
||||
}
|
||||
let types = types_string.split(',');
|
||||
@@ -677,14 +473,15 @@ impl TypesBuilder {
|
||||
return Err(Error::InvalidDefinition);
|
||||
}
|
||||
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 {
|
||||
self.add(name, &glob)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(Error::InvalidDefinition)
|
||||
_ => Err(Error::InvalidDefinition),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -741,7 +538,7 @@ mod tests {
|
||||
"rust:*.rs",
|
||||
"js:*.js",
|
||||
"foo:*.{rs,foo}",
|
||||
"combo:include:html,rust"
|
||||
"combo:include:html,rust",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -775,7 +572,7 @@ mod tests {
|
||||
"combo:include:html,python",
|
||||
// Bad format
|
||||
"combo:foobar:html,rust",
|
||||
""
|
||||
"",
|
||||
];
|
||||
for def in bad_defs {
|
||||
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