• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Used to simulate a fairly large number of options/flags and parsing with thousands of positional
2 // args
3 //
4 // CLI used is adapted from ripgrep 48a8a3a691220f9e5b2b08f4051abe8655ea7e8a
5 
6 use clap::{value_parser, Arg, ArgAction, Command};
7 use criterion::{criterion_group, criterion_main, Criterion};
8 use std::collections::HashMap;
9 
10 use lazy_static::lazy_static;
11 
build_rg_with_short_help(c: &mut Criterion)12 pub fn build_rg_with_short_help(c: &mut Criterion) {
13     c.bench_function("build_rg_with_short_help", |b| b.iter(app_short));
14 }
15 
build_rg_with_long_help(c: &mut Criterion)16 pub fn build_rg_with_long_help(c: &mut Criterion) {
17     c.bench_function("build_rg_with_long_help", |b| b.iter(app_long));
18 }
19 
write_rg_short_help(c: &mut Criterion)20 pub fn write_rg_short_help(c: &mut Criterion) {
21     let mut cmd = app_short();
22     c.bench_function("write_rg_short_help", |b| b.iter(|| build_help(&mut cmd)));
23 }
24 
write_rg_long_help(c: &mut Criterion)25 pub fn write_rg_long_help(c: &mut Criterion) {
26     let mut cmd = app_long();
27     c.bench_function("write_rg_long_help", |b| b.iter(|| build_help(&mut cmd)));
28 }
29 
parse_rg(c: &mut Criterion)30 pub fn parse_rg(c: &mut Criterion) {
31     c.bench_function("parse_rg", |b| {
32         b.iter(|| app_short().get_matches_from(vec!["rg", "pat"]))
33     });
34 }
35 
parse_rg_with_complex(c: &mut Criterion)36 pub fn parse_rg_with_complex(c: &mut Criterion) {
37     c.bench_function("parse_rg_with_complex", |b| {
38         b.iter(|| {
39             app_short().get_matches_from(vec![
40                 "rg",
41                 "pat",
42                 "-cFlN",
43                 "-pqr=some",
44                 "--null",
45                 "--no-filename",
46                 "--no-messages",
47                 "-SH",
48                 "-C5",
49                 "--follow",
50                 "-e some",
51             ])
52         })
53     });
54 }
55 
parse_rg_with_lots(c: &mut Criterion)56 pub fn parse_rg_with_lots(c: &mut Criterion) {
57     c.bench_function("parse_rg_with_lots", |b| {
58         b.iter(|| {
59             app_short().get_matches_from(vec![
60                 "rg", "pat", "some", "some", "some", "some", "some", "some", "some", "some",
61                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
62                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
63                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
64                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
65                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
66                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
67                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
68                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
69                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
70                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
71                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
72                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
73                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
74                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
75                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
76                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
77                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
78                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
79                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
80                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
81                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
82                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
83                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
84                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
85                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
86                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
87                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
88                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
89                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
90                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
91                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
92                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
93                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
94                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
95                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
96                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
97                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
98                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
99                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
100                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
101                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
102                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
103                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
104                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
105                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
106                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
107                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
108                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
109                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
110                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
111                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
112                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
113                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
114                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
115                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
116                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
117                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
118                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
119                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
120                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
121                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
122                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
123                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
124                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
125                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
126                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
127                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
128                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
129                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
130                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
131                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
132                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
133                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
134                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
135                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
136                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
137                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
138                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
139                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
140                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
141                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
142                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
143                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
144                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
145                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
146                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
147                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
148                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
149                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
150                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
151                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
152                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
153                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
154                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
155                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
156                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
157                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
158                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
159                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
160                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
161                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
162                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
163                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
164                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
165                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
166                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
167                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
168                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
169                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
170                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
171                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
172                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
173                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
174                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
175                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
176                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
177                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
178                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
179                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
180                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
181                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
182                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
183                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
184                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
185                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
186                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
187                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
188                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
189                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
190                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
191                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
192                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
193                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
194                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
195                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
196                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
197                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
198                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
199                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
200                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
201                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
202                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
203                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
204                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
205                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
206                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
207                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
208                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
209                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
210                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
211                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
212                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
213                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
214                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
215                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
216                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
217                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
218                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
219                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
220                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
221                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
222                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
223                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
224                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
225                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
226                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
227                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
228                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
229                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
230                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
231                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
232                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
233                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
234                 "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
235                 "some", "some", "some", "some", "some", "some",
236             ])
237         })
238     });
239 }
240 
241 const ABOUT: &str = "
242 ripgrep (rg) recursively searches your current directory for a regex pattern.
243 
244 ripgrep's regex engine uses finite automata and guarantees linear time
245 searching. Because of this, features like backreferences and arbitrary
246 lookaround are not supported.
247 
248 Project home page: https://github.com/BurntSushi/ripgrep
249 
250 Use -h for short descriptions and --help for more details.";
251 
252 const USAGE: &str = "
253     rg [OPTIONS] <pattern> [<path> ...]
254     rg [OPTIONS] [-e PATTERN | -f FILE ]... [<path> ...]
255     rg [OPTIONS] --files [<path> ...]
256     rg [OPTIONS] --type-list";
257 
258 const TEMPLATE: &str = "\
259 {name} {version}
260 {author}
261 {about}
262 
263 USAGE:{usage}
264 
265 ARGS:
266 {positionals}
267 
268 OPTIONS:
269 {options}";
270 
271 /// Build a clap application with short help strings.
app_short() -> Command272 fn app_short() -> Command {
273     cmd(false, |k| USAGES[k].short)
274 }
275 
276 /// Build a clap application with long help strings.
app_long() -> Command277 fn app_long() -> Command {
278     cmd(true, |k| USAGES[k].long)
279 }
280 
281 /// Build the help text of an application.
build_help(cmd: &mut Command) -> String282 fn build_help(cmd: &mut Command) -> String {
283     let help = cmd.render_help();
284     help.to_string()
285 }
286 
287 /// Build a clap application parameterized by usage strings.
288 ///
289 /// The function given should take a clap argument name and return a help
290 /// string. `cmd` will panic if a usage string is not defined.
291 ///
292 /// This is an intentionally stand-alone module so that it can be used easily
293 /// in a `build.rs` script to build shell completion files.
cmd<F>(_next_line_help: bool, doc: F) -> Command where F: Fn(&'static str) -> &'static str,294 fn cmd<F>(_next_line_help: bool, doc: F) -> Command
295 where
296     F: Fn(&'static str) -> &'static str,
297 {
298     let arg = |name| Arg::new(name).help(doc(name));
299     let flag = |name| arg(name).long(name).action(ArgAction::SetTrue);
300 
301     Command::new("ripgrep")
302         .author("BurntSushi") // simulating since it's only a bench
303         .version("0.4.0") // Simulating
304         .about(ABOUT)
305         .max_term_width(100)
306         .override_usage(USAGE)
307         .help_template(TEMPLATE)
308         // Handle help/version manually to make their output formatting
309         // consistent with short/long views.
310         .disable_help_flag(true)
311         .disable_version_flag(true)
312         .arg(arg("help-short").short('h'))
313         .arg(flag("help"))
314         .arg(flag("version").short('V'))
315         // First, set up primary positional/flag arguments.
316         .arg(arg("pattern").required_unless_present_any([
317             "file",
318             "files",
319             "help-short",
320             "help",
321             "regexp",
322             "type-list",
323             "version",
324         ]))
325         .arg(arg("path").num_args(1..))
326         .arg(
327             flag("regexp")
328                 .short('e')
329                 .allow_hyphen_values(true)
330                 .action(ArgAction::Append)
331                 .value_name("pattern"),
332         )
333         .arg(
334             flag("files")
335                 // This should also conflict with `pattern`, but the first file
336                 // path will actually be in `pattern`.
337                 .conflicts_with_all(["file", "regexp", "type-list"]),
338         )
339         .arg(flag("type-list").conflicts_with_all(["file", "files", "pattern", "regexp"]))
340         // Second, set up common flags.
341         .arg(flag("text").short('a'))
342         .arg(flag("count").short('c'))
343         .arg(
344             flag("color")
345                 .value_name("WHEN")
346                 .action(ArgAction::Set)
347                 .hide_possible_values(true)
348                 .value_parser(["never", "auto", "always", "ansi"]),
349         )
350         .arg(flag("colors").value_name("SPEC").action(ArgAction::Append))
351         .arg(flag("fixed-strings").short('F'))
352         .arg(
353             flag("glob")
354                 .short('g')
355                 .action(ArgAction::Append)
356                 .value_name("GLOB"),
357         )
358         .arg(flag("ignore-case").short('i'))
359         .arg(flag("line-number").short('n'))
360         .arg(flag("no-line-number").short('N'))
361         .arg(flag("quiet").short('q'))
362         .arg(
363             flag("type")
364                 .short('t')
365                 .action(ArgAction::Append)
366                 .value_name("TYPE"),
367         )
368         .arg(
369             flag("type-not")
370                 .short('T')
371                 .action(ArgAction::Append)
372                 .value_name("TYPE"),
373         )
374         .arg(flag("unrestricted").short('u').action(ArgAction::Append))
375         .arg(flag("invert-match").short('v'))
376         .arg(flag("word-regexp").short('w'))
377         // Third, set up less common flags.
378         .arg(
379             flag("after-context")
380                 .short('A')
381                 .action(ArgAction::Set)
382                 .value_name("NUM")
383                 .value_parser(value_parser!(usize)),
384         )
385         .arg(
386             flag("before-context")
387                 .short('B')
388                 .action(ArgAction::Set)
389                 .value_name("NUM")
390                 .value_parser(value_parser!(usize)),
391         )
392         .arg(
393             flag("context")
394                 .short('C')
395                 .action(ArgAction::Set)
396                 .value_name("NUM")
397                 .value_parser(value_parser!(usize)),
398         )
399         .arg(flag("column"))
400         .arg(flag("context-separator").value_name("SEPARATOR"))
401         .arg(flag("debug"))
402         .arg(
403             flag("file")
404                 .short('f')
405                 .value_name("FILE")
406                 .action(ArgAction::Append),
407         )
408         .arg(flag("files-with-matches").short('l'))
409         .arg(flag("files-without-match"))
410         .arg(flag("with-filename").short('H'))
411         .arg(flag("no-filename"))
412         .arg(flag("heading").overrides_with("no-heading"))
413         .arg(flag("no-heading").overrides_with("heading"))
414         .arg(flag("hidden"))
415         .arg(
416             flag("ignore-file")
417                 .value_name("FILE")
418                 .action(ArgAction::Append),
419         )
420         .arg(flag("follow").short('L'))
421         .arg(
422             flag("max-count")
423                 .short('m')
424                 .action(ArgAction::Set)
425                 .value_name("NUM")
426                 .value_parser(value_parser!(usize)),
427         )
428         .arg(
429             flag("maxdepth")
430                 .action(ArgAction::Set)
431                 .value_name("NUM")
432                 .value_parser(value_parser!(usize)),
433         )
434         .arg(flag("mmap"))
435         .arg(flag("no-messages"))
436         .arg(flag("no-mmap"))
437         .arg(flag("no-ignore"))
438         .arg(flag("no-ignore-parent"))
439         .arg(flag("no-ignore-vcs"))
440         .arg(flag("null"))
441         .arg(flag("path-separator").value_name("SEPARATOR"))
442         .arg(flag("pretty").short('p'))
443         .arg(
444             flag("replace")
445                 .short('r')
446                 .action(ArgAction::Set)
447                 .value_name("ARG"),
448         )
449         .arg(flag("case-sensitive").short('s'))
450         .arg(flag("smart-case").short('S'))
451         .arg(flag("sort-files"))
452         .arg(
453             flag("threads")
454                 .short('j')
455                 .action(ArgAction::Set)
456                 .value_name("ARG")
457                 .value_parser(value_parser!(usize)),
458         )
459         .arg(flag("vimgrep"))
460         .arg(
461             flag("type-add")
462                 .value_name("TYPE")
463                 .action(ArgAction::Append),
464         )
465         .arg(
466             flag("type-clear")
467                 .value_name("TYPE")
468                 .action(ArgAction::Append),
469         )
470 }
471 
472 struct Usage {
473     short: &'static str,
474     long: &'static str,
475 }
476 
477 macro_rules! doc {
478     ($map:expr, $name:expr, $short:expr) => {
479         doc!($map, $name, $short, $short)
480     };
481     ($map:expr, $name:expr, $short:expr, $long:expr) => {
482         $map.insert(
483             $name,
484             Usage {
485                 short: $short,
486                 long: concat!($long, "\n "),
487             },
488         );
489     };
490 }
491 
492 lazy_static! {
493     static ref USAGES: HashMap<&'static str, Usage> = {
494         let mut h = HashMap::new();
495         doc!(
496             h,
497             "help-short",
498             "Show short help output.",
499             "Show short help output. Use --help to show more details."
500         );
501         doc!(
502             h,
503             "help",
504             "Show verbose help output.",
505             "When given, more details about flags are provided."
506         );
507         doc!(h, "version", "Print version information.");
508 
509         doc!(
510             h,
511             "pattern",
512             "A regular expression used for searching.",
513             "A regular expression used for searching. Multiple patterns \
514              may be given. To match a pattern beginning with a -, use [-]."
515         );
516         doc!(
517             h,
518             "regexp",
519             "A regular expression used for searching.",
520             "A regular expression used for searching. Multiple patterns \
521              may be given. To match a pattern beginning with a -, use [-]."
522         );
523         doc!(
524             h,
525             "path",
526             "A file or directory to search.",
527             "A file or directory to search. Directories are searched \
528              recursively."
529         );
530         doc!(
531             h,
532             "files",
533             "Print each file that would be searched.",
534             "Print each file that would be searched without actually \
535              performing the search. This is useful to determine whether a \
536              particular file is being searched or not."
537         );
538         doc!(
539             h,
540             "type-list",
541             "Show all supported file types.",
542             "Show all supported file types and their corresponding globs."
543         );
544 
545         doc!(h, "text", "Search binary files as if they were text.");
546         doc!(h, "count", "Only show count of matches for each file.");
547         doc!(
548             h,
549             "color",
550             "When to use color. [default: auto]",
551             "When to use color in the output. The possible values are \
552              never, auto, always or ansi. The default is auto. When always \
553              is used, coloring is attempted based on your environment. When \
554              ansi used, coloring is forcefully done using ANSI escape color \
555              codes."
556         );
557         doc!(
558             h,
559             "colors",
560             "Configure color settings and styles.",
561             "This flag specifies color settings for use in the output. \
562              This flag may be provided multiple times. Settings are applied \
563              iteratively. Colors are limited to one of eight choices: \
564              red, blue, green, cyan, magenta, yellow, white and black. \
565              Styles are limited to nobold, bold, nointense or intense.\n\n\
566              The format of the flag is {type}:{attribute}:{value}. {type} \
567              should be one of path, line or match. {attribute} can be fg, bg \
568              or style. {value} is either a color (for fg and bg) or a text \
569              style. A special format, {type}:none, will clear all color \
570              settings for {type}.\n\nFor example, the following command will \
571              change the match color to magenta and the background color for \
572              line numbers to yellow:\n\n\
573              rg --colors 'match:fg:magenta' --colors 'line:bg:yellow' foo."
574         );
575         doc!(
576             h,
577             "fixed-strings",
578             "Treat the pattern as a literal string.",
579             "Treat the pattern as a literal string instead of a regular \
580              expression. When this flag is used, special regular expression \
581              meta characters such as (){}*+. do not need to be escaped."
582         );
583         doc!(
584             h,
585             "glob",
586             "Include or exclude files/directories.",
587             "Include or exclude files/directories for searching that \
588              match the given glob. This always overrides any other \
589              ignore logic. Multiple glob flags may be used. Globbing \
590              rules match .gitignore globs. Precede a glob with a ! \
591              to exclude it."
592         );
593         doc!(
594             h,
595             "ignore-case",
596             "Case insensitive search.",
597             "Case insensitive search. This is overridden by \
598              --case-sensitive."
599         );
600         doc!(
601             h,
602             "line-number",
603             "Show line numbers.",
604             "Show line numbers (1-based). This is enabled by default when \
605              searching in a tty."
606         );
607         doc!(
608             h,
609             "no-line-number",
610             "Suppress line numbers.",
611             "Suppress line numbers. This is enabled by default when NOT \
612              searching in a tty."
613         );
614         doc!(
615             h,
616             "quiet",
617             "Do not print anything to stdout.",
618             "Do not print anything to stdout. If a match is found in a file, \
619              stop searching. This is useful when ripgrep is used only for \
620              its exit code."
621         );
622         doc!(
623             h,
624             "type",
625             "Only search files matching TYPE.",
626             "Only search files matching TYPE. Multiple type flags may be \
627              provided. Use the --type-list flag to list all available \
628              types."
629         );
630         doc!(
631             h,
632             "type-not",
633             "Do not search files matching TYPE.",
634             "Do not search files matching TYPE. Multiple type-not flags may \
635              be provided. Use the --type-list flag to list all available \
636              types."
637         );
638         doc!(
639             h,
640             "unrestricted",
641             "Reduce the level of \"smart\" searching.",
642             "Reduce the level of \"smart\" searching. A single -u \
643              won't respect .gitignore (etc.) files. Two -u flags will \
644              additionally search hidden files and directories. Three \
645              -u flags will additionally search binary files. -uu is \
646              roughly equivalent to grep -r and -uuu is roughly \
647              equivalent to grep -a -r."
648         );
649         doc!(
650             h,
651             "invert-match",
652             "Invert matching.",
653             "Invert matching. Show lines that don't match given patterns."
654         );
655         doc!(
656             h,
657             "word-regexp",
658             "Only show matches surrounded by word boundaries.",
659             "Only show matches surrounded by word boundaries. This is \
660              equivalent to putting \\b before and after all of the search \
661              patterns."
662         );
663 
664         doc!(h, "after-context", "Show NUM lines after each match.");
665         doc!(h, "before-context", "Show NUM lines before each match.");
666         doc!(h, "context", "Show NUM lines before and after each match.");
667         doc!(
668             h,
669             "column",
670             "Show column numbers",
671             "Show column numbers (1-based). This only shows the column \
672              numbers for the first match on each line. This does not try \
673              to account for Unicode. One byte is equal to one column. This \
674              implies --line-number."
675         );
676         doc!(
677             h,
678             "context-separator",
679             "Set the context separator string. [default: --]",
680             "The string used to separate non-contiguous context lines in the \
681              output. Escape sequences like \\x7F or \\t may be used. The \
682              default value is --."
683         );
684         doc!(
685             h,
686             "debug",
687             "Show debug messages.",
688             "Show debug messages. Please use this when filing a bug report."
689         );
690         doc!(
691             h,
692             "file",
693             "Search for patterns from the given file.",
694             "Search for patterns from the given file, with one pattern per \
695              line. When this flag is used or multiple times or in \
696              combination with the -e/--regexp flag, then all patterns \
697              provided are searched. Empty pattern lines will match all input \
698              lines, and the newline is not counted as part of the pattern."
699         );
700         doc!(
701             h,
702             "files-with-matches",
703             "Only show the path of each file with at least one match."
704         );
705         doc!(
706             h,
707             "files-without-match",
708             "Only show the path of each file that contains zero matches."
709         );
710         doc!(
711             h,
712             "with-filename",
713             "Show file name for each match.",
714             "Prefix each match with the file name that contains it. This is \
715              the default when more than one file is searched."
716         );
717         doc!(
718             h,
719             "no-filename",
720             "Never show the file name for a match.",
721             "Never show the file name for a match. This is the default when \
722              one file is searched."
723         );
724         doc!(
725             h,
726             "heading",
727             "Show matches grouped by each file.",
728             "This shows the file name above clusters of matches from each \
729              file instead of showing the file name for every match. This is \
730              the default mode at a tty."
731         );
732         doc!(
733             h,
734             "no-heading",
735             "Don't group matches by each file.",
736             "Don't group matches by each file. If -H/--with-filename is \
737              enabled, then file names will be shown for every line matched. \
738              This is the default mode when not at a tty."
739         );
740         doc!(
741             h,
742             "hidden",
743             "Search hidden files and directories.",
744             "Search hidden files and directories. By default, hidden files \
745              and directories are skipped."
746         );
747         doc!(
748             h,
749             "ignore-file",
750             "Specify additional ignore files.",
751             "Specify additional ignore files for filtering file paths. \
752              Ignore files should be in the gitignore format and are matched \
753              relative to the current working directory. These ignore files \
754              have lower precedence than all other ignore files. When \
755              specifying multiple ignore files, earlier files have lower \
756              precedence than later files."
757         );
758         doc!(h, "follow", "Follow symbolic links.");
759         doc!(
760             h,
761             "max-count",
762             "Limit the number of matches.",
763             "Limit the number of matching lines per file searched to NUM."
764         );
765         doc!(
766             h,
767             "maxdepth",
768             "Descend at most NUM directories.",
769             "Limit the depth of directory traversal to NUM levels beyond \
770              the paths given. A value of zero only searches the \
771              starting-points themselves.\n\nFor example, \
772              'rg --maxdepth 0 dir/' is a no-op because dir/ will not be \
773              descended into. 'rg --maxdepth 1 dir/' will search only the \
774              direct children of dir/."
775         );
776         doc!(
777             h,
778             "mmap",
779             "Searching using memory maps when possible.",
780             "Search using memory maps when possible. This is enabled by \
781              default when ripgrep thinks it will be faster. Note that memory \
782              map searching doesn't currently support all options, so if an \
783              incompatible option (e.g., --context) is given with --mmap, \
784              then memory maps will not be used."
785         );
786         doc!(
787             h,
788             "no-messages",
789             "Suppress all error messages.",
790             "Suppress all error messages. This is equivalent to redirecting \
791              stderr to /dev/null."
792         );
793         doc!(
794             h,
795             "no-mmap",
796             "Never use memory maps.",
797             "Never use memory maps, even when they might be faster."
798         );
799         doc!(
800             h,
801             "no-ignore",
802             "Don't respect ignore files.",
803             "Don't respect ignore files (.gitignore, .ignore, etc.). This \
804              implies --no-ignore-parent and --no-ignore-vcs."
805         );
806         doc!(
807             h,
808             "no-ignore-parent",
809             "Don't respect ignore files in parent directories.",
810             "Don't respect ignore files (.gitignore, .ignore, etc.) in \
811              parent directories."
812         );
813         doc!(
814             h,
815             "no-ignore-vcs",
816             "Don't respect VCS ignore files",
817             "Don't respect version control ignore files (.gitignore, etc.). \
818              This implies --no-ignore-parent. Note that .ignore files will \
819              continue to be respected."
820         );
821         doc!(
822             h,
823             "null",
824             "Print NUL byte after file names",
825             "Whenever a file name is printed, follow it with a NUL byte. \
826              This includes printing file names before matches, and when \
827              printing a list of matching files such as with --count, \
828              --files-with-matches and --files. This option is useful for use \
829              with xargs."
830         );
831         doc!(
832             h,
833             "path-separator",
834             "Path separator to use when printing file paths.",
835             "The path separator to use when printing file paths. This \
836              defaults to your platform's path separator, which is / on Unix \
837              and \\ on Windows. This flag is intended for overriding the \
838              default when the environment demands it (e.g., cygwin). A path \
839              separator is limited to a single byte."
840         );
841         doc!(h, "pretty", "Alias for --color always --heading -n.");
842         doc!(
843             h,
844             "replace",
845             "Replace matches with string given.",
846             "Replace every match with the string given when printing \
847              results. Neither this flag nor any other flag will modify your \
848              files.\n\nCapture group indices (e.g., $5) and names \
849              (e.g., $foo) are supported in the replacement string.\n\n\
850              Note that the replacement by default replaces each match, and \
851              NOT the entire line. To replace the entire line, you should \
852              match the entire line."
853         );
854         doc!(
855             h,
856             "case-sensitive",
857             "Search case sensitively.",
858             "Search case sensitively. This overrides -i/--ignore-case and \
859              -S/--smart-case."
860         );
861         doc!(
862             h,
863             "smart-case",
864             "Smart case search.",
865             "Searches case insensitively if the pattern is all lowercase. \
866              Search case sensitively otherwise. This is overridden by \
867              either -s/--case-sensitive or -i/--ignore-case."
868         );
869         doc!(
870             h,
871             "sort-files",
872             "Sort results by file path. Implies --threads=1.",
873             "Sort results by file path. Note that this currently \
874              disables all parallelism and runs search in a single thread."
875         );
876         doc!(
877             h,
878             "threads",
879             "The approximate number of threads to use.",
880             "The approximate number of threads to use. A value of 0 (which \
881              is the default) causes ripgrep to choose the thread count \
882              using heuristics."
883         );
884         doc!(
885             h,
886             "vimgrep",
887             "Show results in vim compatible format.",
888             "Show results with every match on its own line, including \
889              line numbers and column numbers. With this option, a line with \
890              more than one match will be printed more than once."
891         );
892 
893         doc!(
894             h,
895             "type-add",
896             "Add a new glob for a file type.",
897             "Add a new glob for a particular file type. Only one glob can be \
898              added at a time. Multiple --type-add flags can be provided. \
899              Unless --type-clear is used, globs are added to any existing \
900              globs defined inside of ripgrep.\n\nNote that this MUST be \
901              passed to every invocation of ripgrep. Type settings are NOT \
902              persisted.\n\nExample: \
903              rg --type-add 'foo:*.foo' -tfoo PATTERN.\n\n\
904              --type-add can also be used to include rules from other types \
905              with the special include directive. The include directive \
906              permits specifying one or more other type names (separated by a \
907              comma) that have been defined and its rules will automatically \
908              be imported into the type specified. For example, to create a \
909              type called src that matches C++, Python and Markdown files, one \
910              can use:\n\n\
911              --type-add 'src:include:cpp,py,md'\n\n\
912              Additional glob rules can still be added to the src type by \
913              using the --type-add flag again:\n\n\
914              --type-add 'src:include:cpp,py,md' --type-add 'src:*.foo'\n\n\
915              Note that type names must consist only of Unicode letters or \
916              numbers. Punctuation characters are not allowed."
917         );
918         doc!(
919             h,
920             "type-clear",
921             "Clear globs for given file type.",
922             "Clear the file type globs previously defined for TYPE. This \
923              only clears the default type definitions that are found inside \
924              of ripgrep.\n\nNote that this MUST be passed to every \
925              invocation of ripgrep. Type settings are NOT persisted."
926         );
927 
928         h
929     };
930 }
931 
932 criterion_group!(
933     benches,
934     build_rg_with_short_help,
935     build_rg_with_long_help,
936     write_rg_short_help,
937     write_rg_long_help,
938     parse_rg,
939     parse_rg_with_complex,
940     parse_rg_with_lots
941 );
942 criterion_main!(benches);
943