diff options
Diffstat (limited to 'clap/benches')
| -rw-r--r-- | clap/benches/01_default.rs | 18 | ||||
| -rw-r--r-- | clap/benches/02_simple.rs | 114 | ||||
| -rw-r--r-- | clap/benches/03_complex.rs | 230 | ||||
| -rw-r--r-- | clap/benches/04_new_help.rs | 198 | ||||
| -rw-r--r-- | clap/benches/05_ripgrep.rs | 777 | ||||
| -rw-r--r-- | clap/benches/06_rustup.rs | 458 | 
6 files changed, 1795 insertions, 0 deletions
diff --git a/clap/benches/01_default.rs b/clap/benches/01_default.rs new file mode 100644 index 0000000..24e619e --- /dev/null +++ b/clap/benches/01_default.rs @@ -0,0 +1,18 @@ +#![feature(test)] + +extern crate clap; +extern crate test; + +use clap::App; + +use test::Bencher; + +#[bench] +fn build_app(b: &mut Bencher) { +    b.iter(|| App::new("claptests")); +} + +#[bench] +fn parse_clean(b: &mut Bencher) { +    b.iter(|| App::new("claptests").get_matches_from(vec![""])); +} diff --git a/clap/benches/02_simple.rs b/clap/benches/02_simple.rs new file mode 100644 index 0000000..010fa86 --- /dev/null +++ b/clap/benches/02_simple.rs @@ -0,0 +1,114 @@ +#![feature(test)] + +extern crate clap; +extern crate test; + +use clap::{App, Arg}; + +use test::Bencher; + +macro_rules! create_app { +    () => ({ +        App::new("claptests") +                .version("0.1") +                .about("tests clap library") +                .author("Kevin K. <kbknapp@gmail.com>") +                .args_from_usage("-f --flag         'tests flags' +                                  -o --option=[opt] 'tests options' +                                  [positional]      'tests positional'") +    }) +} + +#[bench] +fn build_app(b: &mut Bencher) { + +    b.iter(|| create_app!()); +} + +#[bench] +fn add_flag(b: &mut Bencher) { +    fn build_app() -> App<'static, 'static> { +        App::new("claptests") +    } + +    b.iter(|| build_app().arg(Arg::from_usage("-s, --some 'something'"))); +} + +#[bench] +fn add_flag_ref(b: &mut Bencher) { +    fn build_app() -> App<'static, 'static> { +        App::new("claptests") +    } + +    b.iter(|| { +        let arg = Arg::from_usage("-s, --some 'something'"); +        build_app().arg(&arg) +    }); +} + +#[bench] +fn add_opt(b: &mut Bencher) { +    fn build_app() -> App<'static, 'static> { +        App::new("claptests") +    } + +    b.iter(|| build_app().arg(Arg::from_usage("-s, --some <FILE> 'something'"))); +} + +#[bench] +fn add_opt_ref(b: &mut Bencher) { +    fn build_app() -> App<'static, 'static> { +        App::new("claptests") +    } + +    b.iter(|| { +        let arg = Arg::from_usage("-s, --some <FILE> 'something'"); +        build_app().arg(&arg) +    }); +} + +#[bench] +fn add_pos(b: &mut Bencher) { +    fn build_app() -> App<'static, 'static> { +        App::new("claptests") +    } + +    b.iter(|| build_app().arg(Arg::with_name("some"))); +} + +#[bench] +fn add_pos_ref(b: &mut Bencher) { +    fn build_app() -> App<'static, 'static> { +        App::new("claptests") +    } + +    b.iter(|| { +        let arg = Arg::with_name("some"); +        build_app().arg(&arg) +    }); +} + +#[bench] +fn parse_clean(b: &mut Bencher) { +    b.iter(|| create_app!().get_matches_from(vec![""])); +} + +#[bench] +fn parse_flag(b: &mut Bencher) { +    b.iter(|| create_app!().get_matches_from(vec!["myprog", "-f"])); +} + +#[bench] +fn parse_option(b: &mut Bencher) { +    b.iter(|| create_app!().get_matches_from(vec!["myprog", "-o", "option1"])); +} + +#[bench] +fn parse_positional(b: &mut Bencher) { +    b.iter(|| create_app!().get_matches_from(vec!["myprog", "arg1"])); +} + +#[bench] +fn parse_complex(b: &mut Bencher) { +    b.iter(|| create_app!().get_matches_from(vec!["myprog", "-o", "option1", "-f", "arg1"])); +} diff --git a/clap/benches/03_complex.rs b/clap/benches/03_complex.rs new file mode 100644 index 0000000..b00fc4e --- /dev/null +++ b/clap/benches/03_complex.rs @@ -0,0 +1,230 @@ +#![feature(test)] + +#[macro_use] +extern crate clap; +extern crate test; + +use clap::{App, Arg, SubCommand, AppSettings}; + +use test::Bencher; + +static ARGS: &'static str = "-o --option=[opt]... 'tests options' +                             [positional] 'tests positionals'"; +static OPT3_VALS: [&'static str; 2] = ["fast", "slow"]; +static POS3_VALS: [&'static str; 2] = ["vi", "emacs"]; + +macro_rules! create_app { +    () => ({ +        App::new("claptests") +                .version("0.1") +                .about("tests clap library") +                .author("Kevin K. <kbknapp@gmail.com>") +                .args_from_usage(ARGS) +                .arg(Arg::from_usage("-f --flag... 'tests flags'") +                             .global(true)) +                .args(&[ +                          Arg::from_usage("[flag2] -F 'tests flags with exclusions'").conflicts_with("flag").requires("option2"), +                          Arg::from_usage("--long-option-2 [option2] 'tests long options with exclusions'").conflicts_with("option").requires("positional2"), +                          Arg::from_usage("[positional2] 'tests positionals with exclusions'"), +                          Arg::from_usage("-O --Option [option3] 'tests options with specific value sets'").possible_values(&OPT3_VALS), +                          Arg::from_usage("[positional3]... 'tests positionals with specific values'").possible_values(&POS3_VALS), +                          Arg::from_usage("--multvals [one] [two] 'Tests multiple values, not mult occs'"), +                          Arg::from_usage("--multvalsmo... [one] [two] 'Tests multiple values, not mult occs'"), +                          Arg::from_usage("--minvals2 [minvals]... 'Tests 2 min vals'").min_values(2), +                          Arg::from_usage("--maxvals3 [maxvals]... 'Tests 3 max vals'").max_values(3) +                    ]) +                .subcommand(SubCommand::with_name("subcmd") +                                        .about("tests subcommands") +                                        .version("0.1") +                                        .author("Kevin K. <kbknapp@gmail.com>") +                                        .arg_from_usage("-o --option [scoption]... 'tests options'") +                                        .arg_from_usage("[scpositional] 'tests positionals'")) +    }) +} + +#[bench] +fn create_app_from_usage(b: &mut Bencher) { + +    b.iter(|| create_app!()); +} + +#[bench] +fn create_app_builder(b: &mut Bencher) { +    b.iter(|| { +        App::new("claptests") +                .version("0.1") +                .about("tests clap library") +                .author("Kevin K. <kbknapp@gmail.com>") +                .arg(Arg::with_name("opt") +                    .help("tests options") +                    .short("o") +                    .long("option") +                    .takes_value(true) +                    .multiple(true)) +                .arg(Arg::with_name("positional") +                    .help("tests positionals") +                    .index(1)) +                .arg(Arg::with_name("flag") +                     .short("f") +                     .help("tests flags") +                     .long("flag") +                     .multiple(true) +                     .global(true)) +                .arg(Arg::with_name("flag2") +                    .short("F") +                    .help("tests flags with exclusions") +                    .conflicts_with("flag") +                    .requires("option2")) +                .arg(Arg::with_name("option2") +                    .help("tests long options with exclusions") +                    .conflicts_with("option") +                    .requires("positional2") +                    .takes_value(true) +                    .long("long-option-2")) +                .arg(Arg::with_name("positional2") +                    .index(3) +                    .help("tests positionals with exclusions")) +                .arg(Arg::with_name("option3") +                    .short("O") +                    .long("Option") +                    .takes_value(true) +                    .help("tests options with specific value sets") +                    .possible_values(&OPT3_VALS)) +                .arg(Arg::with_name("positional3") +                    .multiple(true) +                    .help("tests positionals with specific values") +                    .index(4) +                    .possible_values(&POS3_VALS)) +                .arg(Arg::with_name("multvals") +                    .long("multvals") +                    .takes_value(true) +                    .help("Tests multiple values, not mult occs") +                    .value_names(&["one", "two"])) +                .arg(Arg::with_name("multvalsmo") +                    .long("multvalsmo") +                    .takes_value(true) +                    .multiple(true) +                    .help("Tests multiple values, not mult occs") +                    .value_names(&["one", "two"])) +                .arg(Arg::with_name("minvals") +                    .long("minvals2") +                    .multiple(true) +                    .takes_value(true) +                    .help("Tests 2 min vals") +                    .min_values(2)) +                .arg(Arg::with_name("maxvals") +                    .long("maxvals3") +                    .takes_value(true) +                    .multiple(true) +                    .help("Tests 3 max vals") +                    .max_values(3)) +                .subcommand(SubCommand::with_name("subcmd") +                    .about("tests subcommands") +                    .version("0.1") +                    .author("Kevin K. <kbknapp@gmail.com>") +                    .arg(Arg::with_name("scoption") +                        .short("o") +                        .long("option") +                        .multiple(true) +                        .takes_value(true) +                        .help("tests options")) +                    .arg(Arg::with_name("scpositional") +                        .index(1) +                        .help("tests positionals"))); +    }); +} + +#[bench] +fn create_app_macros(b: &mut Bencher) { +    b.iter(|| { +        clap_app!(claptests => +                (version: "0.1") +                (about: "tests clap library") +                (author: "Kevin K. <kbknapp@gmail.com>") +                (@arg opt: -o --option +takes_value ... "tests options") +                (@arg positional: index(1) "tests positionals") +                (@arg flag: -f --flag ... +global "tests flags") +                (@arg flag2: -F conflicts_with[flag] requires[option2] +                    "tests flags with exclusions") +                (@arg option2: --long_option_2 conflicts_with[option] requires[positional2] +                    "tests long options with exclusions") +                (@arg positional2: index(2) "tests positionals with exclusions") +                (@arg option3: -O --Option +takes_value possible_value[fast slow] +                    "tests options with specific value sets") +                (@arg positional3: index(3) ... possible_value[vi emacs] +                    "tests positionals with specific values") +                (@arg multvals: --multvals +takes_value value_name[one two] +                    "Tests multiple values, not mult occs") +                (@arg multvalsmo: --multvalsmo ... +takes_value value_name[one two] +                    "Tests multiple values, not mult occs") +                (@arg minvals: --minvals2 min_values(1) ... +takes_value "Tests 2 min vals") +                (@arg maxvals: --maxvals3 ... +takes_value max_values(3) "Tests 3 max vals") +                (@subcommand subcmd => +                    (about: "tests subcommands") +                    (version: "0.1") +                    (author: "Kevin K. <kbknapp@gmail.com>") +                    (@arg scoption: -o --option ... +takes_value "tests options") +                    (@arg scpositional: index(1) "tests positionals")) +        ); +    }); +} + +#[bench] +fn parse_clean(b: &mut Bencher) { +    b.iter(|| create_app!().get_matches_from(vec![""])); +} + +#[bench] +fn parse_flag(b: &mut Bencher) { +    b.iter(|| create_app!().get_matches_from(vec!["myprog", "-f"])); +} + +#[bench] +fn parse_option(b: &mut Bencher) { +    b.iter(|| create_app!().get_matches_from(vec!["myprog", "-o", "option1"])); +} + +#[bench] +fn parse_positional(b: &mut Bencher) { +    b.iter(|| create_app!().get_matches_from(vec!["myprog", "arg1"])); +} + +#[bench] +fn parse_sc_clean(b: &mut Bencher) { +    b.iter(|| create_app!().get_matches_from(vec!["myprog", "subcmd"])); +} + +#[bench] +fn parse_sc_flag(b: &mut Bencher) { +    b.iter(|| create_app!().get_matches_from(vec!["myprog", "subcmd", "-f"])); +} + +#[bench] +fn parse_sc_option(b: &mut Bencher) { +    b.iter(|| create_app!().get_matches_from(vec!["myprog", "subcmd", "-o", "option1"])); +} + +#[bench] +fn parse_sc_positional(b: &mut Bencher) { +    b.iter(|| create_app!().get_matches_from(vec!["myprog", "subcmd", "arg1"])); +} + +#[bench] +fn parse_complex1(b: &mut Bencher) { +    b.iter(|| create_app!().get_matches_from(vec!["myprog", "-ff", "-o", "option1", "arg1", "-O", "fast", "arg2", "--multvals", "one", "two", "emacs"])); +} + +#[bench] +fn parse_complex2(b: &mut Bencher) { +    b.iter(|| create_app!().get_matches_from(vec!["myprog", "arg1", "-f", "arg2", "--long-option-2", "some", "-O", "slow", "--multvalsmo", "one", "two", "--minvals2", "3", "2", "1"])); +} + +#[bench] +fn parse_complex2_with_args_negate_scs(b: &mut Bencher) { +    b.iter(|| create_app!().setting(AppSettings::ArgsNegateSubcommands).get_matches_from(vec!["myprog", "arg1", "-f", "arg2", "--long-option-2", "some", "-O", "slow", "--multvalsmo", "one", "two", "--minvals2", "3", "2", "1"])); +} + +#[bench] +fn parse_sc_complex(b: &mut Bencher) { +    b.iter(|| create_app!().get_matches_from(vec!["myprog", "subcmd", "-f", "-o", "option1", "arg1"])); +} diff --git a/clap/benches/04_new_help.rs b/clap/benches/04_new_help.rs new file mode 100644 index 0000000..f033efb --- /dev/null +++ b/clap/benches/04_new_help.rs @@ -0,0 +1,198 @@ +#![feature(test)] + +extern crate clap; +extern crate test; + +use test::Bencher; + +use std::io::Cursor; + +use clap::App; +use clap::{Arg, SubCommand}; + +fn build_help(app: &App) -> String { +    let mut buf = Cursor::new(Vec::with_capacity(50)); +    app.write_help(&mut buf).unwrap(); +    let content = buf.into_inner(); +    String::from_utf8(content).unwrap() +} + +fn app_example1<'b, 'c>() -> App<'b, 'c> { +    App::new("MyApp") +        .version("1.0") +        .author("Kevin K. <kbknapp@gmail.com>") +        .about("Does awesome things") +        .args_from_usage("-c, --config=[FILE] 'Sets a custom config file' +                          <output> 'Sets an optional output file' +                          -d... 'Turn debugging information on'") +        .subcommand(SubCommand::with_name("test") +            .about("does testing things") +            .arg_from_usage("-l, --list 'lists test values'")) +} + +fn app_example2<'b, 'c>() -> App<'b, 'c> { +    App::new("MyApp") +        .version("1.0") +        .author("Kevin K. <kbknapp@gmail.com>") +        .about("Does awesome things") +} + +fn app_example3<'b, 'c>() -> App<'b, 'c> { +    App::new("MyApp") +        .arg(Arg::with_name("debug") +            .help("turn on debugging information") +            .short("d")) +        .args(&[Arg::with_name("config") +                    .help("sets the config file to use") +                    .takes_value(true) +                    .short("c") +                    .long("config"), +                Arg::with_name("input") +                    .help("the input file to use") +                    .index(1) +                    .required(true)]) +        .arg_from_usage("--license 'display the license file'") +        .args_from_usage("[output] 'Supply an output file to use' +                          -i, --int=[IFACE] 'Set an interface to use'") +} + +fn app_example4<'b, 'c>() -> App<'b, 'c> { +    App::new("MyApp") +        .about("Parses an input file to do awesome things") +        .version("1.0") +        .author("Kevin K. <kbknapp@gmail.com>") +        .arg(Arg::with_name("debug") +            .help("turn on debugging information") +            .short("d") +            .long("debug")) +        .arg(Arg::with_name("config") +            .help("sets the config file to use") +            .short("c") +            .long("config")) +        .arg(Arg::with_name("input") +            .help("the input file to use") +            .index(1) +            .required(true)) +} + +fn app_example5<'b, 'c>() -> App<'b, 'c> { +    App::new("MyApp").arg(Arg::with_name("awesome") +        .help("turns up the awesome") +        .short("a") +        .long("awesome") +        .multiple(true) +        .requires("config") +        .conflicts_with("output")) +} + +fn app_example6<'b, 'c>() -> App<'b, 'c> { +    App::new("MyApp") +        .arg(Arg::with_name("input") +            .help("the input file to use") +            .index(1) +            .requires("config") +            .conflicts_with("output") +            .required(true)) +        .arg(Arg::with_name("config") +            .help("the config file to use") +            .index(2)) +} + +fn app_example7<'b, 'c>() -> App<'b, 'c> { +    App::new("MyApp") +        .arg(Arg::with_name("config")) +        .arg(Arg::with_name("output")) +        .arg(Arg::with_name("input") +            .help("the input file to use") +            .takes_value(true) +            .short("i") +            .long("input") +            .multiple(true) +            .required(true) +            .requires("config") +            .conflicts_with("output")) +} + +fn app_example8<'b, 'c>() -> App<'b, 'c> { +    App::new("MyApp") +        .arg(Arg::with_name("config")) +        .arg(Arg::with_name("output")) +        .arg(Arg::with_name("input") +            .help("the input file to use") +            .takes_value(true) +            .short("i") +            .long("input") +            .multiple(true) +            .required(true) +            .requires("config") +            .conflicts_with("output")) +} + +fn app_example10<'b, 'c>() -> App<'b, 'c> { +    App::new("myapp") +        .about("does awesome things") +        .arg(Arg::with_name("CONFIG") +            .help("The config file to use (default is \"config.json\")") +            .short("c") +            .takes_value(true)) +} + +#[bench] +fn example1(b: &mut Bencher) { +    let app = app_example1(); +    b.iter(|| build_help(&app)); +} + +#[bench] +fn example2(b: &mut Bencher) { +    let app = app_example2(); +    b.iter(|| build_help(&app)); +} + +#[bench] +fn example3(b: &mut Bencher) { +    let app = app_example3(); +    b.iter(|| build_help(&app)); +} + +#[bench] +fn example4(b: &mut Bencher) { +    let app = app_example4(); +    b.iter(|| build_help(&app)); +} + +#[bench] +fn example5(b: &mut Bencher) { +    let app = app_example5(); +    b.iter(|| build_help(&app)); +} + +#[bench] +fn example6(b: &mut Bencher) { +    let app = app_example6(); +    b.iter(|| build_help(&app)); +} + +#[bench] +fn example7(b: &mut Bencher) { +    let app = app_example7(); +    b.iter(|| build_help(&app)); +} + +#[bench] +fn example8(b: &mut Bencher) { +    let app = app_example8(); +    b.iter(|| build_help(&app)); +} + +#[bench] +fn example10(b: &mut Bencher) { +    let app = app_example10(); +    b.iter(|| build_help(&app)); +} + +#[bench] +fn example4_template(b: &mut Bencher) { +    let app = app_example4().template("{bin} {version}\n{author}\n{about}\n\nUSAGE:\n    {usage}\n\nFLAGS:\n{flags}\n\nARGS:\n{args}\n"); +    b.iter(|| build_help(&app)); +} diff --git a/clap/benches/05_ripgrep.rs b/clap/benches/05_ripgrep.rs new file mode 100644 index 0000000..7db1552 --- /dev/null +++ b/clap/benches/05_ripgrep.rs @@ -0,0 +1,777 @@ +// Used to simulate a fairly large number of options/flags and parsing with thousands of positional +// args +// +// CLI used is adapted from ripgrep 48a8a3a691220f9e5b2b08f4051abe8655ea7e8a + +#![feature(test)] + +extern crate clap; +extern crate test; +#[macro_use] +extern crate lazy_static; + +use clap::{App, AppSettings, Arg, ArgSettings}; + +use test::Bencher; +use std::collections::HashMap; +use std::io::Cursor; + +#[bench] +fn build_app_short(b: &mut Bencher) { b.iter(|| app_short()); } + +#[bench] +fn build_app_long(b: &mut Bencher) { b.iter(|| app_long()); } + +#[bench] +fn build_help_short(b: &mut Bencher) { +    let app = app_short(); +    b.iter(|| build_help(&app)); +} + +#[bench] +fn build_help_long(b: &mut Bencher) { +    let app = app_long(); +    b.iter(|| build_help(&app)); +} + +#[bench] +fn parse_clean(b: &mut Bencher) { b.iter(|| app_short().get_matches_from(vec!["rg", "pat"])); } + +#[bench] +fn parse_complex(b: &mut Bencher) { +    b.iter(|| { +        app_short().get_matches_from(vec!["rg", +                                          "pat", +                                          "-cFlN", +                                          "-pqr=some", +                                          "--null", +                                          "--no-filename", +                                          "--no-messages", +                                          "-SH", +                                          "-C5", +                                          "--follow", +                                          "-e some"]) +    }); +} + +#[bench] +fn parse_lots(b: &mut Bencher) { +    b.iter(|| { +        app_short() +            .get_matches_from(vec!["rg", "pat", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some", "some", "some", "some", "some", +                                   "some", "some", "some", "some"]) +    }); +} + +const ABOUT: &'static str = " +ripgrep (rg) recursively searches your current directory for a regex pattern. + +ripgrep's regex engine uses finite automata and guarantees linear time +searching. Because of this, features like backreferences and arbitrary +lookaround are not supported. + +Project home page: https://github.com/BurntSushi/ripgrep + +Use -h for short descriptions and --help for more details."; + +const USAGE: &'static str = " +    rg [OPTIONS] <pattern> [<path> ...] +    rg [OPTIONS] [-e PATTERN | -f FILE ]... [<path> ...] +    rg [OPTIONS] --files [<path> ...] +    rg [OPTIONS] --type-list"; + +const TEMPLATE: &'static str = "\ +{bin} {version} +{author} +{about} + +USAGE:{usage} + +ARGS: +{positionals} + +OPTIONS: +{unified}"; + +/// Build a clap application with short help strings. +pub fn app_short() -> App<'static, 'static> { app(false, |k| USAGES[k].short) } + +/// Build a clap application with long help strings. +pub fn app_long() -> App<'static, 'static> { app(true, |k| USAGES[k].long) } + + +/// Build the help text of an application. +fn build_help(app: &App) -> String { +    let mut buf = Cursor::new(Vec::with_capacity(50)); +    app.write_help(&mut buf).unwrap(); +    let content = buf.into_inner(); +    String::from_utf8(content).unwrap() +} + + +/// Build a clap application parameterized by usage strings. +/// +/// The function given should take a clap argument name and return a help +/// string. `app` will panic if a usage string is not defined. +/// +/// This is an intentionally stand-alone module so that it can be used easily +/// in a `build.rs` script to build shell completion files. +fn app<F>(next_line_help: bool, doc: F) -> App<'static, 'static> +    where F: Fn(&'static str) -> &'static str +{ +    let arg = |name| Arg::with_name(name).help(doc(name)).next_line_help(next_line_help); +    let flag = |name| arg(name).long(name); + +    App::new("ripgrep") +        .author("BurntSushi") // simulating since it's only a bench +        .version("0.4.0") // Simulating +        .about(ABOUT) +        .max_term_width(100) +        .setting(AppSettings::UnifiedHelpMessage) +        .usage(USAGE) +        .template(TEMPLATE) +        // Handle help/version manually to make their output formatting +        // consistent with short/long views. +        .arg(arg("help-short").short("h")) +        .arg(flag("help")) +        .arg(flag("version").short("V")) +        // First, set up primary positional/flag arguments. +        .arg(arg("pattern") +             .required_unless_one(&[ +                "file", "files", "help-short", "help", "regexp", "type-list", +                "version", +             ])) +        .arg(arg("path").multiple(true)) +        .arg(flag("regexp").short("e") +             .takes_value(true).multiple(true).number_of_values(1) +             .set(ArgSettings::AllowLeadingHyphen) +             .value_name("pattern")) +        .arg(flag("files") +             // This should also conflict with `pattern`, but the first file +             // path will actually be in `pattern`. +             .conflicts_with_all(&["file", "regexp", "type-list"])) +        .arg(flag("type-list") +             .conflicts_with_all(&["file", "files", "pattern", "regexp"])) +        // Second, set up common flags. +        .arg(flag("text").short("a")) +        .arg(flag("count").short("c")) +        .arg(flag("color") +             .value_name("WHEN") +             .takes_value(true) +             .hide_possible_values(true) +             .possible_values(&["never", "auto", "always", "ansi"])) +        .arg(flag("colors").value_name("SPEC") +             .takes_value(true).multiple(true).number_of_values(1)) +        .arg(flag("fixed-strings").short("F")) +        .arg(flag("glob").short("g") +             .takes_value(true).multiple(true).number_of_values(1) +             .value_name("GLOB")) +        .arg(flag("ignore-case").short("i")) +        .arg(flag("line-number").short("n")) +        .arg(flag("no-line-number").short("N")) +        .arg(flag("quiet").short("q")) +        .arg(flag("type").short("t") +             .takes_value(true).multiple(true).number_of_values(1) +             .value_name("TYPE")) +        .arg(flag("type-not").short("T") +             .takes_value(true).multiple(true).number_of_values(1) +             .value_name("TYPE")) +        .arg(flag("unrestricted").short("u") +             .multiple(true)) +        .arg(flag("invert-match").short("v")) +        .arg(flag("word-regexp").short("w")) +        // Third, set up less common flags. +        .arg(flag("after-context").short("A") +             .value_name("NUM").takes_value(true) +             .validator(validate_number)) +        .arg(flag("before-context").short("B") +             .value_name("NUM").takes_value(true) +             .validator(validate_number)) +        .arg(flag("context").short("C") +             .value_name("NUM").takes_value(true) +             .validator(validate_number)) +        .arg(flag("column")) +        .arg(flag("context-separator") +             .value_name("SEPARATOR").takes_value(true)) +        .arg(flag("debug")) +        .arg(flag("file").short("f") +             .value_name("FILE").takes_value(true) +             .multiple(true).number_of_values(1)) +        .arg(flag("files-with-matches").short("l")) +        .arg(flag("files-without-match")) +        .arg(flag("with-filename").short("H")) +        .arg(flag("no-filename")) +        .arg(flag("heading").overrides_with("no-heading")) +        .arg(flag("no-heading").overrides_with("heading")) +        .arg(flag("hidden")) +        .arg(flag("ignore-file") +             .value_name("FILE").takes_value(true) +             .multiple(true).number_of_values(1)) +        .arg(flag("follow").short("L")) +        .arg(flag("max-count") +             .short("m").value_name("NUM").takes_value(true) +             .validator(validate_number)) +        .arg(flag("maxdepth") +             .value_name("NUM").takes_value(true) +             .validator(validate_number)) +        .arg(flag("mmap")) +        .arg(flag("no-messages")) +        .arg(flag("no-mmap")) +        .arg(flag("no-ignore")) +        .arg(flag("no-ignore-parent")) +        .arg(flag("no-ignore-vcs")) +        .arg(flag("null")) +        .arg(flag("path-separator").value_name("SEPARATOR").takes_value(true)) +        .arg(flag("pretty").short("p")) +        .arg(flag("replace").short("r").value_name("ARG").takes_value(true)) +        .arg(flag("case-sensitive").short("s")) +        .arg(flag("smart-case").short("S")) +        .arg(flag("sort-files")) +        .arg(flag("threads") +             .short("j").value_name("ARG").takes_value(true) +             .validator(validate_number)) +        .arg(flag("vimgrep")) +        .arg(flag("type-add") +             .value_name("TYPE").takes_value(true) +             .multiple(true).number_of_values(1)) +        .arg(flag("type-clear") +             .value_name("TYPE").takes_value(true) +             .multiple(true).number_of_values(1)) +} + +struct Usage { +    short: &'static str, +    long: &'static str, +} + +macro_rules! doc { +    ($map:expr, $name:expr, $short:expr) => { +        doc!($map, $name, $short, $short) +    }; +    ($map:expr, $name:expr, $short:expr, $long:expr) => { +        $map.insert($name, Usage { +            short: $short, +            long: concat!($long, "\n "), +        }); +    }; +} + +lazy_static! { +    static ref USAGES: HashMap<&'static str, Usage> = { +        let mut h = HashMap::new(); +        doc!(h, "help-short", +             "Show short help output.", +             "Show short help output. Use --help to show more details."); +        doc!(h, "help", +             "Show verbose help output.", +             "When given, more details about flags are provided."); +        doc!(h, "version", +             "Prints version information."); + +        doc!(h, "pattern", +             "A regular expression used for searching.", +             "A regular expression used for searching. Multiple patterns \ +              may be given. To match a pattern beginning with a -, use [-]."); +        doc!(h, "regexp", +             "A regular expression used for searching.", +             "A regular expression used for searching. Multiple patterns \ +              may be given. To match a pattern beginning with a -, use [-]."); +        doc!(h, "path", +             "A file or directory to search.", +             "A file or directory to search. Directories are searched \ +              recursively."); +        doc!(h, "files", +             "Print each file that would be searched.", +             "Print each file that would be searched without actually \ +              performing the search. This is useful to determine whether a \ +              particular file is being searched or not."); +        doc!(h, "type-list", +             "Show all supported file types.", +             "Show all supported file types and their corresponding globs."); + +        doc!(h, "text", +             "Search binary files as if they were text."); +        doc!(h, "count", +             "Only show count of matches for each file."); +        doc!(h, "color", +             "When to use color. [default: auto]", +             "When to use color in the output. The possible values are \ +              never, auto, always or ansi. The default is auto. When always \ +              is used, coloring is attempted based on your environment. When \ +              ansi used, coloring is forcefully done using ANSI escape color \ +              codes."); +        doc!(h, "colors", +             "Configure color settings and styles.", +             "This flag specifies color settings for use in the output. \ +              This flag may be provided multiple times. Settings are applied \ +              iteratively. Colors are limited to one of eight choices: \ +              red, blue, green, cyan, magenta, yellow, white and black. \ +              Styles are limited to nobold, bold, nointense or intense.\n\n\ +              The format of the flag is {type}:{attribute}:{value}. {type} \ +              should be one of path, line or match. {attribute} can be fg, bg \ +              or style. {value} is either a color (for fg and bg) or a text \ +              style. A special format, {type}:none, will clear all color \ +              settings for {type}.\n\nFor example, the following command will \ +              change the match color to magenta and the background color for \ +              line numbers to yellow:\n\n\ +              rg --colors 'match:fg:magenta' --colors 'line:bg:yellow' foo."); +        doc!(h, "fixed-strings", +             "Treat the pattern as a literal string.", +             "Treat the pattern as a literal string instead of a regular \ +              expression. When this flag is used, special regular expression \ +              meta characters such as (){}*+. do not need to be escaped."); +        doc!(h, "glob", +             "Include or exclude files/directories.", +             "Include or exclude files/directories for searching that \ +              match the given glob. This always overrides any other \ +              ignore logic. Multiple glob flags may be used. Globbing \ +              rules match .gitignore globs. Precede a glob with a ! \ +              to exclude it."); +        doc!(h, "ignore-case", +             "Case insensitive search.", +             "Case insensitive search. This is overridden by \ +              --case-sensitive."); +        doc!(h, "line-number", +             "Show line numbers.", +             "Show line numbers (1-based). This is enabled by default when \ +              searching in a tty."); +        doc!(h, "no-line-number", +             "Suppress line numbers.", +             "Suppress line numbers. This is enabled by default when NOT \ +              searching in a tty."); +        doc!(h, "quiet", +             "Do not print anything to stdout.", +             "Do not print anything to stdout. If a match is found in a file, \ +              stop searching. This is useful when ripgrep is used only for \ +              its exit code."); +        doc!(h, "type", +             "Only search files matching TYPE.", +             "Only search files matching TYPE. Multiple type flags may be \ +              provided. Use the --type-list flag to list all available \ +              types."); +        doc!(h, "type-not", +             "Do not search files matching TYPE.", +             "Do not search files matching TYPE. Multiple type-not flags may \ +              be provided. Use the --type-list flag to list all available \ +              types."); +        doc!(h, "unrestricted", +             "Reduce the level of \"smart\" searching.", +             "Reduce the level of \"smart\" searching. A single -u \ +              won't respect .gitignore (etc.) files. Two -u flags will \ +              additionally search hidden files and directories. Three \ +              -u flags will additionally search binary files. -uu is \ +              roughly equivalent to grep -r and -uuu is roughly \ +              equivalent to grep -a -r."); +        doc!(h, "invert-match", +             "Invert matching.", +             "Invert matching. Show lines that don't match given patterns."); +        doc!(h, "word-regexp", +             "Only show matches surrounded by word boundaries.", +             "Only show matches surrounded by word boundaries. This is \ +              equivalent to putting \\b before and after all of the search \ +              patterns."); + +        doc!(h, "after-context", +             "Show NUM lines after each match."); +        doc!(h, "before-context", +             "Show NUM lines before each match."); +        doc!(h, "context", +             "Show NUM lines before and after each match."); +        doc!(h, "column", +             "Show column numbers", +             "Show column numbers (1-based). This only shows the column \ +              numbers for the first match on each line. This does not try \ +              to account for Unicode. One byte is equal to one column. This \ +              implies --line-number."); +        doc!(h, "context-separator", +             "Set the context separator string. [default: --]", +             "The string used to separate non-contiguous context lines in the \ +              output. Escape sequences like \\x7F or \\t may be used. The \ +              default value is --."); +        doc!(h, "debug", +             "Show debug messages.", +             "Show debug messages. Please use this when filing a bug report."); +        doc!(h, "file", +             "Search for patterns from the given file.", +             "Search for patterns from the given file, with one pattern per \ +              line. When this flag is used or multiple times or in \ +              combination with the -e/--regexp flag, then all patterns \ +              provided are searched. Empty pattern lines will match all input \ +              lines, and the newline is not counted as part of the pattern."); +        doc!(h, "files-with-matches", +             "Only show the path of each file with at least one match."); +        doc!(h, "files-without-match", +             "Only show the path of each file that contains zero matches."); +        doc!(h, "with-filename", +             "Show file name for each match.", +             "Prefix each match with the file name that contains it. This is \ +              the default when more than one file is searched."); +        doc!(h, "no-filename", +             "Never show the file name for a match.", +             "Never show the file name for a match. This is the default when \ +              one file is searched."); +        doc!(h, "heading", +             "Show matches grouped by each file.", +             "This shows the file name above clusters of matches from each \ +              file instead of showing the file name for every match. This is \ +              the default mode at a tty."); +        doc!(h, "no-heading", +             "Don't group matches by each file.", +             "Don't group matches by each file. If -H/--with-filename is \ +              enabled, then file names will be shown for every line matched. \ +              This is the default mode when not at a tty."); +        doc!(h, "hidden", +             "Search hidden files and directories.", +             "Search hidden files and directories. By default, hidden files \ +              and directories are skipped."); +        doc!(h, "ignore-file", +             "Specify additional ignore files.", +             "Specify additional ignore files for filtering file paths. \ +              Ignore files should be in the gitignore format and are matched \ +              relative to the current working directory. These ignore files \ +              have lower precedence than all other ignore files. When \ +              specifying multiple ignore files, earlier files have lower \ +              precedence than later files."); +        doc!(h, "follow", +             "Follow symbolic links."); +        doc!(h, "max-count", +             "Limit the number of matches.", +             "Limit the number of matching lines per file searched to NUM."); +        doc!(h, "maxdepth", +             "Descend at most NUM directories.", +             "Limit the depth of directory traversal to NUM levels beyond \ +              the paths given. A value of zero only searches the \ +              starting-points themselves.\n\nFor example, \ +              'rg --maxdepth 0 dir/' is a no-op because dir/ will not be \ +              descended into. 'rg --maxdepth 1 dir/' will search only the \ +              direct children of dir/."); +        doc!(h, "mmap", +             "Searching using memory maps when possible.", +             "Search using memory maps when possible. This is enabled by \ +              default when ripgrep thinks it will be faster. Note that memory \ +              map searching doesn't currently support all options, so if an \ +              incompatible option (e.g., --context) is given with --mmap, \ +              then memory maps will not be used."); +        doc!(h, "no-messages", +             "Suppress all error messages.", +             "Suppress all error messages. This is equivalent to redirecting \ +              stderr to /dev/null."); +        doc!(h, "no-mmap", +             "Never use memory maps.", +             "Never use memory maps, even when they might be faster."); +        doc!(h, "no-ignore", +             "Don't respect ignore files.", +             "Don't respect ignore files (.gitignore, .ignore, etc.). This \ +              implies --no-ignore-parent and --no-ignore-vcs."); +        doc!(h, "no-ignore-parent", +             "Don't respect ignore files in parent directories.", +             "Don't respect ignore files (.gitignore, .ignore, etc.) in \ +              parent directories."); +        doc!(h, "no-ignore-vcs", +             "Don't respect VCS ignore files", +             "Don't respect version control ignore files (.gitignore, etc.). \ +              This implies --no-ignore-parent. Note that .ignore files will \ +              continue to be respected."); +        doc!(h, "null", +             "Print NUL byte after file names", +             "Whenever a file name is printed, follow it with a NUL byte. \ +              This includes printing file names before matches, and when \ +              printing a list of matching files such as with --count, \ +              --files-with-matches and --files. This option is useful for use \ +              with xargs."); +        doc!(h, "path-separator", +             "Path separator to use when printing file paths.", +             "The path separator to use when printing file paths. This \ +              defaults to your platform's path separator, which is / on Unix \ +              and \\ on Windows. This flag is intended for overriding the \ +              default when the environment demands it (e.g., cygwin). A path \ +              separator is limited to a single byte."); +        doc!(h, "pretty", +             "Alias for --color always --heading -n."); +        doc!(h, "replace", +             "Replace matches with string given.", +             "Replace every match with the string given when printing \ +              results. Neither this flag nor any other flag will modify your \ +              files.\n\nCapture group indices (e.g., $5) and names \ +              (e.g., $foo) are supported in the replacement string.\n\n\ +              Note that the replacement by default replaces each match, and \ +              NOT the entire line. To replace the entire line, you should \ +              match the entire line."); +        doc!(h, "case-sensitive", +             "Search case sensitively.", +             "Search case sensitively. This overrides -i/--ignore-case and \ +              -S/--smart-case."); +        doc!(h, "smart-case", +             "Smart case search.", +             "Searches case insensitively if the pattern is all lowercase. \ +              Search case sensitively otherwise. This is overridden by \ +              either -s/--case-sensitive or -i/--ignore-case."); +        doc!(h, "sort-files", +             "Sort results by file path. Implies --threads=1.", +             "Sort results by file path. Note that this currently \ +              disables all parallelism and runs search in a single thread."); +        doc!(h, "threads", +             "The approximate number of threads to use.", +             "The approximate number of threads to use. A value of 0 (which \ +              is the default) causes ripgrep to choose the thread count \ +              using heuristics."); +        doc!(h, "vimgrep", +             "Show results in vim compatible format.", +             "Show results with every match on its own line, including \ +              line numbers and column numbers. With this option, a line with \ +              more than one match will be printed more than once."); + +        doc!(h, "type-add", +             "Add a new glob for a file type.", +             "Add a new glob for a particular file type. Only one glob can be \ +              added at a time. Multiple --type-add flags can be provided. \ +              Unless --type-clear is used, globs are added to any existing \ +              globs defined inside of ripgrep.\n\nNote that this MUST be \ +              passed to every invocation of ripgrep. Type settings are NOT \ +              persisted.\n\nExample: \ +              rg --type-add 'foo:*.foo' -tfoo PATTERN.\n\n\ +              --type-add can also be used to include rules from other types \ +              with the special include directive. The include directive \ +              permits specifying one or more other type names (separated by a \ +              comma) that have been defined and its rules will automatically \ +              be imported into the type specified. For example, to create a \ +              type called src that matches C++, Python and Markdown files, one \ +              can use:\n\n\ +              --type-add 'src:include:cpp,py,md'\n\n\ +              Additional glob rules can still be added to the src type by \ +              using the --type-add flag again:\n\n\ +              --type-add 'src:include:cpp,py,md' --type-add 'src:*.foo'\n\n\ +              Note that type names must consist only of Unicode letters or \ +              numbers. Punctuation characters are not allowed."); +        doc!(h, "type-clear", +             "Clear globs for given file type.", +             "Clear the file type globs previously defined for TYPE. This \ +              only clears the default type definitions that are found inside \ +              of ripgrep.\n\nNote that this MUST be passed to every \ +              invocation of ripgrep. Type settings are NOT persisted."); + +        h +    }; +} + +fn validate_number(s: String) -> Result<(), String> { +    s.parse::<usize>().map(|_| ()).map_err(|err| err.to_string()) +} diff --git a/clap/benches/06_rustup.rs b/clap/benches/06_rustup.rs new file mode 100644 index 0000000..f9ba477 --- /dev/null +++ b/clap/benches/06_rustup.rs @@ -0,0 +1,458 @@ +// Used to simulate a fairly large number of subcommands +// +// CLI used is from rustup 408ed84f0e50511ed44a405dd91365e5da588790 + +#![feature(test)] + +extern crate clap; +extern crate test; + +use clap::{App, AppSettings, Arg, Shell, SubCommand, ArgGroup}; + +use test::Bencher; + +#[bench] +fn build_app(b: &mut Bencher) { b.iter(|| build_cli()); } + +#[bench] +fn parse_clean(b: &mut Bencher) { b.iter(|| build_cli().get_matches_from(vec![""])); } + +#[bench] +fn parse_subcommands(b: &mut Bencher) { +    b.iter(|| build_cli().get_matches_from(vec!["rustup override add stable"])); +} + +pub fn build_cli() -> App<'static, 'static> { +    App::new("rustup") +        .version("0.9.0") // Simulating +        .about("The Rust toolchain installer") +        .after_help(RUSTUP_HELP) +        .setting(AppSettings::VersionlessSubcommands) +        .setting(AppSettings::DeriveDisplayOrder) +        // .setting(AppSettings::SubcommandRequiredElseHelp) +        .arg(Arg::with_name("verbose") +            .help("Enable verbose output") +            .short("v") +            .long("verbose")) +        .subcommand(SubCommand::with_name("show") +            .about("Show the active and installed toolchains") +            .after_help(SHOW_HELP)) +        .subcommand(SubCommand::with_name("install") +            .about("Update Rust toolchains") +            .after_help(TOOLCHAIN_INSTALL_HELP) +            .setting(AppSettings::Hidden) // synonym for 'toolchain install' +            .arg(Arg::with_name("toolchain") +                .required(true))) +        .subcommand(SubCommand::with_name("update") +            .about("Update Rust toolchains") +            .after_help(UPDATE_HELP) +            .arg(Arg::with_name("toolchain").required(false)) +            .arg(Arg::with_name("no-self-update") +                .help("Don't perform self update when running the `rustup` command") +                .long("no-self-update") +                .takes_value(false) +                .hidden(true))) +        .subcommand(SubCommand::with_name("default") +            .about("Set the default toolchain") +            .after_help(DEFAULT_HELP) +            .arg(Arg::with_name("toolchain").required(true))) +        .subcommand(SubCommand::with_name("toolchain") +            .about("Modify or query the installed toolchains") +            .after_help(TOOLCHAIN_HELP) +            .setting(AppSettings::VersionlessSubcommands) +            .setting(AppSettings::DeriveDisplayOrder) +            // .setting(AppSettings::SubcommandRequiredElseHelp) +            .subcommand(SubCommand::with_name("list").about("List installed toolchains")) +            .subcommand(SubCommand::with_name("install") +                .about("Install or update a given toolchain") +                .arg(Arg::with_name("toolchain").required(true))) +            .subcommand(SubCommand::with_name("uninstall") +                .about("Uninstall a toolchain") +                .arg(Arg::with_name("toolchain").required(true))) +            .subcommand(SubCommand::with_name("link") +                .about("Create a custom toolchain by symlinking to a directory") +                .arg(Arg::with_name("toolchain").required(true)) +                .arg(Arg::with_name("path").required(true))) +            .subcommand(SubCommand::with_name("update") +                .setting(AppSettings::Hidden) // synonym for 'install' +                .arg(Arg::with_name("toolchain") +                .required(true))) +            .subcommand(SubCommand::with_name("add") +                .setting(AppSettings::Hidden) // synonym for 'install' +                .arg(Arg::with_name("toolchain") +                     .required(true))) +            .subcommand(SubCommand::with_name("remove") +                .setting(AppSettings::Hidden) // synonym for 'uninstall' +                .arg(Arg::with_name("toolchain") +                     .required(true)))) +        .subcommand(SubCommand::with_name("target") +            .about("Modify a toolchain's supported targets") +            .setting(AppSettings::VersionlessSubcommands) +            .setting(AppSettings::DeriveDisplayOrder) +            // .setting(AppSettings::SubcommandRequiredElseHelp) +            .subcommand(SubCommand::with_name("list") +                .about("List installed and available targets") +                .arg(Arg::with_name("toolchain") +                    .long("toolchain") +                    .takes_value(true))) +            .subcommand(SubCommand::with_name("add") +                .about("Add a target to a Rust toolchain") +                .arg(Arg::with_name("target").required(true)) +                .arg(Arg::with_name("toolchain") +                    .long("toolchain") +                    .takes_value(true))) +            .subcommand(SubCommand::with_name("remove") +                .about("Remove a target  from a Rust toolchain") +                .arg(Arg::with_name("target").required(true)) +                .arg(Arg::with_name("toolchain") +                    .long("toolchain") +                    .takes_value(true))) +            .subcommand(SubCommand::with_name("install") +                .setting(AppSettings::Hidden) // synonym for 'add' +                .arg(Arg::with_name("target") +                    .required(true)) +                .arg(Arg::with_name("toolchain") +                    .long("toolchain") +                    .takes_value(true))) +            .subcommand(SubCommand::with_name("uninstall") +                .setting(AppSettings::Hidden) // synonym for 'remove' +                .arg(Arg::with_name("target") +                    .required(true)) +                .arg(Arg::with_name("toolchain") +                    .long("toolchain") +                    .takes_value(true)))) +        .subcommand(SubCommand::with_name("component") +            .about("Modify a toolchain's installed components") +            .setting(AppSettings::VersionlessSubcommands) +            .setting(AppSettings::DeriveDisplayOrder) +            // .setting(AppSettings::SubcommandRequiredElseHelp) +            .subcommand(SubCommand::with_name("list") +                .about("List installed and available components") +                .arg(Arg::with_name("toolchain") +                    .long("toolchain") +                    .takes_value(true))) +            .subcommand(SubCommand::with_name("add") +                .about("Add a component to a Rust toolchain") +                .arg(Arg::with_name("component").required(true)) +                .arg(Arg::with_name("toolchain") +                    .long("toolchain") +                    .takes_value(true)) +                .arg(Arg::with_name("target") +                    .long("target") +                    .takes_value(true))) +            .subcommand(SubCommand::with_name("remove") +                .about("Remove a component from a Rust toolchain") +                .arg(Arg::with_name("component").required(true)) +                .arg(Arg::with_name("toolchain") +                    .long("toolchain") +                    .takes_value(true)) +                .arg(Arg::with_name("target") +                    .long("target") +                    .takes_value(true)))) +        .subcommand(SubCommand::with_name("override") +            .about("Modify directory toolchain overrides") +            .after_help(OVERRIDE_HELP) +            .setting(AppSettings::VersionlessSubcommands) +            .setting(AppSettings::DeriveDisplayOrder) +            // .setting(AppSettings::SubcommandRequiredElseHelp) +            .subcommand(SubCommand::with_name("list").about("List directory toolchain overrides")) +            .subcommand(SubCommand::with_name("set") +                .about("Set the override toolchain for a directory") +                .arg(Arg::with_name("toolchain").required(true))) +            .subcommand(SubCommand::with_name("unset") +                .about("Remove the override toolchain for a directory") +                .after_help(OVERRIDE_UNSET_HELP) +                .arg(Arg::with_name("path") +                    .long("path") +                    .takes_value(true) +                    .help("Path to the directory")) +                .arg(Arg::with_name("nonexistent") +                    .long("nonexistent") +                    .takes_value(false) +                    .help("Remove override toolchain for all nonexistent directories"))) +            .subcommand(SubCommand::with_name("add") +                .setting(AppSettings::Hidden) // synonym for 'set' +                .arg(Arg::with_name("toolchain") +                     .required(true))) +            .subcommand(SubCommand::with_name("remove") +                .setting(AppSettings::Hidden) // synonym for 'unset' +                .about("Remove the override toolchain for a directory") +                .arg(Arg::with_name("path") +                    .long("path") +                    .takes_value(true)) +                .arg(Arg::with_name("nonexistent") +                    .long("nonexistent") +                    .takes_value(false) +                    .help("Remove override toolchain for all nonexistent directories")))) +        .subcommand(SubCommand::with_name("run") +            .about("Run a command with an environment configured for a given toolchain") +            .after_help(RUN_HELP) +            .setting(AppSettings::TrailingVarArg) +            .arg(Arg::with_name("toolchain").required(true)) +            .arg(Arg::with_name("command") +                .required(true) +                .multiple(true) +                .use_delimiter(false))) +        .subcommand(SubCommand::with_name("which") +            .about("Display which binary will be run for a given command") +            .arg(Arg::with_name("command").required(true))) +        .subcommand(SubCommand::with_name("doc") +            .about("Open the documentation for the current toolchain") +            .after_help(DOC_HELP) +            .arg(Arg::with_name("book") +                .long("book") +                .help("The Rust Programming Language book")) +            .arg(Arg::with_name("std") +                .long("std") +                .help("Standard library API documentation")) +            .group(ArgGroup::with_name("page").args(&["book", "std"]))) +        .subcommand(SubCommand::with_name("man") +            .about("View the man page for a given command") +            .arg(Arg::with_name("command").required(true)) +            .arg(Arg::with_name("toolchain") +                .long("toolchain") +                .takes_value(true))) +        .subcommand(SubCommand::with_name("self") +            .about("Modify the rustup installation") +            .setting(AppSettings::VersionlessSubcommands) +            .setting(AppSettings::DeriveDisplayOrder) +            // .setting(AppSettings::SubcommandRequiredElseHelp) +            .subcommand(SubCommand::with_name("update") +                .about("Download and install updates to rustup")) +            .subcommand(SubCommand::with_name("uninstall") +                .about("Uninstall rustup.") +                .arg(Arg::with_name("no-prompt").short("y"))) +            .subcommand(SubCommand::with_name("upgrade-data") +                .about("Upgrade the internal data format."))) +        .subcommand(SubCommand::with_name("telemetry") +            .about("rustup telemetry commands") +            .setting(AppSettings::Hidden) +            .setting(AppSettings::VersionlessSubcommands) +            .setting(AppSettings::DeriveDisplayOrder) +            // .setting(AppSettings::SubcommandRequiredElseHelp) +            .subcommand(SubCommand::with_name("enable").about("Enable rustup telemetry")) +            .subcommand(SubCommand::with_name("disable").about("Disable rustup telemetry")) +            .subcommand(SubCommand::with_name("analyze").about("Analyze stored telemetry"))) +        .subcommand(SubCommand::with_name("set") +            .about("Alter rustup settings") +            // .setting(AppSettings::SubcommandRequiredElseHelp) +            .subcommand(SubCommand::with_name("default-host") +                .about("The triple used to identify toolchains when not specified") +                .arg(Arg::with_name("host_triple").required(true)))) +        .subcommand(SubCommand::with_name("completions") +            .about("Generate completion scripts for your shell") +            .after_help(COMPLETIONS_HELP) +            .setting(AppSettings::ArgRequiredElseHelp) +            .arg(Arg::with_name("shell").possible_values(&Shell::variants()))) +} + +static RUSTUP_HELP: &'static str = r" +rustup installs The Rust Programming Language from the official +release channels, enabling you to easily switch between stable, beta, +and nightly compilers and keep them updated. It makes cross-compiling +simpler with binary builds of the standard library for common platforms. + +If you are new to Rust consider running `rustup doc --book` +to learn Rust."; + +static SHOW_HELP: &'static str = r" +Shows the name of the active toolchain and the version of `rustc`. + +If the active toolchain has installed support for additional +compilation targets, then they are listed as well. + +If there are multiple toolchains installed then all installed +toolchains are listed as well."; + +static UPDATE_HELP: &'static str = r" +With no toolchain specified, the `update` command updates each of the +installed toolchains from the official release channels, then updates +rustup itself. + +If given a toolchain argument then `update` updates that toolchain, +the same as `rustup toolchain install`. + +'toolchain' specifies a toolchain name, such as 'stable', 'nightly', +or '1.8.0'. For more information see `rustup help toolchain`."; + +static TOOLCHAIN_INSTALL_HELP: &'static str = r" +Installs a specific rust toolchain. + +The 'install' command is an alias for 'rustup update <toolchain>'. + +'toolchain' specifies a toolchain name, such as 'stable', 'nightly', +or '1.8.0'. For more information see `rustup help toolchain`."; + +static DEFAULT_HELP: &'static str = r" +Sets the default toolchain to the one specified. If the toolchain is +not already installed then it is installed first."; + +static TOOLCHAIN_HELP: &'static str = r" +Many `rustup` commands deal with *toolchains*, a single installation +of the Rust compiler. `rustup` supports multiple types of +toolchains. The most basic track the official release channels: +'stable', 'beta' and 'nightly'; but `rustup` can also install +toolchains from the official archives, for alternate host platforms, +and from local builds. + +Standard release channel toolchain names have the following form: + +    <channel>[-<date>][-<host>] + +    <channel>       = stable|beta|nightly|<version> +    <date>          = YYYY-MM-DD +    <host>          = <target-triple> + +'channel' is either a named release channel or an explicit version +number, such as '1.8.0'. Channel names can be optionally appended with +an archive date, as in 'nightly-2014-12-18', in which case the +toolchain is downloaded from the archive for that date. + +Finally, the host may be specified as a target triple. This is most +useful for installing a 32-bit compiler on a 64-bit platform, or for +installing the [MSVC-based toolchain] on Windows. For example: + +    rustup toolchain install stable-x86_64-pc-windows-msvc + +For convenience, elements of the target triple that are omitted will be +inferred, so the above could be written: + +    $ rustup default stable-msvc + +Toolchain names that don't name a channel instead can be used to name +custom toolchains with the `rustup toolchain link` command."; + +static OVERRIDE_HELP: &'static str = r" +Overrides configure rustup to use a specific toolchain when +running in a specific directory. + +Directories can be assigned their own Rust toolchain with +`rustup override`. When a directory has an override then +any time `rustc` or `cargo` is run inside that directory, +or one of its child directories, the override toolchain +will be invoked. + +To pin to a specific nightly: + +    rustup override set nightly-2014-12-18 + +Or a specific stable release: + +    rustup override set 1.0.0 + +To see the active toolchain use `rustup show`. To remove the override +and use the default toolchain again, `rustup override unset`."; + +static OVERRIDE_UNSET_HELP: &'static str = r" +If `--path` argument is present, removes the override toolchain for +the specified directory. If `--nonexistent` argument is present, removes +the override toolchain for all nonexistent directories. Otherwise, +removes the override toolchain for the current directory."; + +static RUN_HELP: &'static str = r" +Configures an environment to use the given toolchain and then runs +the specified program. The command may be any program, not just +rustc or cargo. This can be used for testing arbitrary toolchains +without setting an override. + +Commands explicitly proxied by `rustup` (such as `rustc` and `cargo`) +also have a shorthand for this available. The toolchain can be set by +using `+toolchain` as the first argument. These are equivalent: + +    cargo +nightly build + +    rustup run nightly cargo build"; + +static DOC_HELP: &'static str = r" +Opens the documentation for the currently active toolchain with the +default browser. + +By default, it opens the documentation index. Use the various flags to +open specific pieces of documentation."; + +static COMPLETIONS_HELP: &'static str = r" +One can generate a completion script for `rustup` that is compatible with +a given shell. The script is output on `stdout` allowing one to re-direct +the output to the file of their choosing. Where you place the file will +depend on which shell, and which operating system you are using. Your +particular configuration may also determine where these scripts need +to be placed. + +Here are some common set ups for the three supported shells under +Unix and similar operating systems (such as GNU/Linux). + +BASH: + +Completion files are commonly stored in `/usr/share/bash-completion/completions` + +Run the command: + +`rustup completions bash > /usr/share/bash-completion/completions/rustup.bash` + +This installs the completion script. You may have to log out and log +back in to your shell session for the changes to take affect. + +FISH: + +Fish completion files are commonly stored in +`$HOME/.config/fish/completions` + +Run the command: +`rustup completions fish > ~/.config/fish/completions/rustup.fish` + +This installs the completion script. You may have to log out and log +back in to your shell session for the changes to take affect. + +ZSH: + +ZSH completions are commonly stored in any directory listed in your +`$fpath` variable. To use these completions, you must either add the +generated script to one of those directories, or add your own +to this list. + +Adding a custom directory is often the safest best if you're unsure +of which directory to use. First create the directory, for this +example we'll create a hidden directory inside our `$HOME` directory + +`mkdir ~/.zfunc` + +Then add the following lines to your `.zshrc` just before `compinit` + +`fpath+=~/.zfunc` + +Now you can install the completions script using the following command + +`rustup completions zsh > ~/.zfunc/_rustup` + +You must then either log out and log back in, or simply run + +`exec zsh` + +For the new completions to take affect. + +CUSTOM LOCATIONS: + +Alternatively, you could save these files to the place of your choosing, +such as a custom directory inside your $HOME. Doing so will require you +to add the proper directives, such as `source`ing inside your login +script. Consult your shells documentation for how to add such directives. + +POWERSHELL: + +The powershell completion scripts require PowerShell v5.0+ (which comes +Windows 10, but can be downloaded separately for windows 7 or 8.1). + +First, check if a profile has already been set + +`PS C:\> Test-Path $profile` + +If the above command returns `False` run the following + +`PS C:\> New-Item -path $profile -type file --force` + +Now open the file provided by `$profile` (if you used the `New-Item` command +it will be `%USERPROFILE%\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1` + +Next, we either save the completions file into our profile, or into a separate file +and source it inside our profile. To save the completions into our profile simply +use";  | 
