Merge pull request #1154 from kbknapp/v3-prep

v3 Prep
This commit is contained in:
Kevin K 2018-01-25 23:15:17 -05:00 committed by GitHub
commit 7372359c9c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
93 changed files with 6821 additions and 6891 deletions

View file

@ -23,6 +23,7 @@ appveyor = { repository = "kbknapp/clap-rs" }
bitflags = "1.0" bitflags = "1.0"
unicode-width = "0.1.4" unicode-width = "0.1.4"
textwrap = "0.9.0" textwrap = "0.9.0"
ordermap = "0.3.5"
strsim = { version = "0.7.0", optional = true } strsim = { version = "0.7.0", optional = true }
ansi_term = { version = "0.10.0", optional = true } ansi_term = { version = "0.10.0", optional = true }
yaml-rust = { version = "0.3.5", optional = true } yaml-rust = { version = "0.3.5", optional = true }

19
TODO.md Normal file
View file

@ -0,0 +1,19 @@
- [ ] update-todo.sh
- [ ] src/lib.rs
-[ ] 578:@TODO @release @docs
-[ ] 580:@TODO @release @docs
-[ ] 583:@TODO @release @docs
-[ ] 592:@TODO @release @docs
-[ ] 598:@TODO @release @docs
-[ ] 608:@TODO @release @docs
-[ ] 610:@TODO @release @docs
-[ ] 614:@TODO @release @docs
-[ ] 616:@TODO @release @docs
-[ ] 619:@TODO @release @docs
-[ ] 623:@TODO @release @docs
- [ ] src/app/parser.rs
-[ ] 678:@TODO @perf: cloning all these Apps ins't great, but since it's just displaying the help
- [ ] src/app/mod.rs
-[ ] 1760:@TODO @v3-alpha @perf: should only propagate globals to subcmd we find, or for help
- [ ] src/args/arg.rs
-[ ] 3545:@TODO @p2 @docs @release: write docs

View file

@ -8,11 +8,7 @@ use clap::App;
use test::Bencher; use test::Bencher;
#[bench] #[bench]
fn build_app(b: &mut Bencher) { fn build_app(b: &mut Bencher) { b.iter(|| App::new("claptests")); }
b.iter(|| App::new("claptests"));
}
#[bench] #[bench]
fn parse_clean(b: &mut Bencher) { fn parse_clean(b: &mut Bencher) { b.iter(|| App::new("claptests").get_matches_from(vec![""])); }
b.iter(|| App::new("claptests").get_matches_from(vec![""]));
}

View file

@ -20,25 +20,18 @@ macro_rules! create_app {
} }
#[bench] #[bench]
fn build_app(b: &mut Bencher) { fn build_app(b: &mut Bencher) { b.iter(|| create_app!()); }
b.iter(|| create_app!());
}
#[bench] #[bench]
fn add_flag(b: &mut Bencher) { fn add_flag(b: &mut Bencher) {
fn build_app() -> App<'static, 'static> { fn build_app() -> App<'static, 'static> { App::new("claptests") }
App::new("claptests")
}
b.iter(|| build_app().arg(Arg::from_usage("-s, --some 'something'"))); b.iter(|| build_app().arg(Arg::from_usage("-s, --some 'something'")));
} }
#[bench] #[bench]
fn add_flag_ref(b: &mut Bencher) { fn add_flag_ref(b: &mut Bencher) {
fn build_app() -> App<'static, 'static> { fn build_app() -> App<'static, 'static> { App::new("claptests") }
App::new("claptests")
}
b.iter(|| { b.iter(|| {
let arg = Arg::from_usage("-s, --some 'something'"); let arg = Arg::from_usage("-s, --some 'something'");
@ -48,18 +41,14 @@ fn add_flag_ref(b: &mut Bencher) {
#[bench] #[bench]
fn add_opt(b: &mut Bencher) { fn add_opt(b: &mut Bencher) {
fn build_app() -> App<'static, 'static> { fn build_app() -> App<'static, 'static> { App::new("claptests") }
App::new("claptests")
}
b.iter(|| build_app().arg(Arg::from_usage("-s, --some <FILE> 'something'"))); b.iter(|| build_app().arg(Arg::from_usage("-s, --some <FILE> 'something'")));
} }
#[bench] #[bench]
fn add_opt_ref(b: &mut Bencher) { fn add_opt_ref(b: &mut Bencher) {
fn build_app() -> App<'static, 'static> { fn build_app() -> App<'static, 'static> { App::new("claptests") }
App::new("claptests")
}
b.iter(|| { b.iter(|| {
let arg = Arg::from_usage("-s, --some <FILE> 'something'"); let arg = Arg::from_usage("-s, --some <FILE> 'something'");
@ -69,18 +58,14 @@ fn add_opt_ref(b: &mut Bencher) {
#[bench] #[bench]
fn add_pos(b: &mut Bencher) { fn add_pos(b: &mut Bencher) {
fn build_app() -> App<'static, 'static> { fn build_app() -> App<'static, 'static> { App::new("claptests") }
App::new("claptests")
}
b.iter(|| build_app().arg(Arg::with_name("some"))); b.iter(|| build_app().arg(Arg::with_name("some")));
} }
#[bench] #[bench]
fn add_pos_ref(b: &mut Bencher) { fn add_pos_ref(b: &mut Bencher) {
fn build_app() -> App<'static, 'static> { fn build_app() -> App<'static, 'static> { App::new("claptests") }
App::new("claptests")
}
b.iter(|| { b.iter(|| {
let arg = Arg::with_name("some"); let arg = Arg::with_name("some");
@ -89,14 +74,10 @@ fn add_pos_ref(b: &mut Bencher) {
} }
#[bench] #[bench]
fn parse_clean(b: &mut Bencher) { fn parse_clean(b: &mut Bencher) { b.iter(|| create_app!().get_matches_from(vec![""])); }
b.iter(|| create_app!().get_matches_from(vec![""]));
}
#[bench] #[bench]
fn parse_flag(b: &mut Bencher) { fn parse_flag(b: &mut Bencher) { b.iter(|| create_app!().get_matches_from(vec!["myprog", "-f"])); }
b.iter(|| create_app!().get_matches_from(vec!["myprog", "-f"]));
}
#[bench] #[bench]
fn parse_option(b: &mut Bencher) { fn parse_option(b: &mut Bencher) {

View file

@ -4,7 +4,7 @@
extern crate clap; extern crate clap;
extern crate test; extern crate test;
use clap::{App, Arg, SubCommand, AppSettings}; use clap::{App, AppSettings, Arg, SubCommand};
use test::Bencher; use test::Bencher;
@ -43,94 +43,121 @@ macro_rules! create_app {
} }
#[bench] #[bench]
fn create_app_from_usage(b: &mut Bencher) { fn create_app_from_usage(b: &mut Bencher) { b.iter(|| create_app!()); }
b.iter(|| create_app!());
}
#[bench] #[bench]
fn create_app_builder(b: &mut Bencher) { fn create_app_builder(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
App::new("claptests") App::new("claptests")
.version("0.1") .version("0.1")
.about("tests clap library") .about("tests clap library")
.author("Kevin K. <kbknapp@gmail.com>") .author("Kevin K. <kbknapp@gmail.com>")
.arg(Arg::with_name("opt") .arg(
Arg::with_name("opt")
.help("tests options") .help("tests options")
.short("o") .short("o")
.long("option") .long("option")
.takes_value(true) .takes_value(true)
.multiple(true)) .multiple(true),
.arg(Arg::with_name("positional") )
.arg(
Arg::with_name("positional")
.help("tests positionals") .help("tests positionals")
.index(1)) .index(1),
.arg(Arg::with_name("flag") )
.short("f") .arg(
.help("tests flags") Arg::with_name("flag")
.long("flag") .short("f")
.multiple(true) .help("tests flags")
.global(true)) .long("flag")
.arg(Arg::with_name("flag2") .multiple(true)
.global(true),
)
.arg(
Arg::with_name("flag2")
.short("F") .short("F")
.help("tests flags with exclusions") .help("tests flags with exclusions")
.conflicts_with("flag") .conflicts_with("flag")
.requires("option2")) .requires("option2"),
.arg(Arg::with_name("option2") )
.arg(
Arg::with_name("option2")
.help("tests long options with exclusions") .help("tests long options with exclusions")
.conflicts_with("option") .conflicts_with("option")
.requires("positional2") .requires("positional2")
.takes_value(true) .takes_value(true)
.long("long-option-2")) .long("long-option-2"),
.arg(Arg::with_name("positional2") )
.arg(
Arg::with_name("positional2")
.index(3) .index(3)
.help("tests positionals with exclusions")) .help("tests positionals with exclusions"),
.arg(Arg::with_name("option3") )
.arg(
Arg::with_name("option3")
.short("O") .short("O")
.long("Option") .long("Option")
.takes_value(true) .takes_value(true)
.help("tests options with specific value sets") .help("tests options with specific value sets")
.possible_values(&OPT3_VALS)) .possible_values(&OPT3_VALS),
.arg(Arg::with_name("positional3") )
.arg(
Arg::with_name("positional3")
.multiple(true) .multiple(true)
.help("tests positionals with specific values") .help("tests positionals with specific values")
.index(4) .index(4)
.possible_values(&POS3_VALS)) .possible_values(&POS3_VALS),
.arg(Arg::with_name("multvals") )
.arg(
Arg::with_name("multvals")
.long("multvals") .long("multvals")
.takes_value(true) .takes_value(true)
.help("Tests mutliple values, not mult occs") .help("Tests mutliple values, not mult occs")
.value_names(&["one", "two"])) .value_names(&["one", "two"]),
.arg(Arg::with_name("multvalsmo") )
.arg(
Arg::with_name("multvalsmo")
.long("multvalsmo") .long("multvalsmo")
.takes_value(true) .takes_value(true)
.multiple(true) .multiple(true)
.help("Tests mutliple values, not mult occs") .help("Tests mutliple values, not mult occs")
.value_names(&["one", "two"])) .value_names(&["one", "two"]),
.arg(Arg::with_name("minvals") )
.arg(
Arg::with_name("minvals")
.long("minvals2") .long("minvals2")
.multiple(true) .multiple(true)
.takes_value(true) .takes_value(true)
.help("Tests 2 min vals") .help("Tests 2 min vals")
.min_values(2)) .min_values(2),
.arg(Arg::with_name("maxvals") )
.arg(
Arg::with_name("maxvals")
.long("maxvals3") .long("maxvals3")
.takes_value(true) .takes_value(true)
.multiple(true) .multiple(true)
.help("Tests 3 max vals") .help("Tests 3 max vals")
.max_values(3)) .max_values(3),
.subcommand(SubCommand::with_name("subcmd") )
.subcommand(
SubCommand::with_name("subcmd")
.about("tests subcommands") .about("tests subcommands")
.version("0.1") .version("0.1")
.author("Kevin K. <kbknapp@gmail.com>") .author("Kevin K. <kbknapp@gmail.com>")
.arg(Arg::with_name("scoption") .arg(
.short("o") Arg::with_name("scoption")
.long("option") .short("o")
.multiple(true) .long("option")
.takes_value(true) .multiple(true)
.help("tests options")) .takes_value(true)
.arg(Arg::with_name("scpositional") .help("tests options"),
.index(1) )
.help("tests positionals"))); .arg(
Arg::with_name("scpositional")
.index(1)
.help("tests positionals"),
),
);
}); });
} }
@ -170,14 +197,10 @@ fn create_app_macros(b: &mut Bencher) {
} }
#[bench] #[bench]
fn parse_clean(b: &mut Bencher) { fn parse_clean(b: &mut Bencher) { b.iter(|| create_app!().get_matches_from(vec![""])); }
b.iter(|| create_app!().get_matches_from(vec![""]));
}
#[bench] #[bench]
fn parse_flag(b: &mut Bencher) { fn parse_flag(b: &mut Bencher) { b.iter(|| create_app!().get_matches_from(vec!["myprog", "-f"])); }
b.iter(|| create_app!().get_matches_from(vec!["myprog", "-f"]));
}
#[bench] #[bench]
fn parse_option(b: &mut Bencher) { fn parse_option(b: &mut Bencher) {
@ -211,20 +234,75 @@ fn parse_sc_positional(b: &mut Bencher) {
#[bench] #[bench]
fn parse_complex1(b: &mut Bencher) { 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"])); b.iter(|| {
create_app!().get_matches_from(vec![
"myprog",
"-ff",
"-o",
"option1",
"arg1",
"-O",
"fast",
"arg2",
"--multvals",
"one",
"two",
"emacs",
])
});
} }
#[bench] #[bench]
fn parse_complex2(b: &mut Bencher) { 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"])); 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] #[bench]
fn parse_complex2_with_args_negate_scs(b: &mut Bencher) { 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"])); 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] #[bench]
fn parse_sc_complex(b: &mut Bencher) { fn parse_sc_complex(b: &mut Bencher) {
b.iter(|| create_app!().get_matches_from(vec!["myprog", "subcmd", "-f", "-o", "option1", "arg1"])); b.iter(|| {
create_app!().get_matches_from(vec!["myprog", "subcmd", "-f", "-o", "option1", "arg1"])
});
} }

View file

@ -10,7 +10,7 @@ use std::io::Cursor;
use clap::App; use clap::App;
use clap::{Arg, SubCommand}; use clap::{Arg, SubCommand};
fn build_help(app: &App) -> String { fn build_help(app: &mut App) -> String {
let mut buf = Cursor::new(Vec::with_capacity(50)); let mut buf = Cursor::new(Vec::with_capacity(50));
app.write_help(&mut buf).unwrap(); app.write_help(&mut buf).unwrap();
let content = buf.into_inner(); let content = buf.into_inner();
@ -22,12 +22,16 @@ fn app_example1<'b, 'c>() -> App<'b, 'c> {
.version("1.0") .version("1.0")
.author("Kevin K. <kbknapp@gmail.com>") .author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things") .about("Does awesome things")
.args_from_usage("-c, --config=[FILE] 'Sets a custom config file' .args_from_usage(
"-c, --config=[FILE] 'Sets a custom config file'
<output> 'Sets an optional output file' <output> 'Sets an optional output file'
-d... 'Turn debugging information on'") -d... 'Turn debugging information on'",
.subcommand(SubCommand::with_name("test") )
.about("does testing things") .subcommand(
.arg_from_usage("-l, --list 'lists test values'")) SubCommand::with_name("test")
.about("does testing things")
.arg_from_usage("-l, --list 'lists test values'"),
)
} }
fn app_example2<'b, 'c>() -> App<'b, 'c> { fn app_example2<'b, 'c>() -> App<'b, 'c> {
@ -39,21 +43,27 @@ fn app_example2<'b, 'c>() -> App<'b, 'c> {
fn app_example3<'b, 'c>() -> App<'b, 'c> { fn app_example3<'b, 'c>() -> App<'b, 'c> {
App::new("MyApp") App::new("MyApp")
.arg(Arg::with_name("debug") .arg(
.help("turn on debugging information") Arg::with_name("debug")
.short("d")) .help("turn on debugging information")
.args(&[Arg::with_name("config") .short("d"),
.help("sets the config file to use") )
.takes_value(true) .args(&[
.short("c") Arg::with_name("config")
.long("config"), .help("sets the config file to use")
Arg::with_name("input") .takes_value(true)
.help("the input file to use") .short("c")
.index(1) .long("config"),
.required(true)]) Arg::with_name("input")
.help("the input file to use")
.index(1)
.required(true),
])
.arg_from_usage("--license 'display the license file'") .arg_from_usage("--license 'display the license file'")
.args_from_usage("[output] 'Supply an output file to use' .args_from_usage(
-i, --int=[IFACE] 'Set an interface to use'") "[output] 'Supply an output file to use'
-i, --int=[IFACE] 'Set an interface to use'",
)
} }
fn app_example4<'b, 'c>() -> App<'b, 'c> { fn app_example4<'b, 'c>() -> App<'b, 'c> {
@ -61,138 +71,154 @@ fn app_example4<'b, 'c>() -> App<'b, 'c> {
.about("Parses an input file to do awesome things") .about("Parses an input file to do awesome things")
.version("1.0") .version("1.0")
.author("Kevin K. <kbknapp@gmail.com>") .author("Kevin K. <kbknapp@gmail.com>")
.arg(Arg::with_name("debug") .arg(
.help("turn on debugging information") Arg::with_name("debug")
.short("d") .help("turn on debugging information")
.long("debug")) .short("d")
.arg(Arg::with_name("config") .long("debug"),
.help("sets the config file to use") )
.short("c") .arg(
.long("config")) Arg::with_name("config")
.arg(Arg::with_name("input") .help("sets the config file to use")
.help("the input file to use") .short("c")
.index(1) .long("config"),
.required(true)) )
.arg(
Arg::with_name("input")
.help("the input file to use")
.index(1)
.required(true),
)
} }
fn app_example5<'b, 'c>() -> App<'b, 'c> { fn app_example5<'b, 'c>() -> App<'b, 'c> {
App::new("MyApp").arg(Arg::with_name("awesome") App::new("MyApp").arg(
.help("turns up the awesome") Arg::with_name("awesome")
.short("a") .help("turns up the awesome")
.long("awesome") .short("a")
.multiple(true) .long("awesome")
.requires("config") .multiple(true)
.conflicts_with("output")) .requires("config")
.conflicts_with("output"),
)
} }
fn app_example6<'b, 'c>() -> App<'b, 'c> { fn app_example6<'b, 'c>() -> App<'b, 'c> {
App::new("MyApp") App::new("MyApp")
.arg(Arg::with_name("input") .arg(
.help("the input file to use") Arg::with_name("input")
.index(1) .help("the input file to use")
.requires("config") .index(1)
.conflicts_with("output") .requires("config")
.required(true)) .conflicts_with("output")
.arg(Arg::with_name("config") .required(true),
.help("the config file to use") )
.index(2)) .arg(
Arg::with_name("config")
.help("the config file to use")
.index(2),
)
} }
fn app_example7<'b, 'c>() -> App<'b, 'c> { fn app_example7<'b, 'c>() -> App<'b, 'c> {
App::new("MyApp") App::new("MyApp")
.arg(Arg::with_name("config")) .arg(Arg::with_name("config"))
.arg(Arg::with_name("output")) .arg(Arg::with_name("output"))
.arg(Arg::with_name("input") .arg(
.help("the input file to use") Arg::with_name("input")
.takes_value(true) .help("the input file to use")
.short("i") .takes_value(true)
.long("input") .short("i")
.multiple(true) .long("input")
.required(true) .multiple(true)
.requires("config") .required(true)
.conflicts_with("output")) .requires("config")
.conflicts_with("output"),
)
} }
fn app_example8<'b, 'c>() -> App<'b, 'c> { fn app_example8<'b, 'c>() -> App<'b, 'c> {
App::new("MyApp") App::new("MyApp")
.arg(Arg::with_name("config")) .arg(Arg::with_name("config"))
.arg(Arg::with_name("output")) .arg(Arg::with_name("output"))
.arg(Arg::with_name("input") .arg(
.help("the input file to use") Arg::with_name("input")
.takes_value(true) .help("the input file to use")
.short("i") .takes_value(true)
.long("input") .short("i")
.multiple(true) .long("input")
.required(true) .multiple(true)
.requires("config") .required(true)
.conflicts_with("output")) .requires("config")
.conflicts_with("output"),
)
} }
fn app_example10<'b, 'c>() -> App<'b, 'c> { fn app_example10<'b, 'c>() -> App<'b, 'c> {
App::new("myapp") App::new("myapp").about("does awesome things").arg(
.about("does awesome things") Arg::with_name("CONFIG")
.arg(Arg::with_name("CONFIG")
.help("The config file to use (default is \"config.json\")") .help("The config file to use (default is \"config.json\")")
.short("c") .short("c")
.takes_value(true)) .takes_value(true),
)
} }
#[bench] #[bench]
fn example1(b: &mut Bencher) { fn example1(b: &mut Bencher) {
let app = app_example1(); let mut app = app_example1();
b.iter(|| build_help(&app)); b.iter(|| build_help(&mut app));
} }
#[bench] #[bench]
fn example2(b: &mut Bencher) { fn example2(b: &mut Bencher) {
let app = app_example2(); let mut app = app_example2();
b.iter(|| build_help(&app)); b.iter(|| build_help(&mut app));
} }
#[bench] #[bench]
fn example3(b: &mut Bencher) { fn example3(b: &mut Bencher) {
let app = app_example3(); let mut app = app_example3();
b.iter(|| build_help(&app)); b.iter(|| build_help(&mut app));
} }
#[bench] #[bench]
fn example4(b: &mut Bencher) { fn example4(b: &mut Bencher) {
let app = app_example4(); let mut app = app_example4();
b.iter(|| build_help(&app)); b.iter(|| build_help(&mut app));
} }
#[bench] #[bench]
fn example5(b: &mut Bencher) { fn example5(b: &mut Bencher) {
let app = app_example5(); let mut app = app_example5();
b.iter(|| build_help(&app)); b.iter(|| build_help(&mut app));
} }
#[bench] #[bench]
fn example6(b: &mut Bencher) { fn example6(b: &mut Bencher) {
let app = app_example6(); let mut app = app_example6();
b.iter(|| build_help(&app)); b.iter(|| build_help(&mut app));
} }
#[bench] #[bench]
fn example7(b: &mut Bencher) { fn example7(b: &mut Bencher) {
let app = app_example7(); let mut app = app_example7();
b.iter(|| build_help(&app)); b.iter(|| build_help(&mut app));
} }
#[bench] #[bench]
fn example8(b: &mut Bencher) { fn example8(b: &mut Bencher) {
let app = app_example8(); let mut app = app_example8();
b.iter(|| build_help(&app)); b.iter(|| build_help(&mut app));
} }
#[bench] #[bench]
fn example10(b: &mut Bencher) { fn example10(b: &mut Bencher) {
let app = app_example10(); let mut app = app_example10();
b.iter(|| build_help(&app)); b.iter(|| build_help(&mut app));
} }
#[bench] #[bench]
fn example4_template(b: &mut Bencher) { 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"); let mut 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)); b.iter(|| build_help(&mut app));
} }

View file

@ -6,9 +6,9 @@
#![feature(test)] #![feature(test)]
extern crate clap; extern crate clap;
extern crate test;
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
extern crate test;
use clap::{App, AppSettings, Arg, ArgSettings}; use clap::{App, AppSettings, Arg, ArgSettings};
@ -24,14 +24,14 @@ fn build_app_long(b: &mut Bencher) { b.iter(|| app_long()); }
#[bench] #[bench]
fn build_help_short(b: &mut Bencher) { fn build_help_short(b: &mut Bencher) {
let app = app_short(); let mut app = app_short();
b.iter(|| build_help(&app)); b.iter(|| build_help(&mut app));
} }
#[bench] #[bench]
fn build_help_long(b: &mut Bencher) { fn build_help_long(b: &mut Bencher) {
let app = app_long(); let mut app = app_long();
b.iter(|| build_help(&app)); b.iter(|| build_help(&mut app));
} }
#[bench] #[bench]
@ -40,244 +40,187 @@ fn parse_clean(b: &mut Bencher) { b.iter(|| app_short().get_matches_from(vec!["r
#[bench] #[bench]
fn parse_complex(b: &mut Bencher) { fn parse_complex(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
app_short().get_matches_from(vec!["rg", app_short().get_matches_from(vec![
"pat", "rg",
"-cFlN", "pat",
"-pqr=some", "-cFlN",
"--null", "-pqr=some",
"--no-filename", "--null",
"--no-messages", "--no-filename",
"-SH", "--no-messages",
"-C5", "-SH",
"--follow", "-C5",
"-e some"]) "--follow",
"-e some",
])
}); });
} }
#[bench] #[bench]
fn parse_lots(b: &mut Bencher) { fn parse_lots(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
app_short() app_short().get_matches_from(vec![
.get_matches_from(vec!["rg", "pat", "some", "some", "some", "some", "some", "some", "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", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", ])
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some"])
}); });
} }
@ -317,16 +260,14 @@ pub fn app_short() -> App<'static, 'static> { app(false, |k| USAGES[k].short) }
/// Build a clap application with long help strings. /// Build a clap application with long help strings.
pub fn app_long() -> App<'static, 'static> { app(true, |k| USAGES[k].long) } pub fn app_long() -> App<'static, 'static> { app(true, |k| USAGES[k].long) }
/// Build the help text of an application. /// Build the help text of an application.
fn build_help(app: &App) -> String { fn build_help(app: &mut App) -> String {
let mut buf = Cursor::new(Vec::with_capacity(50)); let mut buf = Cursor::new(Vec::with_capacity(50));
app.write_help(&mut buf).unwrap(); app.write_help(&mut buf).unwrap();
let content = buf.into_inner(); let content = buf.into_inner();
String::from_utf8(content).unwrap() String::from_utf8(content).unwrap()
} }
/// Build a clap application parameterized by usage strings. /// Build a clap application parameterized by usage strings.
/// ///
/// The function given should take a clap argument name and return a help /// The function given should take a clap argument name and return a help
@ -335,9 +276,14 @@ fn build_help(app: &App) -> String {
/// This is an intentionally stand-alone module so that it can be used easily /// This is an intentionally stand-alone module so that it can be used easily
/// in a `build.rs` script to build shell completion files. /// in a `build.rs` script to build shell completion files.
fn app<F>(next_line_help: bool, doc: F) -> App<'static, 'static> fn app<F>(next_line_help: bool, doc: F) -> App<'static, 'static>
where F: Fn(&'static str) -> &'static str where
F: Fn(&'static str) -> &'static str,
{ {
let arg = |name| Arg::with_name(name).help(doc(name)).next_line_help(next_line_help); let arg = |name| {
Arg::with_name(name)
.help(doc(name))
.next_line_help(next_line_help)
};
let flag = |name| arg(name).long(name); let flag = |name| arg(name).long(name);
App::new("ripgrep") App::new("ripgrep")
@ -773,5 +719,7 @@ lazy_static! {
} }
fn validate_number(s: String) -> Result<(), String> { fn validate_number(s: String) -> Result<(), String> {
s.parse::<usize>().map(|_| ()).map_err(|err| err.to_string()) s.parse::<usize>()
.map(|_| ())
.map_err(|err| err.to_string())
} }

View file

@ -7,7 +7,7 @@
extern crate clap; extern crate clap;
extern crate test; extern crate test;
use clap::{App, AppSettings, Arg, Shell, SubCommand, ArgGroup}; use clap::{App, AppSettings, Arg, ArgGroup, Shell, SubCommand};
use test::Bencher; use test::Bencher;

View file

@ -36,9 +36,11 @@ mod test {
err.write_to(&mut buf).unwrap(); err.write_to(&mut buf).unwrap();
let content = buf.into_inner(); let content = buf.into_inner();
let left = String::from_utf8(content).unwrap(); let left = String::from_utf8(content).unwrap();
assert_eq!(stderr, err.use_stderr()); assert_eq!(stderr, err.use_stderr(),
"Should Use STDERR failed. Should be {} but is {}", stderr, err.use_stderr());
compare(left, right) compare(left, right)
} }
pub fn compare_output2(l: App, args: &str, right1: &str, right2: &str, stderr: bool) -> bool { pub fn compare_output2(l: App, args: &str, right1: &str, right2: &str, stderr: bool) -> bool {
let mut buf = Cursor::new(Vec::with_capacity(50)); let mut buf = Cursor::new(Vec::with_capacity(50));
let res = l.get_matches_from_safe(args.split(' ').collect::<Vec<_>>()); let res = l.get_matches_from_safe(args.split(' ').collect::<Vec<_>>());

17
etc/count-tests.sh Executable file
View file

@ -0,0 +1,17 @@
#!/bin/bash
IFS=$'\n'
touch .tmp.out
echo -n "Testing"
for TEST in $(find tests/ -type f -name "*.rs" -exec basename {} .rs \;); do
echo -n "."
echo -n -e "$TEST:\t" >> .tmp.out
cargo test --test $TEST 2>&1 | grep -o -e '[0-9]* failed;' >> .tmp.out
done
echo "Done"
column -t < .tmp.out
rm .tmp.out
unset IFS

18
etc/update-todo.sh Executable file
View file

@ -0,0 +1,18 @@
#!/bin/bash
rg -h 1>/dev/null || (echo "ripgrep not found" && false)
IFS=$'\n'
mv TODO.md TODO.bak || true
touch TODO.md
for FILE in $(rg '@TODO' --ignore-file='update-todo.sh' --files-with-matches); do
echo "- [ ] $FILE" >> TODO.md
for LINE in $(rg -noe '@TODO([ @a-zA-Z-]+):?(.*)$' $FILE); do
echo " -[ ] $LINE" >> TODO.md
done;
done;
unset IFS
rm TODO.bak || true

View file

@ -3,7 +3,6 @@ extern crate clap;
use clap::{App, SubCommand}; use clap::{App, SubCommand};
fn main() { fn main() {
// This example shows how to create an application with several arguments using usage strings, which can be // This example shows how to create an application with several arguments using usage strings, which can be
// far less verbose that shown in 01b_QuickExample.rs, but is more readable. The downside is you cannot set // far less verbose that shown in 01b_QuickExample.rs, but is more readable. The downside is you cannot set
// the more advanced configuration options using this method (well...actually you can, you'll see ;) ) // the more advanced configuration options using this method (well...actually you can, you'll see ;) )
@ -33,16 +32,20 @@ fn main() {
// - A subcommand "help" (automatically generated by clap because we specified a subcommand of our own) // - A subcommand "help" (automatically generated by clap because we specified a subcommand of our own)
// + Used by "$ myapp help" (same functionality as "-h" or "--help") // + Used by "$ myapp help" (same functionality as "-h" or "--help")
let matches = App::new("MyApp") let matches = App::new("MyApp")
.version("1.0") .version("1.0")
.author("Kevin K. <kbknapp@gmail.com>") .author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things") .about("Does awesome things")
.args_from_usage("-c, --config=[FILE] 'Sets a custom config file' .args_from_usage(
"-c, --config=[FILE] 'Sets a custom config file'
<output> 'Sets an optional output file' <output> 'Sets an optional output file'
-d... 'Turn debugging information on'") -d... 'Turn debugging information on'",
.subcommand(SubCommand::with_name("test") )
.about("does testing things") .subcommand(
.arg_from_usage("-l, --list 'lists test values'")) SubCommand::with_name("test")
.get_matches(); .about("does testing things")
.arg_from_usage("-l, --list 'lists test values'"),
)
.get_matches();
// You can check the value provided by positional arguments, or option arguments // You can check the value provided by positional arguments, or option arguments
if let Some(o) = matches.value_of("output") { if let Some(o) = matches.value_of("output") {
@ -60,20 +63,19 @@ fn main() {
1 => println!("Debug mode is kind of on"), 1 => println!("Debug mode is kind of on"),
2 => println!("Debug mode is on"), 2 => println!("Debug mode is on"),
3 | _ => println!("Don't be crazy"), 3 | _ => println!("Don't be crazy"),
} }
// You can check for the existence of subcommands, and if found use their // You can check for the existence of subcommands, and if found use their
// matches just as you would the top level app // matches just as you would the top level app
if let Some(ref matches) = matches.subcommand_matches("test") { if let Some(ref matches) = matches.subcommand_matches("test") {
// "$ myapp test" was run // "$ myapp test" was run
if matches.is_present("list") { if matches.is_present("list") {
// "$ myapp test -l" was run // "$ myapp test -l" was run
println!("Printing testing lists..."); println!("Printing testing lists...");
} else { } else {
println!("Not printing testing lists..."); println!("Not printing testing lists...");
} }
} }
// Continued program logic goes here... // Continued program logic goes here...
} }

View file

@ -3,7 +3,6 @@ extern crate clap;
use clap::{App, Arg, SubCommand}; use clap::{App, Arg, SubCommand};
fn main() { fn main() {
// This method shows the traditional, and slightly more configurable way to set up arguments. This method is // This method shows the traditional, and slightly more configurable way to set up arguments. This method is
// more verbose, but allows setting more configuration options, and even supports easier dynamic generation. // more verbose, but allows setting more configuration options, and even supports easier dynamic generation.
// //
@ -35,28 +34,34 @@ fn main() {
// - A subcommand "help" (automatically generated by clap because we specified a subcommand of our own) // - A subcommand "help" (automatically generated by clap because we specified a subcommand of our own)
// + Used by "$ myapp help" (same functionality as "-h" or "--help") // + Used by "$ myapp help" (same functionality as "-h" or "--help")
let matches = App::new("MyApp") let matches = App::new("MyApp")
.version("1.0") .version("1.0")
.author("Kevin K. <kbknapp@gmail.com>") .author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things") .about("Does awesome things")
.arg(Arg::with_name("config") .arg(
.short("c") Arg::with_name("config")
.long("config") .short("c")
.value_name("FILE") .long("config")
.help("Sets a custom config file") .value_name("FILE")
.takes_value(true)) .help("Sets a custom config file")
.arg(Arg::with_name("output") .takes_value(true),
.help("Sets an optional output file") )
.index(1)) .arg(
.arg(Arg::with_name("debug") Arg::with_name("output")
.short("d") .help("Sets an optional output file")
.multiple(true) .index(1),
.help("Turn debugging information on")) )
.subcommand(SubCommand::with_name("test") .arg(
.about("does testing things") Arg::with_name("debug")
.arg(Arg::with_name("list") .short("d")
.short("l") .multiple(true)
.help("lists test values"))) .help("Turn debugging information on"),
.get_matches(); )
.subcommand(
SubCommand::with_name("test")
.about("does testing things")
.arg(Arg::with_name("list").short("l").help("lists test values")),
)
.get_matches();
// You can check the value provided by positional arguments, or option arguments // You can check the value provided by positional arguments, or option arguments
if let Some(o) = matches.value_of("output") { if let Some(o) = matches.value_of("output") {
@ -74,20 +79,19 @@ fn main() {
1 => println!("Debug mode is kind of on"), 1 => println!("Debug mode is kind of on"),
2 => println!("Debug mode is on"), 2 => println!("Debug mode is on"),
3 | _ => println!("Don't be crazy"), 3 | _ => println!("Don't be crazy"),
} }
// You can check for the existence of subcommands, and if found use their // You can check for the existence of subcommands, and if found use their
// matches just as you would the top level app // matches just as you would the top level app
if let Some(ref matches) = matches.subcommand_matches("test") { if let Some(ref matches) = matches.subcommand_matches("test") {
// "$ myapp test" was run // "$ myapp test" was run
if matches.is_present("list") { if matches.is_present("list") {
// "$ myapp test -l" was run // "$ myapp test -l" was run
println!("Printing testing lists..."); println!("Printing testing lists...");
} else { } else {
println!("Not printing testing lists..."); println!("Not printing testing lists...");
} }
} }
// Continued program logic goes here... // Continued program logic goes here...
} }

View file

@ -65,7 +65,14 @@ fn main() {
// an example, and may be somewhat contrived // an example, and may be somewhat contrived
// //
// First we check if debugging should be on or not // First we check if debugging should be on or not
println!("Debugging mode is: {}", if matches.is_present("debug") { "ON" } else { "OFF" }); println!(
"Debugging mode is: {}",
if matches.is_present("debug") {
"ON"
} else {
"OFF"
}
);
// Next we print the config file we're using, if any was defined with either -c <file> or // Next we print the config file we're using, if any was defined with either -c <file> or
// --config <file> // --config <file>

View file

@ -3,7 +3,6 @@ extern crate clap;
use clap::{App, Arg}; use clap::{App, Arg};
fn main() { fn main() {
// Once all App settings (including all arguments) have been set, you call get_matches() which // Once all App settings (including all arguments) have been set, you call get_matches() which
// parses the string provided by the user, and returns all the valid matches to the ones you // parses the string provided by the user, and returns all the valid matches to the ones you
// specified. // specified.
@ -18,22 +17,28 @@ fn main() {
// argument which is the input file we want to work with, this will be the only required // argument which is the input file we want to work with, this will be the only required
// argument. // argument.
let matches = App::new("MyApp") let matches = App::new("MyApp")
.about("Parses an input file to do awesome things") .about("Parses an input file to do awesome things")
.version("1.0") .version("1.0")
.author("Kevin K. <kbknapp@gmail.com>") .author("Kevin K. <kbknapp@gmail.com>")
.arg(Arg::with_name("debug") .arg(
.help("turn on debugging information") Arg::with_name("debug")
.short("d") .help("turn on debugging information")
.long("debug")) .short("d")
.arg(Arg::with_name("config") .long("debug"),
.help("sets the config file to use") )
.short("c") .arg(
.long("config")) Arg::with_name("config")
.arg(Arg::with_name("input") .help("sets the config file to use")
.help("the input file to use") .short("c")
.index(1) .long("config"),
.required(true)) )
.get_matches(); .arg(
Arg::with_name("input")
.help("the input file to use")
.index(1)
.required(true),
)
.get_matches();
// We can find out whether or not debugging was turned on // We can find out whether or not debugging was turned on
if matches.is_present("debug") { if matches.is_present("debug") {
@ -48,7 +53,10 @@ fn main() {
// Because "input" is required we can safely call unwrap() because had the user NOT // Because "input" is required we can safely call unwrap() because had the user NOT
// specified a value, clap would have explained the error the user, and exited. // specified a value, clap would have explained the error the user, and exited.
println!("Doing real work with file: {}", matches.value_of("input").unwrap() ); println!(
"Doing real work with file: {}",
matches.value_of("input").unwrap()
);
// Continued program logic goes here... // Continued program logic goes here...
} }

View file

@ -3,7 +3,6 @@ extern crate clap;
use clap::{App, Arg}; use clap::{App, Arg};
fn main() { fn main() {
// Of the three argument types, flags are the most simple. Flags are simple switches which can // Of the three argument types, flags are the most simple. Flags are simple switches which can
// be either "on" or "off" // be either "on" or "off"
// //

View file

@ -3,7 +3,6 @@ extern crate clap;
use clap::{App, Arg}; use clap::{App, Arg};
fn main() { fn main() {
// Positional arguments are those values after the program name which are not preceded by any // Positional arguments are those values after the program name which are not preceded by any
// identifier (such as "myapp some_file"). Positionals support many of the same options as // identifier (such as "myapp some_file"). Positionals support many of the same options as
// flags, as well as a few additional ones. // flags, as well as a few additional ones.
@ -50,7 +49,11 @@ fn main() {
// We can also get the values for those arguments // We can also get the values for those arguments
if let Some(ref in_file) = matches.value_of("input") { if let Some(ref in_file) = matches.value_of("input") {
// It's safe to call unwrap() because of the required options we set above // It's safe to call unwrap() because of the required options we set above
println!("Doing work with {} and {}", in_file, matches.value_of("config").unwrap()); println!(
"Doing work with {} and {}",
in_file,
matches.value_of("config").unwrap()
);
} }
// Continued program logic goes here... // Continued program logic goes here...
} }

View file

@ -3,7 +3,6 @@ extern crate clap;
use clap::{App, Arg}; use clap::{App, Arg};
fn main() { fn main() {
// Option arguments are those that take an additional value, such as "-c value". In clap they // Option arguments are those that take an additional value, such as "-c value". In clap they
// support three types of specification, those with short() as "-o some", or those with long() // support three types of specification, those with short() as "-o some", or those with long()
// as "--option value" or "--option=value" // as "--option value" or "--option=value"
@ -65,7 +64,10 @@ fn main() {
// NOTE: Just like with flags, if we did not specify the multiple() setting this will only // NOTE: Just like with flags, if we did not specify the multiple() setting this will only
// return 1 no matter how many times the argument was used (unless it wasn't used at all, in // return 1 no matter how many times the argument was used (unless it wasn't used at all, in
// in which case 0 is returned) // in which case 0 is returned)
println!("The \"input\" argument was used {} times", matches.occurrences_of("input")); println!(
"The \"input\" argument was used {} times",
matches.occurrences_of("input")
);
// Continued program logic goes here... // Continued program logic goes here...
} }

View file

@ -3,7 +3,6 @@ extern crate clap;
use clap::{App, Arg, SubCommand}; use clap::{App, Arg, SubCommand};
fn main() { fn main() {
// SubCommands function exactly like sub-Apps, because that's exactly what they are. Each // SubCommands function exactly like sub-Apps, because that's exactly what they are. Each
// instance of a SubCommand can have it's own version, author(s), Args, and even it's own // instance of a SubCommand can have it's own version, author(s), Args, and even it's own
// subcommands. // subcommands.
@ -49,8 +48,8 @@ fn main() {
// You can also match on a subcommand's name // You can also match on a subcommand's name
match matches.subcommand_name() { match matches.subcommand_name() {
Some("add") => println!("'myapp add' was used"), Some("add") => println!("'myapp add' was used"),
None => println!("No subcommand was used"), None => println!("No subcommand was used"),
_ => println!("Some other subcommand was used"), _ => println!("Some other subcommand was used"),
} }
// Continued program logic goes here... // Continued program logic goes here...

View file

@ -12,22 +12,25 @@ fn main() {
// //
// For this example, assume you want one positional argument of either "fast" or "slow" // For this example, assume you want one positional argument of either "fast" or "slow"
// i.e. the only possible ways to run the program are "myprog fast" or "myprog slow" // i.e. the only possible ways to run the program are "myprog fast" or "myprog slow"
let matches = App::new("myapp").about("does awesome things") let matches = App::new("myapp")
.arg(Arg::with_name("MODE") .about("does awesome things")
.help("What mode to run the program in") .arg(
.index(1) Arg::with_name("MODE")
.possible_values(&["fast", "slow"]) .help("What mode to run the program in")
.required(true)) .index(1)
.get_matches(); .possible_values(&["fast", "slow"])
.required(true),
)
.get_matches();
// Note, it's safe to call unwrap() because the arg is required // Note, it's safe to call unwrap() because the arg is required
match matches.value_of("MODE").unwrap() { match matches.value_of("MODE").unwrap() {
"fast" => { "fast" => {
// Do fast things... // Do fast things...
}, }
"slow" => { "slow" => {
// Do slow things... // Do slow things...
}, }
_ => unreachable!() _ => unreachable!(),
} }
} }

View file

@ -55,12 +55,11 @@ fn main() {
let t = value_t!(m.value_of("foo"), Foo).unwrap_or_else(|e| e.exit()); let t = value_t!(m.value_of("foo"), Foo).unwrap_or_else(|e| e.exit());
let t2 = value_t!(m.value_of("oof"), Oof).unwrap_or_else(|e| e.exit()); let t2 = value_t!(m.value_of("oof"), Oof).unwrap_or_else(|e| e.exit());
// Now we can use our enum like normal. // Now we can use our enum like normal.
match t { match t {
Foo::Bar => println!("Found a Bar"), Foo::Bar => println!("Found a Bar"),
Foo::Baz => println!("Found a Baz"), Foo::Baz => println!("Found a Baz"),
Foo::Qux => println!("Found a Qux") Foo::Qux => println!("Found a Qux"),
} }
// Since our Oof derives Debug, we can do this: // Since our Oof derives Debug, we can do this:

View file

@ -15,7 +15,7 @@ enum Vals {
Foo, Foo,
Bar, Bar,
Baz, Baz,
Qux Qux,
} }
// Implement the trait // Implement the trait
@ -28,7 +28,7 @@ impl FromStr for Vals {
"Bar" => Ok(Vals::Bar), "Bar" => Ok(Vals::Bar),
"Baz" => Ok(Vals::Baz), "Baz" => Ok(Vals::Baz),
"Qux" => Ok(Vals::Qux), "Qux" => Ok(Vals::Qux),
_ => Err("no match") _ => Err("no match"),
} }
} }
} }
@ -49,6 +49,6 @@ fn main() {
Vals::Foo => println!("Found a Foo"), Vals::Foo => println!("Found a Foo"),
Vals::Bar => println!("Found a Bar"), Vals::Bar => println!("Found a Bar"),
Vals::Baz => println!("Found a Baz"), Vals::Baz => println!("Found a Baz"),
Vals::Qux => println!("Found a Qux") Vals::Qux => println!("Found a Qux"),
} }
} }

View file

@ -20,7 +20,6 @@
/// of the three numbers. So you create three flags `--major`, `--minor`, and `--patch`. All of /// of the three numbers. So you create three flags `--major`, `--minor`, and `--patch`. All of
/// these arguments shouldn't be used at one time but you want to specify that *at least one* of /// these arguments shouldn't be used at one time but you want to specify that *at least one* of
/// them is used. For this, you can create a group. /// them is used. For this, you can create a group.
extern crate clap; extern crate clap;
use clap::{App, Arg, ArgGroup}; use clap::{App, Arg, ArgGroup};
@ -61,14 +60,16 @@ fn main() {
format!("{}", ver) format!("{}", ver)
} else { } else {
// Increment the one requested (in a real program, we'd reset the lower numbers) // Increment the one requested (in a real program, we'd reset the lower numbers)
let (maj, min, pat) = (matches.is_present("major"), let (maj, min, pat) = (
matches.is_present("minor"), matches.is_present("major"),
matches.is_present("patch")); matches.is_present("minor"),
matches.is_present("patch"),
);
match (maj, min, pat) { match (maj, min, pat) {
(true, _, _) => major += 1, (true, _, _) => major += 1,
(_, true, _) => minor += 1, (_, true, _) => minor += 1,
(_, _, true) => patch += 1, (_, _, true) => patch += 1,
_ => unreachable!(), _ => unreachable!(),
}; };
format!("{}.{}.{}", major, minor, patch) format!("{}.{}.{}", major, minor, patch)
}; };
@ -77,11 +78,13 @@ fn main() {
// Check for usage of -c // Check for usage of -c
if matches.is_present("config") { if matches.is_present("config") {
let input = matches.value_of("INPUT_FILE").unwrap_or(matches.value_of("SPEC_IN").unwrap()); let input = matches
println!("Doing work using input {} and config {}", .value_of("INPUT_FILE")
input, .unwrap_or(matches.value_of("SPEC_IN").unwrap());
matches.value_of("config").unwrap()); println!(
"Doing work using input {} and config {}",
input,
matches.value_of("config").unwrap()
);
} }
} }

View file

@ -36,6 +36,6 @@ fn main() {
match matches.subcommand() { match matches.subcommand() {
("test", _) => println!("The 'test' subcommand was used"), ("test", _) => println!("The 'test' subcommand was used"),
_ => unreachable!() _ => unreachable!(),
} }
} }

View file

@ -11,7 +11,6 @@
// [dependencies] // [dependencies]
// clap = { features = ["yaml"] } // clap = { features = ["yaml"] }
// Using yaml requires calling a clap macro `load_yaml!()` so we must use the '#[macro_use]' // Using yaml requires calling a clap macro `load_yaml!()` so we must use the '#[macro_use]'
// directive // directive
#[macro_use] #[macro_use]
@ -38,7 +37,7 @@ fn main() {
match mode { match mode {
"vi" => println!("You are using vi"), "vi" => println!("You are using vi"),
"emacs" => println!("You are using emacs..."), "emacs" => println!("You are using emacs..."),
_ => unreachable!() _ => unreachable!(),
} }
} else { } else {
println!("--mode <MODE> wasn't used..."); println!("--mode <MODE> wasn't used...");

View file

@ -5,7 +5,6 @@ extern crate clap;
// $crate:: internally // $crate:: internally
fn main() { fn main() {
// Validation example testing that a file exists // Validation example testing that a file exists
let file_exists = |path| { let file_exists = |path| {
if std::fs::metadata(path).is_ok() { if std::fs::metadata(path).is_ok() {

View file

@ -41,31 +41,36 @@
extern crate clap; extern crate clap;
use clap::{App, Arg, SubCommand, AppSettings}; use clap::{App, AppSettings, Arg, SubCommand};
fn main() { fn main() {
let matches = App::new("git") let matches = App::new("git")
.about("A fictional versioning CLI") .about("A fictional versioning CLI")
.version("1.0") .version("1.0")
.author("Me") .author("Me")
.subcommand(SubCommand::with_name("clone") .subcommand(
.about("clones repos") SubCommand::with_name("clone").about("clones repos").arg(
.arg(Arg::with_name("repo") Arg::with_name("repo")
.help("The repo to clone") .help("The repo to clone")
.required(true))) .required(true),
.subcommand(SubCommand::with_name("push") ),
.about("pushes things") )
.setting(AppSettings::SubcommandRequiredElseHelp) .subcommand(
.subcommand(SubCommand::with_name("remote") // Subcommands can have thier own subcommands, SubCommand::with_name("push")
.about("pushes things")
.setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand(
SubCommand::with_name("remote") // Subcommands can have thier own subcommands,
// which in turn have their own subcommands // which in turn have their own subcommands
.about("pushes remote things") .about("pushes remote things")
.arg(Arg::with_name("repo") .arg(Arg::with_name("repo")
.required(true) .required(true)
.help("The remote repo to push things to"))) .help("The remote repo to push things to")),
.subcommand(SubCommand::with_name("local") )
.about("pushes local things"))) .subcommand(SubCommand::with_name("local").about("pushes local things")),
.subcommand(SubCommand::with_name("add") )
.subcommand(
SubCommand::with_name("add")
.about("adds things") .about("adds things")
.author("Someone Else") // Subcommands can list different authors .author("Someone Else") // Subcommands can list different authors
.version("v2.0 (I'm versioned differently") // or different version from their parents .version("v2.0 (I'm versioned differently") // or different version from their parents
@ -74,7 +79,8 @@ fn main() {
.long("stuff") .long("stuff")
.help("Stuff to add") .help("Stuff to add")
.takes_value(true) .takes_value(true)
.multiple(true))) .multiple(true)),
)
.get_matches(); .get_matches();
// At this point, the matches we have point to git. Keep this in mind... // At this point, the matches we have point to git. Keep this in mind...
@ -101,8 +107,8 @@ fn main() {
Some("clone") => println!("'git clone' was used"), Some("clone") => println!("'git clone' was used"),
Some("push") => println!("'git push' was used"), Some("push") => println!("'git push' was used"),
Some("add") => println!("'git add' was used"), Some("add") => println!("'git add' was used"),
None => println!("No subcommand was used"), None => println!("No subcommand was used"),
_ => unreachable!(), // Assuming you've listed all direct children above, this is unreachable _ => unreachable!(), // Assuming you've listed all direct children above, this is unreachable
} }
// You could get the independent subcommand matches, although this is less common // You could get the independent subcommand matches, although this is less common
@ -114,29 +120,36 @@ fn main() {
// The most common way to handle subcommands is via a combined approach using // The most common way to handle subcommands is via a combined approach using
// `ArgMatches::subcommand` which returns a tuple of both the name and matches // `ArgMatches::subcommand` which returns a tuple of both the name and matches
match matches.subcommand() { match matches.subcommand() {
("clone", Some(clone_matches)) =>{ ("clone", Some(clone_matches)) => {
// Now we have a reference to clone's matches // Now we have a reference to clone's matches
println!("Cloning {}", clone_matches.value_of("repo").unwrap()); println!("Cloning {}", clone_matches.value_of("repo").unwrap());
}, }
("push", Some(push_matches)) =>{ ("push", Some(push_matches)) => {
// Now we have a reference to push's matches // Now we have a reference to push's matches
match push_matches.subcommand() { match push_matches.subcommand() {
("remote", Some(remote_matches)) =>{ ("remote", Some(remote_matches)) => {
// Now we have a reference to remote's matches // Now we have a reference to remote's matches
println!("Pushing to {}", remote_matches.value_of("repo").unwrap()); println!("Pushing to {}", remote_matches.value_of("repo").unwrap());
}, }
("local", Some(_)) =>{ ("local", Some(_)) => {
println!("'git push local' was used"); println!("'git push local' was used");
}, }
_ => unreachable!(), _ => unreachable!(),
} }
}, }
("add", Some(add_matches)) =>{ ("add", Some(add_matches)) => {
// Now we have a reference to add's matches // Now we have a reference to add's matches
println!("Adding {}", add_matches.values_of("stuff").unwrap().collect::<Vec<_>>().join(", ")); println!(
}, "Adding {}",
("", None) => println!("No subcommand was used"), // If no subcommand was usd it'll match the tuple ("", None) add_matches
_ => unreachable!(), // If all subcommands are defined above, anything else is unreachabe!() .values_of("stuff")
.unwrap()
.collect::<Vec<_>>()
.join(", ")
);
}
("", None) => println!("No subcommand was used"), // If no subcommand was usd it'll match the tuple ("", None)
_ => unreachable!(), // If all subcommands are defined above, anything else is unreachabe!()
} }
// Continued program logic goes here... // Continued program logic goes here...

View file

@ -3,19 +3,21 @@ extern crate clap;
use clap::{App, Arg, SubCommand}; use clap::{App, Arg, SubCommand};
fn main() { fn main() {
let matches = App::new("MyApp") let matches = App::new("MyApp")
.subcommand(SubCommand::with_name("ls") .subcommand(
.aliases(&["list", "dir"]) SubCommand::with_name("ls")
.about("Adds files to myapp") .aliases(&["list", "dir"])
.version("0.1") .about("Adds files to myapp")
.author("Kevin K.") .version("0.1")
.arg(Arg::with_name("input") .author("Kevin K.")
.help("the file to add") .arg(
.index(1) Arg::with_name("input")
.required(true)) .help("the file to add")
) .index(1)
.get_matches(); .required(true),
),
)
.get_matches();
// You can check if a subcommand was used like normal // You can check if a subcommand was used like normal
if matches.is_present("add") { if matches.is_present("add") {
@ -31,8 +33,8 @@ fn main() {
// You can also match on a subcommand's name // You can also match on a subcommand's name
match matches.subcommand_name() { match matches.subcommand_name() {
Some("add") => println!("'myapp add' was used"), Some("add") => println!("'myapp add' was used"),
None => println!("No subcommand was used"), None => println!("No subcommand was used"),
_ => println!("Some other subcommand was used"), _ => println!("Some other subcommand was used"),
} }
// Continued program logic goes here... // Continued program logic goes here...

View file

@ -4,22 +4,20 @@ use clap::{App, Arg};
/// myprog -f -p=bob -- sloppy slop slop /// myprog -f -p=bob -- sloppy slop slop
fn main() { fn main() {
let matches = App::new("myprog") let matches = App::new("myprog")
.arg(Arg::with_name("eff") .arg(Arg::with_name("eff").short("f"))
.short("f")) .arg(Arg::with_name("pea").short("p").takes_value(true))
.arg(Arg::with_name("pea") .arg(Arg::with_name("slop").multiple(true).last(true))
.short("p")
.takes_value(true))
.arg(Arg::with_name("slop")
.multiple(true)
.last(true))
.get_matches(); .get_matches();
println!("-f used: {:?}", matches.is_present("eff")); println!("-f used: {:?}", matches.is_present("eff"));
println!("-p's value: {:?}", matches.value_of("pea")); println!("-p's value: {:?}", matches.value_of("pea"));
println!("'slops' values: {:?}", matches.values_of("slop").map(|vals| vals.collect::<Vec<_>>())); println!(
"'slops' values: {:?}",
matches
.values_of("slop")
.map(|vals| vals.collect::<Vec<_>>())
);
// Continued program logic goes here... // Continued program logic goes here...
} }

View file

@ -1,3 +1,4 @@
@update-contributors: @update-contributors:
echo 'Removing old CONTRIBUTORS.md' echo 'Removing old CONTRIBUTORS.md'
mv CONTRIBUTORS.md CONTRIBUTORS.md.bak mv CONTRIBUTORS.md CONTRIBUTORS.md.bak
@ -11,11 +12,11 @@
echo "This list was generated by [mgechev/github-contributors-list](https://github.com/mgechev/github-contributors-list)" >> CONTRIBUTORS.md echo "This list was generated by [mgechev/github-contributors-list](https://github.com/mgechev/github-contributors-list)" >> CONTRIBUTORS.md
rm CONTRIBUTORS.md.bak rm CONTRIBUTORS.md.bak
run-test TEST: run-test TESTG TEST="":
cargo test --test {{TEST}} cargo test --test {{TESTG}} -- {{TEST}}
debug TEST: debug TESTG TEST="":
cargo test --test {{TEST}} --features debug cargo test --test {{TESTG}} --features debug -- {{TEST}}
run-tests: run-tests:
cargo test --features "yaml unstable" cargo test --features "yaml unstable"
@ -37,3 +38,24 @@ clean:
find . -type f -name "*.orig" -exec rm {} \; find . -type f -name "*.orig" -exec rm {} \;
find . -type f -name "*.bk" -exec rm {} \; find . -type f -name "*.bk" -exec rm {} \;
find . -type f -name ".*~" -exec rm {} \; find . -type f -name ".*~" -exec rm {} \;
top-errors NUM="95":
@cargo check 2>&1 | head -n {{NUM}}
count-errors:
@cargo check 2>&1 | grep -e '^error' | wc -l
find-errors:
@cargo check 2>&1 | grep --only-matching -e '-->[^:]*' | sort | uniq -c | sort -nr
count-warnings:
@cargo check 2>&1 | grep -e '^warning' | wc -l
find-warnings:
@cargo check 2>&1 | grep -A1 -e 'warning' | grep --only-matching -e '-->[^:]*' | sort | uniq -c | sort -nr
@update-todo:
./etc/update-todo.sh
@count-failures:
./etc/count-tests.sh

View file

@ -1,4 +1,2 @@
format_strings = false format_strings = false
chain_overflow_last = false
same_line_if_else = true
fn_single_line = true fn_single_line = true

View file

@ -2,17 +2,16 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::cmp; use std::cmp;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fmt::Display;
use std::io::{self, Cursor, Read, Write}; use std::io::{self, Cursor, Read, Write};
use std::usize; use std::usize;
// Internal // Internal
use app::{App, AppSettings}; use app::{App, AppSettings};
use app::parser::Parser; use app::parser::Parser;
use args::{AnyArg, ArgSettings, DispOrder}; use args::{Arg, ArgSettings};
use errors::{Error, Result as ClapResult}; use errors::{Error, Result as ClapResult};
use fmt::{Colorizer, ColorizerOption, Format}; use fmt::{Colorizer, ColorizerOption, Format};
use app::usage; use app::usage::Usage;
use map::VecMap; use map::VecMap;
use INTERNAL_ERROR_MSG; use INTERNAL_ERROR_MSG;
@ -31,29 +30,16 @@ fn str_width(s: &str) -> usize { UnicodeWidthStr::width(s) }
const TAB: &'static str = " "; const TAB: &'static str = " ";
// These are just convenient traits to make the code easier to read. // trait ArgWithOrder<'b, 'c>: Display + DispOrder {
trait ArgWithDisplay<'b, 'c>: AnyArg<'b, 'c> + Display {} // fn as_base(&self) -> &Arg<'b, 'c>;
impl<'b, 'c, T> ArgWithDisplay<'b, 'c> for T // }
where // impl<'b, 'c, T> ArgWithOrder<'b, 'c> for T
T: AnyArg<'b, 'c> + Display, // where
{ // T: Display + DispOrder,
} // {
// fn as_base(&self) -> &Arg<'b, 'c> { self }
trait ArgWithOrder<'b, 'c>: ArgWithDisplay<'b, 'c> + DispOrder { // }
fn as_base(&self) -> &ArgWithDisplay<'b, 'c>; // fn as_arg_trait<'w, 'b, T: ArgWithOrder<'w, 'b>>(x: &T) -> &ArgWithOrder<'w, 'b> { x }
}
impl<'b, 'c, T> ArgWithOrder<'b, 'c> for T
where
T: ArgWithDisplay<'b, 'c> + DispOrder,
{
fn as_base(&self) -> &ArgWithDisplay<'b, 'c> { self }
}
fn as_arg_trait<'a, 'b, T: ArgWithOrder<'a, 'b>>(x: &T) -> &ArgWithOrder<'a, 'b> { x }
impl<'b, 'c> DispOrder for App<'b, 'c> {
fn disp_ord(&self) -> usize { 999 }
}
macro_rules! color { macro_rules! color {
($_self:ident, $s:expr, $c:ident) => { ($_self:ident, $s:expr, $c:ident) => {
@ -75,8 +61,8 @@ macro_rules! color {
/// `clap` Help Writer. /// `clap` Help Writer.
/// ///
/// Wraps a writer stream providing different methods to generate help for `clap` objects. /// Wraps a writer stream providing different methods to generate help for `clap` objects.
pub struct Help<'a> { pub struct Help<'w> {
writer: &'a mut Write, writer: &'w mut Write,
next_line_help: bool, next_line_help: bool,
hide_pv: bool, hide_pv: bool,
term_w: usize, term_w: usize,
@ -88,11 +74,11 @@ pub struct Help<'a> {
} }
// Public Functions // Public Functions
impl<'a> Help<'a> { impl<'w> Help<'w> {
/// Create a new `Help` instance. /// Create a new `Help` instance.
#[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))] #[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
pub fn new( pub fn new(
w: &'a mut Write, w: &'w mut Write,
next_line_help: bool, next_line_help: bool,
hide_pv: bool, hide_pv: bool,
color: bool, color: bool,
@ -128,16 +114,9 @@ impl<'a> Help<'a> {
} }
} }
/// Reads help settings from an App
/// and write its help to the wrapped stream.
pub fn write_app_help(w: &'a mut Write, app: &App, use_long: bool) -> ClapResult<()> {
debugln!("Help::write_app_help;");
Self::write_parser_help(w, &app.p, use_long)
}
/// Reads help settings from a Parser /// Reads help settings from a Parser
/// and write its help to the wrapped stream. /// and write its help to the wrapped stream.
pub fn write_parser_help(w: &'a mut Write, parser: &Parser, use_long: bool) -> ClapResult<()> { pub fn write_parser_help(w: &'w mut Write, parser: &Parser, use_long: bool) -> ClapResult<()> {
debugln!("Help::write_parser_help;"); debugln!("Help::write_parser_help;");
Self::_write_parser_help(w, parser, false, use_long) Self::_write_parser_help(w, parser, false, use_long)
} }
@ -145,14 +124,14 @@ impl<'a> Help<'a> {
/// Reads help settings from a Parser /// Reads help settings from a Parser
/// and write its help to the wrapped stream which will be stderr. This method prevents /// and write its help to the wrapped stream which will be stderr. This method prevents
/// formatting when required. /// formatting when required.
pub fn write_parser_help_to_stderr(w: &'a mut Write, parser: &Parser) -> ClapResult<()> { pub fn write_parser_help_to_stderr(w: &'w mut Write, parser: &Parser) -> ClapResult<()> {
debugln!("Help::write_parser_help;"); debugln!("Help::write_parser_help;");
Self::_write_parser_help(w, parser, true, false) Self::_write_parser_help(w, parser, true, false)
} }
#[doc(hidden)] #[doc(hidden)]
pub fn _write_parser_help( pub fn _write_parser_help(
w: &'a mut Write, w: &'w mut Write,
parser: &Parser, parser: &Parser,
stderr: bool, stderr: bool,
use_long: bool, use_long: bool,
@ -163,7 +142,7 @@ impl<'a> Help<'a> {
let color = parser.is_set(AppSettings::ColoredHelp); let color = parser.is_set(AppSettings::ColoredHelp);
let cizer = Colorizer::new(ColorizerOption { let cizer = Colorizer::new(ColorizerOption {
use_stderr: stderr, use_stderr: stderr,
when: parser.color(), when: parser.app.color(),
}); });
Self::new( Self::new(
w, w,
@ -171,8 +150,8 @@ impl<'a> Help<'a> {
hide_v, hide_v,
color, color,
cizer, cizer,
parser.meta.term_w, parser.app.term_w,
parser.meta.max_w, parser.app.max_w,
use_long, use_long,
).write_help(parser) ).write_help(parser)
} }
@ -180,9 +159,9 @@ impl<'a> Help<'a> {
/// Writes the parser help to the wrapped stream. /// Writes the parser help to the wrapped stream.
pub fn write_help(&mut self, parser: &Parser) -> ClapResult<()> { pub fn write_help(&mut self, parser: &Parser) -> ClapResult<()> {
debugln!("Help::write_help;"); debugln!("Help::write_help;");
if let Some(h) = parser.meta.help_str { if let Some(h) = parser.app.help_str {
write!(self.writer, "{}", h).map_err(Error::from)?; write!(self.writer, "{}", h).map_err(Error::from)?;
} else if let Some(tmpl) = parser.meta.template { } else if let Some(tmpl) = parser.app.template {
self.write_templated_help(parser, tmpl)?; self.write_templated_help(parser, tmpl)?;
} else { } else {
self.write_default_help(parser)?; self.write_default_help(parser)?;
@ -191,12 +170,13 @@ impl<'a> Help<'a> {
} }
} }
// Methods to write AnyArg help. // Methods to write Arg help.
impl<'a> Help<'a> { impl<'w> Help<'w> {
/// Writes help for each argument in the order they were declared to the wrapped stream. /// Writes help for each argument in the order they were declared to the wrapped stream.
fn write_args_unsorted<'b: 'd, 'c: 'd, 'd, I: 'd>(&mut self, args: I) -> io::Result<()> fn write_args_unsorted<'a, 'b, I>(&mut self, args: I) -> io::Result<()>
where where
I: Iterator<Item = &'d ArgWithOrder<'b, 'c>>, 'a: 'b,
I: Iterator<Item = &'b Arg<'a, 'b>>,
{ {
debugln!("Help::write_args_unsorted;"); debugln!("Help::write_args_unsorted;");
// The shortest an arg can legally be is 2 (i.e. '-x') // The shortest an arg can legally be is 2 (i.e. '-x')
@ -217,15 +197,16 @@ impl<'a> Help<'a> {
} else { } else {
self.writer.write_all(b"\n")?; self.writer.write_all(b"\n")?;
} }
self.write_arg(arg.as_base())?; self.write_arg(arg)?;
} }
Ok(()) Ok(())
} }
/// Sorts arguments by length and display order and write their help to the wrapped stream. /// Sorts arguments by length and display order and write their help to the wrapped stream.
fn write_args<'b: 'd, 'c: 'd, 'd, I: 'd>(&mut self, args: I) -> io::Result<()> fn write_args<'a, 'b, I>(&mut self, args: I) -> io::Result<()>
where where
I: Iterator<Item = &'d ArgWithOrder<'b, 'c>>, 'a: 'b,
I: Iterator<Item = &'b Arg<'a, 'b>>,
{ {
debugln!("Help::write_args;"); debugln!("Help::write_args;");
// The shortest an arg can legally be is 2 (i.e. '-x') // The shortest an arg can legally be is 2 (i.e. '-x')
@ -233,8 +214,8 @@ impl<'a> Help<'a> {
let mut ord_m = VecMap::new(); let mut ord_m = VecMap::new();
// Determine the longest // Determine the longest
for arg in args.filter(|arg| { for arg in args.filter(|arg| {
// If it's NextLineHelp, but we don't care to compute how long because it may be // If it's NextLineHelp we don't care to compute how long it is because it may be
// NextLineHelp on purpose *because* it's so long and would throw off all other // NextLineHelp on purpose simply *because* it's so long and would throw off all other
// args alignment // args alignment
!arg.is_set(ArgSettings::Hidden) || arg.is_set(ArgSettings::NextLineHelp) !arg.is_set(ArgSettings::Hidden) || arg.is_set(ArgSettings::NextLineHelp)
}) { }) {
@ -243,8 +224,8 @@ impl<'a> Help<'a> {
self.longest = cmp::max(self.longest, str_width(arg.to_string().as_str())); self.longest = cmp::max(self.longest, str_width(arg.to_string().as_str()));
debugln!("Help::write_args: New Longest...{}", self.longest); debugln!("Help::write_args: New Longest...{}", self.longest);
} }
let btm = ord_m.entry(arg.disp_ord()).or_insert(BTreeMap::new()); let btm = ord_m.entry(arg.disp_ord).or_insert(BTreeMap::new());
btm.insert(arg.name(), arg); btm.insert(arg.name, arg);
} }
let mut first = true; let mut first = true;
for btm in ord_m.values() { for btm in ord_m.values() {
@ -254,14 +235,14 @@ impl<'a> Help<'a> {
} else { } else {
self.writer.write_all(b"\n")?; self.writer.write_all(b"\n")?;
} }
self.write_arg(arg.as_base())?; self.write_arg(arg)?;
} }
} }
Ok(()) Ok(())
} }
/// Writes help for an argument to the wrapped stream. /// Writes help for an argument to the wrapped stream.
fn write_arg<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>) -> io::Result<()> { fn write_arg<'b, 'c>(&mut self, arg: &Arg<'b, 'c>) -> io::Result<()> {
debugln!("Help::write_arg;"); debugln!("Help::write_arg;");
self.short(arg)?; self.short(arg)?;
self.long(arg)?; self.long(arg)?;
@ -271,10 +252,10 @@ impl<'a> Help<'a> {
} }
/// Writes argument's short command to the wrapped stream. /// Writes argument's short command to the wrapped stream.
fn short<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>) -> io::Result<()> { fn short<'b, 'c>(&mut self, arg: &Arg<'b, 'c>) -> io::Result<()> {
debugln!("Help::short;"); debugln!("Help::short;");
write!(self.writer, "{}", TAB)?; write!(self.writer, "{}", TAB)?;
if let Some(s) = arg.short() { if let Some(s) = arg.short {
color!(self, "-{}", s, good) color!(self, "-{}", s, good)
} else if arg.has_switch() { } else if arg.has_switch() {
write!(self.writer, "{}", TAB) write!(self.writer, "{}", TAB)
@ -284,14 +265,14 @@ impl<'a> Help<'a> {
} }
/// Writes argument's long command to the wrapped stream. /// Writes argument's long command to the wrapped stream.
fn long<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>) -> io::Result<()> { fn long<'b, 'c>(&mut self, arg: &Arg<'b, 'c>) -> io::Result<()> {
debugln!("Help::long;"); debugln!("Help::long;");
if !arg.has_switch() { if !arg.has_switch() {
return Ok(()); return Ok(());
} }
if arg.takes_value() { if arg.is_set(ArgSettings::TakesValue) {
if let Some(l) = arg.long() { if let Some(l) = arg.long {
if arg.short().is_some() { if arg.short.is_some() {
write!(self.writer, ", ")?; write!(self.writer, ", ")?;
} }
color!(self, "--{}", l, good)? color!(self, "--{}", l, good)?
@ -303,8 +284,8 @@ impl<'a> Help<'a> {
" " " "
}; };
write!(self.writer, "{}", sep)?; write!(self.writer, "{}", sep)?;
} else if let Some(l) = arg.long() { } else if let Some(l) = arg.long {
if arg.short().is_some() { if arg.short.is_some() {
write!(self.writer, ", ")?; write!(self.writer, ", ")?;
} }
color!(self, "--{}", l, good)?; color!(self, "--{}", l, good)?;
@ -313,15 +294,15 @@ impl<'a> Help<'a> {
} }
/// Writes argument's possible values to the wrapped stream. /// Writes argument's possible values to the wrapped stream.
fn val<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>) -> Result<String, io::Error> { fn val<'b, 'c>(&mut self, arg: &Arg<'b, 'c>) -> Result<String, io::Error> {
debugln!("Help::val: arg={}", arg); debugln!("Help::val: arg={}", arg.name);
if arg.takes_value() { if arg.is_set(ArgSettings::TakesValue) {
let delim = if arg.is_set(ArgSettings::RequireDelimiter) { let delim = if arg.is_set(ArgSettings::RequireDelimiter) {
arg.val_delim().expect(INTERNAL_ERROR_MSG) arg.val_delim.expect(INTERNAL_ERROR_MSG)
} else { } else {
' ' ' '
}; };
if let Some(vec) = arg.val_names() { if let Some(ref vec) = arg.val_names {
let mut it = vec.iter().peekable(); let mut it = vec.iter().peekable();
while let Some((_, val)) = it.next() { while let Some((_, val)) = it.next() {
color!(self, "<{}>", val, good)?; color!(self, "<{}>", val, good)?;
@ -333,10 +314,10 @@ impl<'a> Help<'a> {
if arg.is_set(ArgSettings::Multiple) && num == 1 { if arg.is_set(ArgSettings::Multiple) && num == 1 {
color!(self, "...", good)?; color!(self, "...", good)?;
} }
} else if let Some(num) = arg.num_vals() { } else if let Some(num) = arg.num_vals {
let mut it = (0..num).peekable(); let mut it = (0..num).peekable();
while let Some(_) = it.next() { while let Some(_) = it.next() {
color!(self, "<{}>", arg.name(), good)?; color!(self, "<{}>", arg.name, good)?;
if it.peek().is_some() { if it.peek().is_some() {
write!(self.writer, "{}", delim)?; write!(self.writer, "{}", delim)?;
} }
@ -345,7 +326,7 @@ impl<'a> Help<'a> {
color!(self, "...", good)?; color!(self, "...", good)?;
} }
} else if arg.has_switch() { } else if arg.has_switch() {
color!(self, "<{}>", arg.name(), good)?; color!(self, "<{}>", arg.name, good)?;
if arg.is_set(ArgSettings::Multiple) { if arg.is_set(ArgSettings::Multiple) {
color!(self, "...", good)?; color!(self, "...", good)?;
} }
@ -355,7 +336,7 @@ impl<'a> Help<'a> {
} }
let spec_vals = self.spec_vals(arg); let spec_vals = self.spec_vals(arg);
let h = arg.help().unwrap_or(""); let h = arg.help.unwrap_or("");
let h_w = str_width(h) + str_width(&*spec_vals); let h_w = str_width(h) + str_width(&*spec_vals);
let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp); let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp);
let taken = self.longest + 12; let taken = self.longest + 12;
@ -384,7 +365,7 @@ impl<'a> Help<'a> {
let mut spcs = self.longest - self_len; let mut spcs = self.longest - self_len;
// Since we're writing spaces from the tab point we first need to know if we // Since we're writing spaces from the tab point we first need to know if we
// had a long and short, or just short // had a long and short, or just short
if arg.long().is_some() { if arg.long.is_some() {
// Only account 4 after the val // Only account 4 after the val
spcs += 4; spcs += 4;
} else { } else {
@ -440,12 +421,12 @@ impl<'a> Help<'a> {
} }
/// Writes argument's help to the wrapped stream. /// Writes argument's help to the wrapped stream.
fn help<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>, spec_vals: &str) -> io::Result<()> { fn help<'b, 'c>(&mut self, arg: &Arg<'b, 'c>, spec_vals: &str) -> io::Result<()> {
debugln!("Help::help;"); debugln!("Help::help;");
let h = if self.use_long { let h = if self.use_long {
arg.long_help().unwrap_or_else(|| arg.help().unwrap_or("")) arg.long_help.unwrap_or_else(|| arg.help.unwrap_or(""))
} else { } else {
arg.help().unwrap_or_else(|| arg.long_help().unwrap_or("")) arg.help.unwrap_or_else(|| arg.long_help.unwrap_or(""))
}; };
let mut help = String::from(h) + spec_vals; let mut help = String::from(h) + spec_vals;
let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp) || self.use_long; let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp) || self.use_long;
@ -496,29 +477,30 @@ impl<'a> Help<'a> {
Ok(()) Ok(())
} }
fn spec_vals(&self, a: &ArgWithDisplay) -> String { fn spec_vals(&self, a: &Arg) -> String {
debugln!("Help::spec_vals: a={}", a); debugln!("Help::spec_vals: a={}", a);
let mut spec_vals = vec![]; let mut spec_vals = vec![];
if let Some(ref env) = a.env() { if let Some(ref env) = a.env {
debugln!( debugln!(
"Help::spec_vals: Found environment variable...[{:?}:{:?}]", "Help::spec_vals: Found environment variable...[{:?}:{:?}]",
env.0, env.0,
env.1 env.1
); );
let env_val = if !a.is_set(ArgSettings::HideEnvValues) { let env_val = if !a.is_set(ArgSettings::HideEnvValues) {
format!("={}", env.1.map_or(Cow::Borrowed(""), |val| val.to_string_lossy())) format!(
"={}",
env.1
.as_ref()
.map_or(Cow::Borrowed(""), |val| val.to_string_lossy())
)
} else { } else {
String::new() String::new()
}; };
let env_info = format!( let env_info = format!(" [env: {}{}]", env.0.to_string_lossy(), env_val);
" [env: {}{}]",
env.0.to_string_lossy(),
env_val
);
spec_vals.push(env_info); spec_vals.push(env_info);
} }
if !a.is_set(ArgSettings::HideDefaultValue) { if !a.is_set(ArgSettings::HideDefaultValue) {
if let Some(pv) = a.default_val() { if let Some(pv) = a.default_val {
debugln!("Help::spec_vals: Found default value...[{:?}]", pv); debugln!("Help::spec_vals: Found default value...[{:?}]", pv);
spec_vals.push(format!( spec_vals.push(format!(
" [default: {}]", " [default: {}]",
@ -530,23 +512,29 @@ impl<'a> Help<'a> {
)); ));
} }
} }
if let Some(ref aliases) = a.aliases() { if let Some(ref aliases) = a.aliases {
debugln!("Help::spec_vals: Found aliases...{:?}", aliases); debugln!("Help::spec_vals: Found aliases...{:?}", aliases);
spec_vals.push(format!( let als = if self.color {
" [aliases: {}]", aliases
if self.color { .iter()
aliases .filter(|&als| als.1) // visible
.iter() .map(|&als| format!("{}", self.cizer.good(als.0))) // name
.map(|v| format!("{}", self.cizer.good(v))) .collect::<Vec<_>>()
.collect::<Vec<_>>() .join(", ")
.join(", ") } else {
} else { aliases
aliases.join(", ") .iter()
} .filter(|&als| als.1)
)); .map(|&als| als.0)
.collect::<Vec<_>>()
.join(", ")
};
if !als.is_empty() {
spec_vals.push(format!(" [aliases: {}]", als));
}
} }
if !self.hide_pv && !a.is_set(ArgSettings::HidePossibleValues) { if !self.hide_pv && !a.is_set(ArgSettings::HidePossibleValues) {
if let Some(pv) = a.possible_vals() { if let Some(ref pv) = a.possible_vals {
debugln!("Help::spec_vals: Found possible vals...{:?}", pv); debugln!("Help::spec_vals: Found possible vals...{:?}", pv);
spec_vals.push(if self.color { spec_vals.push(if self.color {
format!( format!(
@ -565,9 +553,121 @@ impl<'a> Help<'a> {
} }
} }
/// Methods to write a single subcommand
impl<'w> Help<'w> {
fn write_subcommand<'a, 'b>(&mut self, app: &App<'a, 'b>) -> io::Result<()> {
debugln!("Help::write_subcommand;");
write!(self.writer, "{}", TAB)?;
color!(self, "{}", app.name, good)?;
let spec_vals = self.sc_val(app)?;
self.sc_help(app, &*spec_vals)?;
Ok(())
}
fn sc_val<'a, 'b>(&mut self, app: &App<'a, 'b>) -> Result<String, io::Error> {
debugln!("Help::sc_val: app={}", app.name);
let spec_vals = self.sc_spec_vals(app);
let h = app.about.unwrap_or("");
let h_w = str_width(h) + str_width(&*spec_vals);
let nlh = self.next_line_help;
let taken = self.longest + 12;
self.force_next_line = !nlh && self.term_w >= taken
&& (taken as f32 / self.term_w as f32) > 0.40
&& h_w > (self.term_w - taken);
if !(nlh || self.force_next_line) {
write_nspaces!(
self.writer,
self.longest + 4 - (str_width(app.to_string().as_str()))
);
}
Ok(spec_vals)
}
fn sc_spec_vals(&self, a: &App) -> String {
debugln!("Help::sc_spec_vals: a={}", a.name);
let mut spec_vals = vec![];
if let Some(ref aliases) = a.aliases {
debugln!("Help::spec_vals: Found aliases...{:?}", aliases);
let als = if self.color {
aliases
.iter()
.filter(|&als| als.1) // visible
.map(|&als| format!("{}", self.cizer.good(als.0))) // name
.collect::<Vec<_>>()
.join(", ")
} else {
aliases
.iter()
.filter(|&als| als.1)
.map(|&als| als.0)
.collect::<Vec<_>>()
.join(", ")
};
if !als.is_empty() {
spec_vals.push(format!(" [aliases: {}]", als));
}
}
spec_vals.join(" ")
}
fn sc_help<'a, 'b>(&mut self, app: &App<'a, 'b>, spec_vals: &str) -> io::Result<()> {
debugln!("Help::sc_help;");
let h = if self.use_long {
app.long_about.unwrap_or_else(|| app.about.unwrap_or(""))
} else {
app.about.unwrap_or_else(|| app.long_about.unwrap_or(""))
};
let mut help = String::from(h) + spec_vals;
let nlh = self.next_line_help || self.use_long;
debugln!("Help::sc_help: Next Line...{:?}", nlh);
let spcs = if nlh || self.force_next_line {
12 // "tab" * 3
} else {
self.longest + 12
};
let too_long = spcs + str_width(h) + str_width(&*spec_vals) >= self.term_w;
// Is help on next line, if so then indent
if nlh || self.force_next_line {
write!(self.writer, "\n{}{}{}", TAB, TAB, TAB)?;
}
debug!("Help::sc_help: Too long...");
if too_long && spcs <= self.term_w || h.contains("{n}") {
sdebugln!("Yes");
debugln!("Help::sc_help: help...{}", help);
debugln!("Help::sc_help: help width...{}", str_width(&*help));
// Determine how many newlines we need to insert
let avail_chars = self.term_w - spcs;
debugln!("Help::sc_help: Usable space...{}", avail_chars);
help = wrap_help(&help.replace("{n}", "\n"), avail_chars);
} else {
sdebugln!("No");
}
if let Some(part) = help.lines().next() {
write!(self.writer, "{}", part)?;
}
for part in help.lines().skip(1) {
write!(self.writer, "\n")?;
if nlh || self.force_next_line {
write!(self.writer, "{}{}{}", TAB, TAB, TAB)?;
} else {
write_nspaces!(self.writer, self.longest + 8);
}
write!(self.writer, "{}", part)?;
}
if !help.contains('\n') && (nlh || self.force_next_line) {
write!(self.writer, "\n")?;
}
Ok(())
}
}
// Methods to write Parser help. // Methods to write Parser help.
impl<'a> Help<'a> { impl<'w> Help<'w> {
/// Writes help for all arguments (options, flags, args, subcommands) /// Writes help for all arguments (options, flags, args, subcommands)
/// including titles of a Parser Object to the wrapped stream. /// including titles of a Parser Object to the wrapped stream.
#[cfg_attr(feature = "lints", allow(useless_let_if_seq))] #[cfg_attr(feature = "lints", allow(useless_let_if_seq))]
@ -575,10 +675,14 @@ impl<'a> Help<'a> {
pub fn write_all_args(&mut self, parser: &Parser) -> ClapResult<()> { pub fn write_all_args(&mut self, parser: &Parser) -> ClapResult<()> {
debugln!("Help::write_all_args;"); debugln!("Help::write_all_args;");
let flags = parser.has_flags(); let flags = parser.has_flags();
let pos = parser // Strange filter/count vs fold... https://github.com/rust-lang/rust/issues/33038
.positionals() let pos = positionals!(parser.app).fold(0, |acc, arg| {
.filter(|arg| !arg.is_set(ArgSettings::Hidden)) if arg.is_set(ArgSettings::Hidden) {
.count() > 0; acc
} else {
acc + 1
}
}) > 0;
let opts = parser.has_opts(); let opts = parser.has_opts();
let subcmds = parser.has_visible_subcommands(); let subcmds = parser.has_visible_subcommands();
@ -587,17 +691,14 @@ impl<'a> Help<'a> {
let mut first = true; let mut first = true;
if unified_help && (flags || opts) { if unified_help && (flags || opts) {
let opts_flags = parser let opts_flags = args!(parser.app).filter(|a| a.has_switch());
.flags()
.map(as_arg_trait)
.chain(parser.opts().map(as_arg_trait));
color!(self, "OPTIONS:\n", warning)?; color!(self, "OPTIONS:\n", warning)?;
self.write_args(opts_flags)?; self.write_args(opts_flags)?;
first = false; first = false;
} else { } else {
if flags { if flags {
color!(self, "FLAGS:\n", warning)?; color!(self, "FLAGS:\n", warning)?;
self.write_args(parser.flags().map(as_arg_trait))?; self.write_args(flags!(parser.app))?;
first = false; first = false;
} }
if opts { if opts {
@ -605,7 +706,7 @@ impl<'a> Help<'a> {
self.writer.write_all(b"\n\n")?; self.writer.write_all(b"\n\n")?;
} }
color!(self, "OPTIONS:\n", warning)?; color!(self, "OPTIONS:\n", warning)?;
self.write_args(parser.opts().map(as_arg_trait))?; self.write_args(opts!(parser.app))?;
first = false; first = false;
} }
} }
@ -615,7 +716,7 @@ impl<'a> Help<'a> {
self.writer.write_all(b"\n\n")?; self.writer.write_all(b"\n\n")?;
} }
color!(self, "ARGS:\n", warning)?; color!(self, "ARGS:\n", warning)?;
self.write_args_unsorted(parser.positionals().map(as_arg_trait))?; self.write_args_unsorted(positionals!(parser.app))?;
first = false; first = false;
} }
@ -624,27 +725,23 @@ impl<'a> Help<'a> {
self.writer.write_all(b"\n\n")?; self.writer.write_all(b"\n\n")?;
} }
color!(self, "SUBCOMMANDS:\n", warning)?; color!(self, "SUBCOMMANDS:\n", warning)?;
self.write_subcommands(parser)?; self.write_subcommands(&parser.app)?;
} }
Ok(()) Ok(())
} }
/// Writes help for subcommands of a Parser Object to the wrapped stream. /// Writes help for subcommands of a Parser Object to the wrapped stream.
fn write_subcommands(&mut self, parser: &Parser) -> io::Result<()> { fn write_subcommands(&mut self, app: &App) -> io::Result<()> {
debugln!("Help::write_subcommands;"); debugln!("Help::write_subcommands;");
// The shortest an arg can legally be is 2 (i.e. '-x') // The shortest an arg can legally be is 2 (i.e. '-x')
self.longest = 2; self.longest = 2;
let mut ord_m = VecMap::new(); let mut ord_m = VecMap::new();
for sc in parser for sc in subcommands!(app).filter(|s| !s.is_set(AppSettings::Hidden)) {
.subcommands let btm = ord_m.entry(sc.disp_ord).or_insert(BTreeMap::new());
.iter() self.longest = cmp::max(self.longest, str_width(sc.name.as_str()));
.filter(|s| !s.p.is_set(AppSettings::Hidden))
{
let btm = ord_m.entry(sc.p.meta.disp_ord).or_insert(BTreeMap::new());
self.longest = cmp::max(self.longest, str_width(sc.p.meta.name.as_str()));
//self.longest = cmp::max(self.longest, sc.p.meta.name.len()); //self.longest = cmp::max(self.longest, sc.p.meta.name.len());
btm.insert(sc.p.meta.name.clone(), sc.clone()); btm.insert(sc.name.clone(), sc.clone());
} }
let mut first = true; let mut first = true;
@ -655,7 +752,7 @@ impl<'a> Help<'a> {
} else { } else {
self.writer.write_all(b"\n")?; self.writer.write_all(b"\n")?;
} }
self.write_arg(sc)?; self.write_subcommand(sc)?;
} }
} }
Ok(()) Ok(())
@ -664,7 +761,7 @@ impl<'a> Help<'a> {
/// Writes version of a Parser Object to the wrapped stream. /// Writes version of a Parser Object to the wrapped stream.
fn write_version(&mut self, parser: &Parser) -> io::Result<()> { fn write_version(&mut self, parser: &Parser) -> io::Result<()> {
debugln!("Help::write_version;"); debugln!("Help::write_version;");
write!(self.writer, "{}", parser.meta.version.unwrap_or(""))?; write!(self.writer, "{}", parser.app.version.unwrap_or(""))?;
Ok(()) Ok(())
} }
@ -673,12 +770,12 @@ impl<'a> Help<'a> {
debugln!("Help::write_bin_name;"); debugln!("Help::write_bin_name;");
macro_rules! write_name { macro_rules! write_name {
() => {{ () => {{
let mut name = parser.meta.name.clone(); let mut name = parser.app.name.clone();
name = name.replace("{n}", "\n"); name = name.replace("{n}", "\n");
color!(self, wrap_help(&name, self.term_w), good)?; color!(self, wrap_help(&name, self.term_w), good)?;
}}; }};
} }
if let Some(bn) = parser.meta.bin_name.as_ref() { if let Some(bn) = parser.app.bin_name.as_ref() {
if bn.contains(' ') { if bn.contains(' ') {
// Incase we're dealing with subcommands i.e. git mv is translated to git-mv // Incase we're dealing with subcommands i.e. git mv is translated to git-mv
color!(self, bn.replace(" ", "-"), good)? color!(self, bn.replace(" ", "-"), good)?
@ -694,7 +791,7 @@ impl<'a> Help<'a> {
/// Writes default help for a Parser Object to the wrapped stream. /// Writes default help for a Parser Object to the wrapped stream.
pub fn write_default_help(&mut self, parser: &Parser) -> ClapResult<()> { pub fn write_default_help(&mut self, parser: &Parser) -> ClapResult<()> {
debugln!("Help::write_default_help;"); debugln!("Help::write_default_help;");
if let Some(h) = parser.meta.pre_help { if let Some(h) = parser.app.pre_help {
self.write_before_after_help(h)?; self.write_before_after_help(h)?;
self.writer.write_all(b"\n\n")?; self.writer.write_all(b"\n\n")?;
} }
@ -712,21 +809,21 @@ impl<'a> Help<'a> {
self.writer.write_all(b" ")?; self.writer.write_all(b" ")?;
self.write_version(parser)?; self.write_version(parser)?;
self.writer.write_all(b"\n")?; self.writer.write_all(b"\n")?;
if let Some(author) = parser.meta.author { if let Some(author) = parser.app.author {
write_thing!(author) write_thing!(author)
} }
if self.use_long { if self.use_long {
if let Some(about) = parser.meta.long_about { if let Some(about) = parser.app.long_about {
debugln!("Help::write_default_help: writing long about"); debugln!("Help::write_default_help: writing long about");
write_thing!(about) write_thing!(about)
} else if let Some(about) = parser.meta.about { } else if let Some(about) = parser.app.about {
debugln!("Help::write_default_help: writing about"); debugln!("Help::write_default_help: writing about");
write_thing!(about) write_thing!(about)
} }
} else if let Some(about) = parser.meta.about { } else if let Some(about) = parser.app.about {
debugln!("Help::write_default_help: writing about"); debugln!("Help::write_default_help: writing about");
write_thing!(about) write_thing!(about)
} else if let Some(about) = parser.meta.long_about { } else if let Some(about) = parser.app.long_about {
debugln!("Help::write_default_help: writing long about"); debugln!("Help::write_default_help: writing long about");
write_thing!(about) write_thing!(about)
} }
@ -736,7 +833,7 @@ impl<'a> Help<'a> {
self.writer, self.writer,
"\n{}{}\n\n", "\n{}{}\n\n",
TAB, TAB,
usage::create_usage_no_title(parser, &[]) Usage::new(parser).create_usage_no_title(&[])
)?; )?;
let flags = parser.has_flags(); let flags = parser.has_flags();
@ -748,7 +845,7 @@ impl<'a> Help<'a> {
self.write_all_args(parser)?; self.write_all_args(parser)?;
} }
if let Some(h) = parser.meta.more_help { if let Some(h) = parser.app.more_help {
if flags || opts || pos || subcmds { if flags || opts || pos || subcmds {
self.writer.write_all(b"\n\n")?; self.writer.write_all(b"\n\n")?;
} }
@ -856,9 +953,8 @@ fn copy_and_capture<R: Read, W: Write>(
} }
} }
// Methods to write Parser help using templates. // Methods to write Parser help using templates.
impl<'a> Help<'a> { impl<'w> Help<'w> {
/// Write help to stream for the parser in the format defined by the template. /// Write help to stream for the parser in the format defined by the template.
/// ///
/// Tags arg given inside curly brackets: /// Tags arg given inside curly brackets:
@ -917,67 +1013,68 @@ impl<'a> Help<'a> {
write!( write!(
self.writer, self.writer,
"{}", "{}",
parser.meta.version.unwrap_or("unknown version") parser.app.version.unwrap_or("unknown version")
)?; )?;
} }
b"author" => { b"author" => {
write!( write!(
self.writer, self.writer,
"{}", "{}",
parser.meta.author.unwrap_or("unknown author") parser.app.author.unwrap_or("unknown author")
)?; )?;
} }
b"about" => { b"about" => {
write!( write!(
self.writer, self.writer,
"{}", "{}",
parser.meta.about.unwrap_or("unknown about") parser.app.about.unwrap_or("unknown about")
)?; )?;
} }
b"long-about" => { b"long-about" => {
write!( write!(
self.writer, self.writer,
"{}", "{}",
parser.meta.long_about.unwrap_or("unknown about") parser.app.long_about.unwrap_or("unknown about")
)?; )?;
} }
b"usage" => { b"usage" => {
write!(self.writer, "{}", usage::create_usage_no_title(parser, &[]))?; write!(
self.writer,
"{}",
Usage::new(parser).create_usage_no_title(&[])
)?;
} }
b"all-args" => { b"all-args" => {
self.write_all_args(parser)?; self.write_all_args(parser)?;
} }
b"unified" => { b"unified" => {
let opts_flags = parser let opts_flags = parser.app.args.iter().filter(|a| a.has_switch());
.flags()
.map(as_arg_trait)
.chain(parser.opts().map(as_arg_trait));
self.write_args(opts_flags)?; self.write_args(opts_flags)?;
} }
b"flags" => { b"flags" => {
self.write_args(parser.flags().map(as_arg_trait))?; self.write_args(flags!(parser.app))?;
} }
b"options" => { b"options" => {
self.write_args(parser.opts().map(as_arg_trait))?; self.write_args(opts!(parser.app))?;
} }
b"positionals" => { b"positionals" => {
self.write_args(parser.positionals().map(as_arg_trait))?; self.write_args(positionals!(parser.app))?;
} }
b"subcommands" => { b"subcommands" => {
self.write_subcommands(parser)?; self.write_subcommands(parser.app)?;
} }
b"after-help" => { b"after-help" => {
write!( write!(
self.writer, self.writer,
"{}", "{}",
parser.meta.more_help.unwrap_or("unknown after-help") parser.app.more_help.unwrap_or("unknown after-help")
)?; )?;
} }
b"before-help" => { b"before-help" => {
write!( write!(
self.writer, self.writer,
"{}", "{}",
parser.meta.pre_help.unwrap_or("unknown before-help") parser.app.pre_help.unwrap_or("unknown before-help")
)?; )?;
} }
// Unknown tag, write it back. // Unknown tag, write it back.

View file

@ -1,33 +0,0 @@
#[doc(hidden)]
#[allow(missing_debug_implementations)]
#[derive(Default, Clone)]
pub struct AppMeta<'b> {
pub name: String,
pub bin_name: Option<String>,
pub author: Option<&'b str>,
pub version: Option<&'b str>,
pub long_version: Option<&'b str>,
pub about: Option<&'b str>,
pub long_about: Option<&'b str>,
pub more_help: Option<&'b str>,
pub pre_help: Option<&'b str>,
pub aliases: Option<Vec<(&'b str, bool)>>, // (name, visible)
pub usage_str: Option<&'b str>,
pub usage: Option<String>,
pub help_str: Option<&'b str>,
pub disp_ord: usize,
pub term_w: Option<usize>,
pub max_w: Option<usize>,
pub template: Option<&'b str>,
}
impl<'b> AppMeta<'b> {
pub fn new() -> Self { Default::default() }
pub fn with_name(s: String) -> Self {
AppMeta {
name: s,
disp_ord: 999,
..Default::default()
}
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -3,477 +3,468 @@ use std::collections::{BTreeMap, VecDeque};
// Internal // Internal
use INTERNAL_ERROR_MSG; use INTERNAL_ERROR_MSG;
use args::{AnyArg, ArgMatcher, PosBuilder}; use args::{Arg, ArgMatcher};
use args::settings::ArgSettings; use args::settings::ArgSettings;
use app::settings::AppSettings as AS; use app::settings::AppSettings as AS;
use app::parser::Parser; use app::parser::Parser;
// Creates a usage string for display. This happens just after all arguments were parsed, but before pub struct Usage<'a, 'b, 'c, 'z>(&'z Parser<'a, 'b, 'c>)
// any subcommands have been parsed (so as to give subcommands their own usage recursively) where
pub fn create_usage_with_title(p: &Parser, used: &[&str]) -> String { 'a: 'b,
debugln!("usage::create_usage_with_title;"); 'b: 'c,
let mut usage = String::with_capacity(75); 'c: 'z;
usage.push_str("USAGE:\n ");
usage.push_str(&*create_usage_no_title(p, used));
usage
}
// Creates a usage string to be used in error message (i.e. one with currently used args) impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
pub fn create_error_usage<'a, 'b>( pub fn new(p: &'z Parser<'a, 'b, 'c>) -> Self { Usage(p) }
p: &Parser<'a, 'b>,
matcher: &'b ArgMatcher<'a>,
extra: Option<&str>,
) -> String {
let mut args: Vec<_> = matcher
.arg_names()
.iter()
.filter(|n| {
if let Some(o) = find_by_name!(p, **n, opts, iter) {
!o.b.is_set(ArgSettings::Required) && !o.b.is_set(ArgSettings::Hidden)
} else if let Some(p) = find_by_name!(p, **n, positionals, values) {
!p.b.is_set(ArgSettings::Required) && p.b.is_set(ArgSettings::Hidden)
} else {
true // flags can't be required, so they're always true
}
})
.map(|&n| n)
.collect();
if let Some(r) = extra {
args.push(r);
}
create_usage_with_title(p, &*args)
}
// Creates a usage string (*without title*) if one was not provided by the user manually. // Creates a usage string for display. This happens just after all arguments were parsed, but before
pub fn create_usage_no_title(p: &Parser, used: &[&str]) -> String { // any subcommands have been parsed (so as to give subcommands their own usage recursively)
debugln!("usage::create_usage_no_title;"); pub fn create_usage_with_title(&self, used: &[&str]) -> String {
if let Some(u) = p.meta.usage_str { debugln!("usage::create_usage_with_title;");
String::from(&*u) let mut usage = String::with_capacity(75);
} else if used.is_empty() { usage.push_str("USAGE:\n ");
create_help_usage(p, true) usage.push_str(&*self.create_usage_no_title(used));
} else { usage
create_smart_usage(p, used)
}
}
// Creates a usage string for display in help messages (i.e. not for errors)
pub fn create_help_usage(p: &Parser, incl_reqs: bool) -> String {
let mut usage = String::with_capacity(75);
let name = p.meta
.usage
.as_ref()
.unwrap_or_else(|| p.meta.bin_name.as_ref().unwrap_or(&p.meta.name));
usage.push_str(&*name);
let req_string = if incl_reqs {
let mut reqs: Vec<&str> = p.required().map(|r| &**r).collect();
reqs.sort();
reqs.dedup();
get_required_usage_from(p, &reqs, None, None, false)
.iter()
.fold(String::new(), |a, s| a + &format!(" {}", s)[..])
} else {
String::new()
};
let flags = needs_flags_tag(p);
if flags && !p.is_set(AS::UnifiedHelpMessage) {
usage.push_str(" [FLAGS]");
} else if flags {
usage.push_str(" [OPTIONS]");
}
if !p.is_set(AS::UnifiedHelpMessage) && p.opts.iter().any(|o| {
!o.is_set(ArgSettings::Required) && !o.is_set(ArgSettings::Hidden)
}) {
usage.push_str(" [OPTIONS]");
} }
usage.push_str(&req_string[..]); // Creates a usage string to be used in error message (i.e. one with currently used args)
pub fn create_error_usage(&self, matcher: &ArgMatcher<'a>, extra: Option<&str>) -> String {
let has_last = p.positionals.values().any(|p| p.is_set(ArgSettings::Last)); let mut args: Vec<_> = matcher
// places a '--' in the usage string if there are args and options .arg_names()
// supporting multiple values .filter(|ref n| {
if p.opts.iter().any(|o| o.is_set(ArgSettings::Multiple)) if let Some(a) = find!(self.0.app, **n) {
&& p.positionals !a.is_set(ArgSettings::Required) && !a.is_set(ArgSettings::Hidden)
.values() } else {
.any(|p| !p.is_set(ArgSettings::Required)) true // flags can't be required, so they're always true
&& !(p.has_visible_subcommands() || p.is_set(AS::AllowExternalSubcommands)) }
&& !has_last })
{ .map(|&n| n)
usage.push_str(" [--]"); .collect();
if let Some(r) = extra {
args.push(r);
}
self.create_usage_with_title(&*args)
} }
let not_req_or_hidden = |p: &PosBuilder| {
(!p.is_set(ArgSettings::Required) || p.is_set(ArgSettings::Last)) // Creates a usage string (*without title*) if one was not provided by the user manually.
&& !p.is_set(ArgSettings::Hidden) pub fn create_usage_no_title(&self, used: &[&str]) -> String {
}; debugln!("usage::create_usage_no_title;");
if p.has_positionals() && p.positionals.values().any(not_req_or_hidden) { if let Some(u) = self.0.app.usage_str {
if let Some(args_tag) = get_args_tag(p, incl_reqs) { String::from(&*u)
usage.push_str(&*args_tag); } else if used.is_empty() {
self.create_help_usage(true)
} else { } else {
usage.push_str(" [ARGS]"); self.create_smart_usage(used)
}
if has_last && incl_reqs {
let pos = p.positionals
.values()
.find(|p| p.b.is_set(ArgSettings::Last))
.expect(INTERNAL_ERROR_MSG);
debugln!("usage::create_help_usage: '{}' has .last(true)", pos.name());
let req = pos.is_set(ArgSettings::Required);
if req
&& p.positionals
.values()
.any(|p| !p.is_set(ArgSettings::Required))
{
usage.push_str(" -- <");
} else if req {
usage.push_str(" [--] <");
} else {
usage.push_str(" [-- <");
}
usage.push_str(&*pos.name_no_brackets());
usage.push_str(">");
usage.push_str(pos.multiple_str());
if !req {
usage.push_str("]");
}
} }
} }
// incl_reqs is only false when this function is called recursively // Creates a usage string for display in help messages (i.e. not for errors)
if p.has_visible_subcommands() && incl_reqs || p.is_set(AS::AllowExternalSubcommands) { pub fn create_help_usage(&self, incl_reqs: bool) -> String {
if p.is_set(AS::SubcommandsNegateReqs) || p.is_set(AS::ArgsNegateSubcommands) { let mut usage = String::with_capacity(75);
if !p.is_set(AS::ArgsNegateSubcommands) { let name = self.0
usage.push_str("\n "); .app
usage.push_str(&*create_help_usage(p, false));
usage.push_str(" <SUBCOMMAND>");
} else {
usage.push_str("\n ");
usage.push_str(&*name);
usage.push_str(" <SUBCOMMAND>");
}
} else if p.is_set(AS::SubcommandRequired) || p.is_set(AS::SubcommandRequiredElseHelp) {
usage.push_str(" <SUBCOMMAND>");
} else {
usage.push_str(" [SUBCOMMAND]");
}
}
usage.shrink_to_fit();
debugln!("usage::create_help_usage: usage={}", usage);
usage
}
// Creates a context aware usage string, or "smart usage" from currently used
// args, and requirements
fn create_smart_usage(p: &Parser, used: &[&str]) -> String {
debugln!("usage::smart_usage;");
let mut usage = String::with_capacity(75);
let mut hs: Vec<&str> = p.required().map(|s| &**s).collect();
hs.extend_from_slice(used);
let r_string = get_required_usage_from(p, &hs, None, None, false)
.iter()
.fold(String::new(), |acc, s| acc + &format!(" {}", s)[..]);
usage.push_str(
&p.meta
.usage .usage
.as_ref() .as_ref()
.unwrap_or_else(|| p.meta.bin_name.as_ref().unwrap_or(&p.meta.name))[..], .unwrap_or_else(|| self.0.app.bin_name.as_ref().unwrap_or(&self.0.app.name));
); usage.push_str(&*name);
usage.push_str(&*r_string); let req_string = if incl_reqs {
if p.is_set(AS::SubcommandRequired) { let mut reqs: Vec<&str> = self.0.required().map(|r| &**r).collect();
usage.push_str(" <SUBCOMMAND>"); reqs.sort();
} reqs.dedup();
usage.shrink_to_fit(); self.get_required_usage_from(&reqs, None, None, false)
usage .iter()
} .fold(String::new(), |a, s| a + &format!(" {}", s)[..])
} else {
String::new()
};
// Gets the `[ARGS]` tag for the usage string let flags = self.needs_flags_tag();
fn get_args_tag(p: &Parser, incl_reqs: bool) -> Option<String> { if flags && !self.0.is_set(AS::UnifiedHelpMessage) {
debugln!("usage::get_args_tag;"); usage.push_str(" [FLAGS]");
let mut count = 0; } else if flags {
'outer: for pos in p.positionals usage.push_str(" [OPTIONS]");
.values() }
.filter(|pos| !pos.is_set(ArgSettings::Required)) if !self.0.is_set(AS::UnifiedHelpMessage)
.filter(|pos| !pos.is_set(ArgSettings::Hidden)) && opts!(self.0.app)
.filter(|pos| !pos.is_set(ArgSettings::Last)) .any(|o| !o.is_set(ArgSettings::Required) && !o.is_set(ArgSettings::Hidden))
{ {
debugln!("usage::get_args_tag:iter:{}:", pos.b.name); usage.push_str(" [OPTIONS]");
if let Some(g_vec) = p.groups_for_arg(pos.b.name) { }
for grp_s in &g_vec {
debugln!("usage::get_args_tag:iter:{}:iter:{};", pos.b.name, grp_s); usage.push_str(&req_string[..]);
// if it's part of a required group we don't want to count it
if p.groups.iter().any(|g| g.required && (&g.name == grp_s)) { let has_last = positionals!(self.0.app).any(|p| p.is_set(ArgSettings::Last));
continue 'outer; // places a '--' in the usage string if there are args and options
// supporting multiple values
if opts!(self.0.app).any(|o| o.is_set(ArgSettings::Multiple))
&& positionals!(self.0.app).any(|p| !p.is_set(ArgSettings::Required))
&& !(self.0.app.has_visible_subcommands()
|| self.0.is_set(AS::AllowExternalSubcommands)) && !has_last
{
usage.push_str(" [--]");
}
let not_req_or_hidden = |p: &Arg| {
(!p.is_set(ArgSettings::Required) || p.is_set(ArgSettings::Last))
&& !p.is_set(ArgSettings::Hidden)
};
if positionals!(self.0.app).any(not_req_or_hidden) {
if let Some(args_tag) = self.get_args_tag(incl_reqs) {
usage.push_str(&*args_tag);
} else {
usage.push_str(" [ARGS]");
}
if has_last && incl_reqs {
let pos = positionals!(self.0.app)
.find(|p| p.is_set(ArgSettings::Last))
.expect(INTERNAL_ERROR_MSG);
debugln!("usage::create_help_usage: '{}' has .last(true)", pos.name);
let req = pos.is_set(ArgSettings::Required);
if req && positionals!(self.0.app).any(|p| !p.is_set(ArgSettings::Required)) {
usage.push_str(" -- <");
} else if req {
usage.push_str(" [--] <");
} else {
usage.push_str(" [-- <");
}
usage.push_str(&*pos.name_no_brackets());
usage.push_str(">");
usage.push_str(pos.multiple_str());
if !req {
usage.push_str("]");
} }
} }
} }
count += 1;
debugln!( // incl_reqs is only false when this function is called recursively
"usage::get_args_tag:iter: {} Args not required or hidden", if self.0.app.has_visible_subcommands() && incl_reqs
count || self.0.is_set(AS::AllowExternalSubcommands)
); {
} if self.0.is_set(AS::SubcommandsNegateReqs) || self.0.is_set(AS::ArgsNegateSubcommands)
if !p.is_set(AS::DontCollapseArgsInUsage) && count > 1 { {
debugln!("usage::get_args_tag:iter: More than one, returning [ARGS]"); if !self.0.is_set(AS::ArgsNegateSubcommands) {
return None; // [ARGS] usage.push_str("\n ");
} else if count == 1 && incl_reqs { usage.push_str(&*self.create_help_usage(false));
let pos = p.positionals usage.push_str(" <SUBCOMMAND>");
.values()
.find(|pos| {
!pos.is_set(ArgSettings::Required) && !pos.is_set(ArgSettings::Hidden)
&& !pos.is_set(ArgSettings::Last)
})
.expect(INTERNAL_ERROR_MSG);
debugln!(
"usage::get_args_tag:iter: Exactly one, returning '{}'",
pos.name()
);
return Some(format!(
" [{}]{}",
pos.name_no_brackets(),
pos.multiple_str()
));
} else if p.is_set(AS::DontCollapseArgsInUsage) && !p.positionals.is_empty() && incl_reqs {
debugln!("usage::get_args_tag:iter: Don't collapse returning all");
return Some(
p.positionals
.values()
.filter(|pos| !pos.is_set(ArgSettings::Required))
.filter(|pos| !pos.is_set(ArgSettings::Hidden))
.filter(|pos| !pos.is_set(ArgSettings::Last))
.map(|pos| {
format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str())
})
.collect::<Vec<_>>()
.join(""),
);
} else if !incl_reqs {
debugln!("usage::get_args_tag:iter: incl_reqs=false, building secondary usage string");
let highest_req_pos = p.positionals
.iter()
.filter_map(|(idx, pos)| {
if pos.b.is_set(ArgSettings::Required) && !pos.b.is_set(ArgSettings::Last) {
Some(idx)
} else { } else {
None usage.push_str("\n ");
usage.push_str(&*name);
usage.push_str(" <SUBCOMMAND>");
} }
}) } else if self.0.is_set(AS::SubcommandRequired)
.max() || self.0.is_set(AS::SubcommandRequiredElseHelp)
.unwrap_or_else(|| p.positionals.len()); {
return Some( usage.push_str(" <SUBCOMMAND>");
p.positionals } else {
.iter() usage.push_str(" [SUBCOMMAND]");
.filter_map(|(idx, pos)| { }
if idx <= highest_req_pos { }
Some(pos) usage.shrink_to_fit();
debugln!("usage::create_help_usage: usage={}", usage);
usage
}
// Creates a context aware usage string, or "smart usage" from currently used
// args, and requirements
fn create_smart_usage(&self, used: &[&str]) -> String {
debugln!("usage::smart_usage;");
let mut usage = String::with_capacity(75);
let mut hs: Vec<&str> = self.0.required().map(|s| &**s).collect();
hs.extend_from_slice(used);
let r_string = self.get_required_usage_from(&hs, None, None, false)
.iter()
.fold(String::new(), |acc, s| acc + &format!(" {}", s)[..]);
usage.push_str(
&self.0
.app
.usage
.as_ref()
.unwrap_or_else(|| self.0.app.bin_name.as_ref().unwrap_or(&self.0.app.name))[..],
);
usage.push_str(&*r_string);
if self.0.is_set(AS::SubcommandRequired) {
usage.push_str(" <SUBCOMMAND>");
}
usage.shrink_to_fit();
usage
}
// Gets the `[ARGS]` tag for the usage string
fn get_args_tag(&self, incl_reqs: bool) -> Option<String> {
debugln!("usage::get_args_tag;");
let mut count = 0;
'outer: for pos in positionals!(self.0.app)
.filter(|pos| !pos.is_set(ArgSettings::Required))
.filter(|pos| !pos.is_set(ArgSettings::Hidden))
.filter(|pos| !pos.is_set(ArgSettings::Last))
{
debugln!("usage::get_args_tag:iter:{}:", pos.name);
if let Some(g_vec) = self.0.groups_for_arg(pos.name) {
for grp_s in &g_vec {
debugln!("usage::get_args_tag:iter:{}:iter:{};", pos.name, grp_s);
// if it's part of a required group we don't want to count it
if groups!(self.0.app).any(|g| g.required && (&g.name == grp_s)) {
continue 'outer;
}
}
}
count += 1;
debugln!(
"usage::get_args_tag:iter: {} Args not required or hidden",
count
);
}
if !self.0.is_set(AS::DontCollapseArgsInUsage) && count > 1 {
debugln!("usage::get_args_tag:iter: More than one, returning [ARGS]");
return None; // [ARGS]
} else if count == 1 && incl_reqs {
let pos = positionals!(self.0.app)
.find(|pos| {
!pos.is_set(ArgSettings::Required) && !pos.is_set(ArgSettings::Hidden)
&& !pos.is_set(ArgSettings::Last)
})
.expect(INTERNAL_ERROR_MSG);
debugln!(
"usage::get_args_tag:iter: Exactly one, returning '{}'",
pos.name
);
return Some(format!(
" [{}]{}",
pos.name_no_brackets(),
pos.multiple_str()
));
} else if self.0.is_set(AS::DontCollapseArgsInUsage) && self.0.has_positionals()
&& incl_reqs
{
debugln!("usage::get_args_tag:iter: Don't collapse returning all");
return Some(
positionals!(self.0.app)
.filter(|pos| !pos.is_set(ArgSettings::Required))
.filter(|pos| !pos.is_set(ArgSettings::Hidden))
.filter(|pos| !pos.is_set(ArgSettings::Last))
.map(|pos| format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str()))
.collect::<Vec<_>>()
.join(""),
);
} else if !incl_reqs {
debugln!("usage::get_args_tag:iter: incl_reqs=false, building secondary usage string");
let highest_req_pos = positionals!(self.0.app)
.filter_map(|pos| {
if pos.is_set(ArgSettings::Required) && !pos.is_set(ArgSettings::Last) {
Some(pos.index)
} else { } else {
None None
} }
}) })
.filter(|pos| !pos.is_set(ArgSettings::Required)) .max()
.filter(|pos| !pos.is_set(ArgSettings::Hidden)) .unwrap_or_else(|| Some(positionals!(self.0.app).count() as u64));
.filter(|pos| !pos.is_set(ArgSettings::Last)) return Some(
.map(|pos| { positionals!(self.0.app)
format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str()) .filter_map(|pos| {
}) if pos.index <= highest_req_pos {
.collect::<Vec<_>>() Some(pos)
.join(""), } else {
); None
}
})
.filter(|pos| !pos.is_set(ArgSettings::Required))
.filter(|pos| !pos.is_set(ArgSettings::Hidden))
.filter(|pos| !pos.is_set(ArgSettings::Last))
.map(|pos| format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str()))
.collect::<Vec<_>>()
.join(""),
);
}
Some("".into())
} }
Some("".into())
}
// Determines if we need the `[FLAGS]` tag in the usage string // Determines if we need the `[FLAGS]` tag in the usage string
fn needs_flags_tag(p: &Parser) -> bool { fn needs_flags_tag(&self) -> bool {
debugln!("usage::needs_flags_tag;"); debugln!("usage::needs_flags_tag;");
'outer: for f in &p.flags { 'outer: for f in flags!(self.0.app) {
debugln!("usage::needs_flags_tag:iter: f={};", f.b.name); debugln!("usage::needs_flags_tag:iter: f={};", f.name);
if let Some(l) = f.s.long { if let Some(l) = f.long {
if l == "help" || l == "version" { if l == "help" || l == "version" {
// Don't print `[FLAGS]` just for help or version // Don't print `[FLAGS]` just for help or version
continue;
}
}
if let Some(g_vec) = self.0.groups_for_arg(f.name) {
for grp_s in &g_vec {
debugln!("usage::needs_flags_tag:iter:iter: grp_s={};", grp_s);
if groups!(self.0.app).any(|g| &g.name == grp_s && g.required) {
debugln!("usage::needs_flags_tag:iter:iter: Group is required");
continue 'outer;
}
}
}
if f.is_set(ArgSettings::Hidden) {
continue; continue;
} }
debugln!("usage::needs_flags_tag:iter: [FLAGS] required");
return true;
} }
if let Some(g_vec) = p.groups_for_arg(f.b.name) {
for grp_s in &g_vec { debugln!("usage::needs_flags_tag: [FLAGS] not required");
debugln!("usage::needs_flags_tag:iter:iter: grp_s={};", grp_s); false
if p.groups.iter().any(|g| &g.name == grp_s && g.required) {
debugln!("usage::needs_flags_tag:iter:iter: Group is required");
continue 'outer;
}
}
}
if f.is_set(ArgSettings::Hidden) {
continue;
}
debugln!("usage::needs_flags_tag:iter: [FLAGS] required");
return true;
} }
debugln!("usage::needs_flags_tag: [FLAGS] not required"); // Returns the required args in usage string form by fully unrolling all groups
false pub fn get_required_usage_from(
} &self,
reqs: &[&str],
// Returns the required args in usage string form by fully unrolling all groups matcher: Option<&ArgMatcher<'a>>,
pub fn get_required_usage_from<'a, 'b>( extra: Option<&str>,
p: &Parser<'a, 'b>, incl_last: bool,
reqs: &[&'a str], ) -> VecDeque<String> {
matcher: Option<&ArgMatcher<'a>>, debugln!(
extra: Option<&str>, "usage::get_required_usage_from: reqs={:?}, extra={:?}",
incl_last: bool, reqs,
) -> VecDeque<String> { extra
debugln!( );
"usage::get_required_usage_from: reqs={:?}, extra={:?}", let mut desc_reqs: Vec<&str> = vec![];
reqs, desc_reqs.extend(extra);
extra let mut new_reqs: Vec<&str> = vec![];
); macro_rules! get_requires {
let mut desc_reqs: Vec<&str> = vec![]; (@group $a: ident, $v:ident, $p:ident) => {{
desc_reqs.extend(extra); if let Some(rl) = groups!(self.0.app)
let mut new_reqs: Vec<&str> = vec![]; .filter(|g| g.requires.is_some())
macro_rules! get_requires { .find(|g| &g.name == $a)
(@group $a: ident, $v:ident, $p:ident) => {{ .map(|g| g.requires.as_ref().unwrap()) {
if let Some(rl) = p.groups.iter() for r in rl {
.filter(|g| g.requires.is_some()) if !$p.contains(&r) {
.find(|g| &g.name == $a) debugln!("usage::get_required_usage_from:iter:{}: adding group req={:?}",
.map(|g| g.requires.as_ref().unwrap()) { $a, r);
for r in rl { $v.push(r);
if !$p.contains(&r) { }
debugln!("usage::get_required_usage_from:iter:{}: adding group req={:?}",
$a, r);
$v.push(r);
} }
} }
} }};
}}; ($a:ident, $what:ident, $how:ident, $v:ident, $p:ident) => {{
($a:ident, $what:ident, $how:ident, $v:ident, $p:ident) => {{ if let Some(rl) = $what!(self.0.app)
if let Some(rl) = p.$what.$how() .filter(|a| a.requires.is_some())
.filter(|a| a.b.requires.is_some()) .find(|arg| &arg.name == $a)
.find(|arg| &arg.b.name == $a) .map(|a| a.requires.as_ref().unwrap()) {
.map(|a| a.b.requires.as_ref().unwrap()) { for &(_, r) in rl.iter() {
for &(_, r) in rl.iter() { if !$p.contains(&r) {
if !$p.contains(&r) { debugln!("usage::get_required_usage_from:iter:{}: adding arg req={:?}",
debugln!("usage::get_required_usage_from:iter:{}: adding arg req={:?}", $a, r);
$a, r); $v.push(r);
$v.push(r); }
} }
} }
} }};
}};
}
// initialize new_reqs
for a in reqs {
get_requires!(a, flags, iter, new_reqs, reqs);
get_requires!(a, opts, iter, new_reqs, reqs);
get_requires!(a, positionals, values, new_reqs, reqs);
get_requires!(@group a, new_reqs, reqs);
}
desc_reqs.extend_from_slice(&*new_reqs);
debugln!(
"usage::get_required_usage_from: after init desc_reqs={:?}",
desc_reqs
);
loop {
let mut tmp = vec![];
for a in &new_reqs {
get_requires!(a, flags, iter, tmp, desc_reqs);
get_requires!(a, opts, iter, tmp, desc_reqs);
get_requires!(a, positionals, values, tmp, desc_reqs);
get_requires!(@group a, tmp, desc_reqs);
} }
if tmp.is_empty() { // initialize new_reqs
debugln!("usage::get_required_usage_from: no more children"); for a in reqs {
break; get_requires!(a, flags, iter, new_reqs, reqs);
get_requires!(a, opts, iter, new_reqs, reqs);
get_requires!(a, positionals, values, new_reqs, reqs);
get_requires!(@group a, new_reqs, reqs);
}
desc_reqs.extend_from_slice(&*new_reqs);
debugln!(
"usage::get_required_usage_from: after init desc_reqs={:?}",
desc_reqs
);
loop {
let mut tmp = vec![];
for a in &new_reqs {
get_requires!(a, flags, iter, tmp, desc_reqs);
get_requires!(a, opts, iter, tmp, desc_reqs);
get_requires!(a, positionals, values, tmp, desc_reqs);
get_requires!(@group a, tmp, desc_reqs);
}
if tmp.is_empty() {
debugln!("usage::get_required_usage_from: no more children");
break;
} else {
debugln!("usage::get_required_usage_from: after iter tmp={:?}", tmp);
debugln!(
"usage::get_required_usage_from: after iter new_reqs={:?}",
new_reqs
);
desc_reqs.extend_from_slice(&*new_reqs);
new_reqs.clear();
new_reqs.extend_from_slice(&*tmp);
debugln!(
"usage::get_required_usage_from: after iter desc_reqs={:?}",
desc_reqs
);
}
}
desc_reqs.extend_from_slice(reqs);
desc_reqs.sort();
desc_reqs.dedup();
debugln!(
"usage::get_required_usage_from: final desc_reqs={:?}",
desc_reqs
);
let mut ret_val = VecDeque::new();
let args_in_groups = groups!(self.0.app)
.filter(|gn| desc_reqs.contains(&gn.name))
.flat_map(|g| self.0.arg_names_in_group(g.name))
.collect::<Vec<_>>();
let pmap = if let Some(m) = matcher {
desc_reqs
.iter()
.filter(|a| self.0.positionals.values().any(|p| &p == a))
.filter(|&pos| !m.contains(pos))
.filter_map(|pos| find!(self.0.app, pos))
.filter(|&pos| incl_last || !pos.is_set(ArgSettings::Last))
.filter(|pos| !args_in_groups.contains(&pos.name))
.map(|pos| (pos.index.unwrap(), pos))
.collect::<BTreeMap<u64, &Arg>>() // sort by index
} else { } else {
debugln!("usage::get_required_usage_from: after iter tmp={:?}", tmp); desc_reqs
debugln!( .iter()
"usage::get_required_usage_from: after iter new_reqs={:?}", .filter(|a| self.0.positionals.values().any(|p| &p == a))
new_reqs .filter_map(|pos| find!(self.0.app, pos))
); .filter(|&pos| incl_last || !pos.is_set(ArgSettings::Last))
desc_reqs.extend_from_slice(&*new_reqs); .filter(|pos| !args_in_groups.contains(&pos.name))
new_reqs.clear(); .map(|pos| (pos.index.unwrap(), pos))
new_reqs.extend_from_slice(&*tmp); .collect::<BTreeMap<u64, &Arg>>() // sort by index
debugln!( };
"usage::get_required_usage_from: after iter desc_reqs={:?}", debugln!(
desc_reqs "usage::get_required_usage_from: args_in_groups={:?}",
); args_in_groups
);
for &p in pmap.values() {
let s = p.to_string();
if args_in_groups.is_empty() || !args_in_groups.contains(&&*s) {
ret_val.push_back(s);
}
} }
} for a in desc_reqs
desc_reqs.extend_from_slice(reqs);
desc_reqs.sort();
desc_reqs.dedup();
debugln!(
"usage::get_required_usage_from: final desc_reqs={:?}",
desc_reqs
);
let mut ret_val = VecDeque::new();
let args_in_groups = p.groups
.iter()
.filter(|gn| desc_reqs.contains(&gn.name))
.flat_map(|g| p.arg_names_in_group(g.name))
.collect::<Vec<_>>();
let pmap = if let Some(m) = matcher {
desc_reqs
.iter() .iter()
.filter(|a| p.positionals.values().any(|p| &&p.b.name == a)) .filter(|name| !positionals!(self.0.app).any(|p| &&p.name == name))
.filter(|&pos| !m.contains(pos)) .filter(|name| !groups!(self.0.app).any(|g| &&g.name == name))
.filter_map(|pos| p.positionals.values().find(|x| &x.b.name == pos)) .filter(|name| !args_in_groups.contains(name))
.filter(|&pos| incl_last || !pos.is_set(ArgSettings::Last)) .filter(|name| !(matcher.is_some() && matcher.as_ref().unwrap().contains(name)))
.filter(|pos| !args_in_groups.contains(&pos.b.name)) {
.map(|pos| (pos.index, pos)) debugln!("usage::get_required_usage_from:iter:{}:", a);
.collect::<BTreeMap<u64, &PosBuilder>>() // sort by index let arg = find!(self.0.app, a)
} else { .map(|f| f.to_string())
desc_reqs .expect(INTERNAL_ERROR_MSG);
ret_val.push_back(arg);
}
let mut g_vec: Vec<String> = vec![];
for g in desc_reqs
.iter() .iter()
.filter(|a| p.positionals.values().any(|pos| &&pos.b.name == a)) .filter(|n| groups!(self.0.app).any(|g| &&g.name == n))
.filter_map(|pos| p.positionals.values().find(|x| &x.b.name == pos)) {
.filter(|&pos| incl_last || !pos.is_set(ArgSettings::Last)) let g_string = self.0.args_in_group(g).join("|");
.filter(|pos| !args_in_groups.contains(&pos.b.name)) let elem = format!("<{}>", &g_string[..g_string.len()]);
.map(|pos| (pos.index, pos)) if !g_vec.contains(&elem) {
.collect::<BTreeMap<u64, &PosBuilder>>() // sort by index g_vec.push(elem);
}; }
debugln!(
"usage::get_required_usage_from: args_in_groups={:?}",
args_in_groups
);
for &p in pmap.values() {
let s = p.to_string();
if args_in_groups.is_empty() || !args_in_groups.contains(&&*s) {
ret_val.push_back(s);
} }
} for g in g_vec {
for a in desc_reqs ret_val.push_back(g);
.iter()
.filter(|name| !p.positionals.values().any(|p| &&p.b.name == name))
.filter(|name| !p.groups.iter().any(|g| &&g.name == name))
.filter(|name| !args_in_groups.contains(name))
.filter(|name| {
!(matcher.is_some() && matcher.as_ref().unwrap().contains(name))
}) {
debugln!("usage::get_required_usage_from:iter:{}:", a);
let arg = find_by_name!(p, *a, flags, iter)
.map(|f| f.to_string())
.unwrap_or_else(|| {
find_by_name!(p, *a, opts, iter)
.map(|o| o.to_string())
.expect(INTERNAL_ERROR_MSG)
});
ret_val.push_back(arg);
}
let mut g_vec: Vec<String> = vec![];
for g in desc_reqs
.iter()
.filter(|n| p.groups.iter().any(|g| &&g.name == n))
{
let g_string = p.args_in_group(g).join("|");
let elem = format!("<{}>", &g_string[..g_string.len()]);
if !g_vec.contains(&elem) {
g_vec.push(elem);
} }
}
for g in g_vec {
ret_val.push_back(g);
}
ret_val ret_val
}
} }

View file

@ -1,12 +1,11 @@
// std // std
use std::fmt::Display;
#[allow(unused_imports)] #[allow(unused_imports)]
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
// Internal // Internal
use INTERNAL_ERROR_MSG; use INTERNAL_ERROR_MSG;
use INVALID_UTF8; use INVALID_UTF8;
use args::{AnyArg, ArgMatcher, MatchedArg}; use args::{Arg, ArgMatcher, MatchedArg};
use args::settings::ArgSettings; use args::settings::ArgSettings;
use errors::{Error, ErrorKind}; use errors::{Error, ErrorKind};
use errors::Result as ClapResult; use errors::Result as ClapResult;
@ -14,15 +13,16 @@ use osstringext::OsStrExt2;
use app::settings::AppSettings as AS; use app::settings::AppSettings as AS;
use app::parser::{ParseResult, Parser}; use app::parser::{ParseResult, Parser};
use fmt::{Colorizer, ColorizerOption}; use fmt::{Colorizer, ColorizerOption};
use app::usage; use app::usage::Usage;
pub struct Validator<'a, 'b, 'z>(&'z mut Parser<'a, 'b>) pub struct Validator<'a, 'b, 'c, 'z>(&'z mut Parser<'a, 'b, 'c>)
where where
'a: 'b, 'a: 'b,
'b: 'z; 'b: 'c,
'c: 'z;
impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
pub fn new(p: &'z mut Parser<'a, 'b>) -> Self { Validator(p) } pub fn new(p: &'z mut Parser<'a, 'b, 'c>) -> Self { Validator(p) }
pub fn validate( pub fn validate(
&mut self, &mut self,
@ -36,23 +36,19 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
self.0.add_defaults(matcher)?; self.0.add_defaults(matcher)?;
if let ParseResult::Opt(a) = needs_val_of { if let ParseResult::Opt(a) = needs_val_of {
debugln!("Validator::validate: needs_val_of={:?}", a); debugln!("Validator::validate: needs_val_of={:?}", a);
let o = self.0 let o = find!(self.0.app, &a).expect(INTERNAL_ERROR_MSG);
.opts
.iter()
.find(|o| o.b.name == a)
.expect(INTERNAL_ERROR_MSG);
self.validate_required(matcher)?; self.validate_required(matcher)?;
reqs_validated = true; reqs_validated = true;
let should_err = if let Some(v) = matcher.0.args.get(&*o.b.name) { let should_err = if let Some(v) = matcher.0.args.get(&*o.name) {
v.vals.is_empty() && !(o.v.min_vals.is_some() && o.v.min_vals.unwrap() == 0) v.vals.is_empty() && !(o.min_vals.is_some() && o.min_vals.unwrap() == 0)
} else { } else {
true true
}; };
if should_err { if should_err {
return Err(Error::empty_value( return Err(Error::empty_value(
o, o,
&*usage::create_error_usage(self.0, matcher, None), &*Usage::new(self.0).create_error_usage(matcher, None),
self.0.color(), self.0.app.color(),
)); ));
} }
} }
@ -73,21 +69,18 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
self.validate_required(matcher)?; self.validate_required(matcher)?;
} }
self.validate_matched_args(matcher)?; self.validate_matched_args(matcher)?;
matcher.usage(usage::create_usage_with_title(self.0, &[])); matcher.usage(Usage::new(self.0).create_usage_with_title(&[]));
Ok(()) Ok(())
} }
fn validate_arg_values<A>( fn validate_arg_values(
&self, &self,
arg: &A, arg: &Arg,
ma: &MatchedArg, ma: &MatchedArg,
matcher: &ArgMatcher<'a>, matcher: &ArgMatcher<'a>,
) -> ClapResult<()> ) -> ClapResult<()> {
where debugln!("Validator::validate_arg_values: arg={:?}", arg.name);
A: AnyArg<'a, 'b> + Display,
{
debugln!("Validator::validate_arg_values: arg={:?}", arg.name());
for val in &ma.vals { for val in &ma.vals {
if self.0.is_set(AS::StrictUtf8) && val.to_str().is_none() { if self.0.is_set(AS::StrictUtf8) && val.to_str().is_none() {
debugln!( debugln!(
@ -95,11 +88,11 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
val val
); );
return Err(Error::invalid_utf8( return Err(Error::invalid_utf8(
&*usage::create_error_usage(self.0, matcher, None), &*Usage::new(self.0).create_error_usage(matcher, None),
self.0.color(), self.0.app.color(),
)); ));
} }
if let Some(p_vals) = arg.possible_vals() { if let Some(ref p_vals) = arg.possible_vals {
debugln!("Validator::validate_arg_values: possible_vals={:?}", p_vals); debugln!("Validator::validate_arg_values: possible_vals={:?}", p_vals);
let val_str = val.to_string_lossy(); let val_str = val.to_string_lossy();
let ok = if arg.is_set(ArgSettings::CaseInsensitive) { let ok = if arg.is_set(ArgSettings::CaseInsensitive) {
@ -112,38 +105,38 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
val_str, val_str,
p_vals, p_vals,
arg, arg,
&*usage::create_error_usage(self.0, matcher, None), &*Usage::new(self.0).create_error_usage(matcher, None),
self.0.color(), self.0.app.color(),
)); ));
} }
} }
if !arg.is_set(ArgSettings::EmptyValues) && val.is_empty_() if !arg.is_set(ArgSettings::EmptyValues) && val.is_empty_()
&& matcher.contains(&*arg.name()) && matcher.contains(&*arg.name)
{ {
debugln!("Validator::validate_arg_values: illegal empty val found"); debugln!("Validator::validate_arg_values: illegal empty val found");
return Err(Error::empty_value( return Err(Error::empty_value(
arg, arg,
&*usage::create_error_usage(self.0, matcher, None), &*Usage::new(self.0).create_error_usage(matcher, None),
self.0.color(), self.0.app.color(),
)); ));
} }
if let Some(vtor) = arg.validator() { if let Some(ref vtor) = arg.validator {
debug!("Validator::validate_arg_values: checking validator..."); debug!("Validator::validate_arg_values: checking validator...");
if let Err(e) = vtor(val.to_string_lossy().into_owned()) { if let Err(e) = vtor(val.to_string_lossy().into_owned()) {
sdebugln!("error"); sdebugln!("error");
return Err(Error::value_validation(Some(arg), e, self.0.color())); return Err(Error::value_validation(Some(arg), e, self.0.app.color()));
} else { } else {
sdebugln!("good"); sdebugln!("good");
} }
} }
if let Some(vtor) = arg.validator_os() { if let Some(ref vtor) = arg.validator_os {
debug!("Validator::validate_arg_values: checking validator_os..."); debug!("Validator::validate_arg_values: checking validator_os...");
if let Err(e) = vtor(val) { if let Err(e) = vtor(val) {
sdebugln!("error"); sdebugln!("error");
return Err(Error::value_validation( return Err(Error::value_validation(
Some(arg), Some(arg),
(*e).to_string_lossy().to_string(), (*e).to_string_lossy().to_string(),
self.0.color(), self.0.app.color(),
)); ));
} else { } else {
sdebugln!("good"); sdebugln!("good");
@ -153,106 +146,50 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
Ok(()) Ok(())
} }
fn build_err(&self, name: &str, matcher: &ArgMatcher) -> ClapResult<()> { fn build_conflict_err(&self, name: &str, matcher: &ArgMatcher<'a>) -> ClapResult<()> {
debugln!("build_err!: name={}", name); debugln!("build_err!: name={}", name);
let mut c_with = find_from!(self.0, &name, blacklist, &matcher); let mut c_with = find_from!(self.0.app, &name, blacklist, &matcher);
c_with = c_with.or( c_with = c_with.or(find!(self.0.app, &name)
self.0.find_any_arg(&name).map_or(None, |aa| aa.blacklist()) .map_or(None, |ref aa| aa.blacklist.as_ref())
.map_or(None, .map_or(None, |ref bl| bl.iter().find(|arg| matcher.contains(arg)))
|bl| bl.iter().find(|arg| matcher.contains(arg))) .map_or(None, |an| find!(self.0.app, an))
.map_or(None, |an| self.0.find_any_arg(an)) .map_or(None, |aa| Some(format!("{}", aa))));
.map_or(None, |aa| Some(format!("{}", aa)))
);
debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, &name); debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, &name);
// matcher.remove(&name); // matcher.remove(&name);
let usg = usage::create_error_usage(self.0, matcher, None); let usg = Usage::new(self.0).create_error_usage(matcher, None);
if let Some(f) = find_by_name!(self.0, name, flags, iter) { if let Some(f) = find!(self.0.app, &name) {
debugln!("build_err!: It was a flag..."); debugln!("build_err!: It was a flag...");
Err(Error::argument_conflict(f, c_with, &*usg, self.0.color())) Err(Error::argument_conflict(
} else if let Some(o) = find_by_name!(self.0, name, opts, iter) { f,
debugln!("build_err!: It was an option..."); c_with,
Err(Error::argument_conflict(o, c_with, &*usg, self.0.color())) &*usg,
self.0.app.color(),
))
} else { } else {
match find_by_name!(self.0, name, positionals, values) { panic!(INTERNAL_ERROR_MSG);
Some(p) => {
debugln!("build_err!: It was a positional...");
Err(Error::argument_conflict(p, c_with, &*usg, self.0.color()))
},
None => panic!(INTERNAL_ERROR_MSG)
}
} }
} }
fn validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()> { fn validate_blacklist(&self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
debugln!("Validator::validate_blacklist;"); debugln!("Validator::validate_blacklist;");
let mut conflicts: Vec<&str> = vec![]; for name in &self.gather_conflicts(matcher) {
for (&name, _) in matcher.iter() {
debugln!("Validator::validate_blacklist:iter:{};", name); debugln!("Validator::validate_blacklist:iter:{};", name);
if let Some(grps) = self.0.groups_for_arg(name) {
for grp in &grps {
if let Some(g) = self.0.groups.iter().find(|g| &g.name == grp) {
if !g.multiple {
for arg in &g.args {
if arg == &name {
continue;
}
conflicts.push(arg);
}
}
if let Some(ref gc) = g.conflicts {
conflicts.extend(&*gc);
}
}
}
}
if let Some(arg) = find_any_by_name!(self.0, name) {
if let Some(bl) = arg.blacklist() {
for conf in bl {
if matcher.get(conf).is_some() {
conflicts.push(conf);
}
}
}
} else {
debugln!("Validator::validate_blacklist:iter:{}:group;", name);
let args = self.0.arg_names_in_group(name);
for arg in &args {
debugln!("Validator::validate_blacklist:iter:{}:group:iter:{};", name, arg);
if let Some(bl) = find_any_by_name!(self.0, *arg).unwrap().blacklist() {
for conf in bl {
if matcher.get(conf).is_some() {
conflicts.push(conf);
}
}
}
}
}
}
for name in &conflicts {
debugln!(
"Validator::validate_blacklist:iter:{}: Checking blacklisted arg",
name
);
let mut should_err = false; let mut should_err = false;
if self.0.groups.iter().any(|g| &g.name == name) { if groups!(self.0.app).any(|g| &g.name == name) {
debugln!( debugln!("Validator::validate_blacklist:iter:{}:group;", name);
"Validator::validate_blacklist:iter:{}: groups contains it...",
name
);
for n in self.0.arg_names_in_group(name) { for n in self.0.arg_names_in_group(name) {
debugln!( debugln!(
"Validator::validate_blacklist:iter:{}:iter:{}: looking in group...", "Validator::validate_blacklist:iter:{}:group:iter:{};",
name, name,
n n
); );
if matcher.contains(n) { if matcher.contains(n) {
debugln!( debugln!(
"Validator::validate_blacklist:iter:{}:iter:{}: matcher contains it...", "Validator::validate_blacklist:iter:{}:group:iter:{}: found;",
name, name,
n n
); );
return self.build_err(n, matcher); return self.build_conflict_err(n, matcher);
} }
} }
} else if let Some(ma) = matcher.get(name) { } else if let Some(ma) = matcher.get(name) {
@ -263,12 +200,66 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
should_err = ma.occurs > 0; should_err = ma.occurs > 0;
} }
if should_err { if should_err {
return self.build_err(*name, matcher); return self.build_conflict_err(*name, matcher);
} }
} }
Ok(()) Ok(())
} }
fn gather_conflicts(&self, matcher: &mut ArgMatcher<'a>) -> Vec<&'a str> {
debugln!("Validator::gather_conflicts;");
let mut conflicts = vec![];
for name in matcher.arg_names() {
debugln!("Validator::gather_conflicts:iter:{};", name);
if let Some(arg) = find!(self.0.app, name) {
if let Some(ref bl) = arg.blacklist {
for conf in bl {
if matcher.get(conf).is_some() {
conflicts.push(*conf);
}
}
}
if let Some(grps) = self.0.groups_for_arg(name) {
for grp in &grps {
if let Some(g) = find!(self.0.app, grp, groups) {
if !g.multiple {
for g_arg in &g.args {
if &g_arg == &name {
continue;
}
conflicts.push(g_arg);
}
}
if let Some(ref gc) = g.conflicts {
conflicts.extend(&*gc);
}
}
}
}
} else {
debugln!("Validator::gather_conflicts:iter:{}:group;", name);
let args = self.0.arg_names_in_group(name);
for arg in &args {
debugln!(
"Validator::gather_conflicts:iter:{}:group:iter:{};",
name,
arg
);
if let Some(ref bl) =
find!(self.0.app, arg).expect(INTERNAL_ERROR_MSG).blacklist
{
for conf in bl {
if matcher.get(conf).is_some() {
conflicts.push(conf);
}
}
}
}
}
}
conflicts
}
fn validate_matched_args(&self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> { fn validate_matched_args(&self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
debugln!("Validator::validate_matched_args;"); debugln!("Validator::validate_matched_args;");
for (name, ma) in matcher.iter() { for (name, ma) in matcher.iter() {
@ -277,25 +268,13 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
name, name,
ma.vals ma.vals
); );
if let Some(opt) = find_by_name!(self.0, *name, opts, iter) { if let Some(arg) = find!(self.0.app, name) {
self.validate_arg_num_vals(opt, ma, matcher)?; self.validate_arg_num_vals(arg, ma, matcher)?;
self.validate_arg_values(opt, ma, matcher)?; self.validate_arg_values(arg, ma, matcher)?;
self.validate_arg_requires(opt, ma, matcher)?; self.validate_arg_requires(arg, ma, matcher)?;
self.validate_arg_num_occurs(opt, ma, matcher)?; self.validate_arg_num_occurs(arg, ma, matcher)?;
} else if let Some(flag) = find_by_name!(self.0, *name, flags, iter) {
self.validate_arg_requires(flag, ma, matcher)?;
self.validate_arg_num_occurs(flag, ma, matcher)?;
} else if let Some(pos) = find_by_name!(self.0, *name, positionals, values) {
self.validate_arg_num_vals(pos, ma, matcher)?;
self.validate_arg_num_occurs(pos, ma, matcher)?;
self.validate_arg_values(pos, ma, matcher)?;
self.validate_arg_requires(pos, ma, matcher)?;
} else { } else {
let grp = self.0 let grp = find!(self.0.app, name, groups).expect(INTERNAL_ERROR_MSG);
.groups
.iter()
.find(|g| &g.name == name)
.expect(INTERNAL_ERROR_MSG);
if let Some(ref g_reqs) = grp.requires { if let Some(ref g_reqs) = grp.requires {
if g_reqs.iter().any(|&n| !matcher.contains(n)) { if g_reqs.iter().any(|&n| !matcher.contains(n)) {
return self.missing_required_error(matcher, None); return self.missing_required_error(matcher, None);
@ -306,38 +285,32 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
Ok(()) Ok(())
} }
fn validate_arg_num_occurs<A>( fn validate_arg_num_occurs(
&self, &self,
a: &A, a: &Arg,
ma: &MatchedArg, ma: &MatchedArg,
matcher: &ArgMatcher, matcher: &ArgMatcher<'a>,
) -> ClapResult<()> ) -> ClapResult<()> {
where debugln!("Validator::validate_arg_num_occurs: a={};", a.name);
A: AnyArg<'a, 'b> + Display,
{
debugln!("Validator::validate_arg_num_occurs: a={};", a.name());
if ma.occurs > 1 && !a.is_set(ArgSettings::Multiple) { if ma.occurs > 1 && !a.is_set(ArgSettings::Multiple) {
// Not the first time, and we don't allow multiples // Not the first time, and we don't allow multiples
return Err(Error::unexpected_multiple_usage( return Err(Error::unexpected_multiple_usage(
a, a,
&*usage::create_error_usage(self.0, matcher, None), &*Usage::new(self.0).create_error_usage(matcher, None),
self.0.color(), self.0.app.color(),
)); ));
} }
Ok(()) Ok(())
} }
fn validate_arg_num_vals<A>( fn validate_arg_num_vals(
&self, &self,
a: &A, a: &Arg,
ma: &MatchedArg, ma: &MatchedArg,
matcher: &ArgMatcher, matcher: &ArgMatcher<'a>,
) -> ClapResult<()> ) -> ClapResult<()> {
where
A: AnyArg<'a, 'b> + Display,
{
debugln!("Validator::validate_arg_num_vals;"); debugln!("Validator::validate_arg_num_vals;");
if let Some(num) = a.num_vals() { if let Some(num) = a.num_vals {
debugln!("Validator::validate_arg_num_vals: num_vals set...{}", num); debugln!("Validator::validate_arg_num_vals: num_vals set...{}", num);
let should_err = if a.is_set(ArgSettings::Multiple) { let should_err = if a.is_set(ArgSettings::Multiple) {
((ma.vals.len() as u64) % num) != 0 ((ma.vals.len() as u64) % num) != 0
@ -361,12 +334,12 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
} else { } else {
"ere" "ere"
}, },
&*usage::create_error_usage(self.0, matcher, None), &*Usage::new(self.0).create_error_usage(matcher, None),
self.0.color(), self.0.app.color(),
)); ));
} }
} }
if let Some(num) = a.max_vals() { if let Some(num) = a.max_vals {
debugln!("Validator::validate_arg_num_vals: max_vals set...{}", num); debugln!("Validator::validate_arg_num_vals: max_vals set...{}", num);
if (ma.vals.len() as u64) > num { if (ma.vals.len() as u64) > num {
debugln!("Validator::validate_arg_num_vals: Sending error TooManyValues"); debugln!("Validator::validate_arg_num_vals: Sending error TooManyValues");
@ -378,12 +351,12 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
.to_str() .to_str()
.expect(INVALID_UTF8), .expect(INVALID_UTF8),
a, a,
&*usage::create_error_usage(self.0, matcher, None), &*Usage::new(self.0).create_error_usage(matcher, None),
self.0.color(), self.0.app.color(),
)); ));
} }
} }
let min_vals_zero = if let Some(num) = a.min_vals() { let min_vals_zero = if let Some(num) = a.min_vals {
debugln!("Validator::validate_arg_num_vals: min_vals set: {}", num); debugln!("Validator::validate_arg_num_vals: min_vals set: {}", num);
if (ma.vals.len() as u64) < num && num != 0 { if (ma.vals.len() as u64) < num && num != 0 {
debugln!("Validator::validate_arg_num_vals: Sending error TooFewValues"); debugln!("Validator::validate_arg_num_vals: Sending error TooFewValues");
@ -391,8 +364,8 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
a, a,
num, num,
ma.vals.len(), ma.vals.len(),
&*usage::create_error_usage(self.0, matcher, None), &*Usage::new(self.0).create_error_usage(matcher, None),
self.0.color(), self.0.app.color(),
)); ));
} }
num == 0 num == 0
@ -401,27 +374,24 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
}; };
// Issue 665 (https://github.com/kbknapp/clap-rs/issues/665) // Issue 665 (https://github.com/kbknapp/clap-rs/issues/665)
// Issue 1105 (https://github.com/kbknapp/clap-rs/issues/1105) // Issue 1105 (https://github.com/kbknapp/clap-rs/issues/1105)
if a.takes_value() && !min_vals_zero && ma.vals.is_empty() { if a.is_set(ArgSettings::TakesValue) && !min_vals_zero && ma.vals.is_empty() {
return Err(Error::empty_value( return Err(Error::empty_value(
a, a,
&*usage::create_error_usage(self.0, matcher, None), &*Usage::new(self.0).create_error_usage(matcher, None),
self.0.color(), self.0.app.color(),
)); ));
} }
Ok(()) Ok(())
} }
fn validate_arg_requires<A>( fn validate_arg_requires(
&self, &self,
a: &A, a: &Arg,
ma: &MatchedArg, ma: &MatchedArg,
matcher: &ArgMatcher, matcher: &ArgMatcher<'a>,
) -> ClapResult<()> ) -> ClapResult<()> {
where debugln!("Validator::validate_arg_requires:{};", a.name);
A: AnyArg<'a, 'b> + Display, if let Some(ref a_reqs) = a.requires {
{
debugln!("Validator::validate_arg_requires:{};", a.name());
if let Some(a_reqs) = a.requires() {
for &(val, name) in a_reqs.iter().filter(|&&(val, _)| val.is_some()) { for &(val, name) in a_reqs.iter().filter(|&&(val, _)| val.is_some()) {
let missing_req = let missing_req =
|v| v == val.expect(INTERNAL_ERROR_MSG) && !matcher.contains(name); |v| v == val.expect(INTERNAL_ERROR_MSG) && !matcher.contains(name);
@ -438,7 +408,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
Ok(()) Ok(())
} }
fn validate_required(&self, matcher: &ArgMatcher) -> ClapResult<()> { fn validate_required(&self, matcher: &ArgMatcher<'a>) -> ClapResult<()> {
debugln!( debugln!(
"Validator::validate_required: required={:?};", "Validator::validate_required: required={:?};",
self.0.required self.0.required
@ -449,7 +419,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
if matcher.contains(name) { if matcher.contains(name) {
continue 'outer; continue 'outer;
} }
if let Some(a) = find_any_by_name!(self.0, *name) { if let Some(a) = find!(self.0.app, name) {
if self.is_missing_required_ok(a, matcher) { if self.is_missing_required_ok(a, matcher) {
continue 'outer; continue 'outer;
} }
@ -468,28 +438,32 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
Ok(()) Ok(())
} }
fn validate_arg_conflicts(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option<bool> { fn is_missing_required_ok(&self, a: &Arg<'a, 'b>, matcher: &ArgMatcher<'a>) -> bool {
debugln!("Validator::validate_arg_conflicts: a={:?};", a.name()); debugln!("Validator::is_missing_required_ok: a={}", a.name);
a.blacklist().map(|bl| { self.validate_arg_conflicts(a, matcher).unwrap_or(false)
bl.iter().any(|conf| { || self.validate_required_unless(a, matcher).unwrap_or(false)
|| self.0.overriden.contains(&a.name)
}
fn validate_arg_conflicts(&self, a: &Arg<'a, 'b>, matcher: &ArgMatcher<'a>) -> Option<bool> {
debugln!("Validator::validate_arg_conflicts: a={:?};", a.name);
a.blacklist.as_ref().map(|bl| {
bl.iter().any(|ref conf| {
matcher.contains(conf) matcher.contains(conf)
|| self.0 || find!(self.0.app, *conf, groups)
.groups
.iter()
.find(|g| &g.name == conf)
.map_or(false, |g| g.args.iter().any(|arg| matcher.contains(arg))) .map_or(false, |g| g.args.iter().any(|arg| matcher.contains(arg)))
}) })
}) })
} }
fn validate_required_unless(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option<bool> { fn validate_required_unless(&self, a: &Arg<'a, 'b>, matcher: &ArgMatcher<'a>) -> Option<bool> {
debugln!("Validator::validate_required_unless: a={:?};", a.name()); debugln!("Validator::validate_required_unless: a={:?};", a.name);
macro_rules! check { macro_rules! check {
($how:ident, $_self:expr, $a:ident, $m:ident) => {{ ($how:ident, $_self:expr, $a:ident, $m:ident) => {{
$a.required_unless().map(|ru| { $a.r_unless.as_ref().map(|ru| {
ru.iter().$how(|n| { ru.iter().$how(|n| {
$m.contains(n) || { $m.contains(n) || {
if let Some(grp) = $_self.groups.iter().find(|g| &g.name == n) { if let Some(grp) = find!($_self.app, n, groups) {
grp.args.iter().any(|arg| $m.contains(arg)) grp.args.iter().any(|arg| $m.contains(arg))
} else { } else {
false false
@ -506,11 +480,15 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
} }
} }
fn missing_required_error(&self, matcher: &ArgMatcher, extra: Option<&str>) -> ClapResult<()> { fn missing_required_error(
&self,
matcher: &ArgMatcher<'a>,
extra: Option<&str>,
) -> ClapResult<()> {
debugln!("Validator::missing_required_error: extra={:?}", extra); debugln!("Validator::missing_required_error: extra={:?}", extra);
let c = Colorizer::new(ColorizerOption { let c = Colorizer::new(ColorizerOption {
use_stderr: true, use_stderr: true,
when: self.0.color(), when: self.0.app.color(),
}); });
let mut reqs = self.0.required.iter().map(|&r| &*r).collect::<Vec<_>>(); let mut reqs = self.0.required.iter().map(|&r| &*r).collect::<Vec<_>>();
if let Some(r) = extra { if let Some(r) = extra {
@ -519,27 +497,20 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
reqs.retain(|n| !matcher.contains(n)); reqs.retain(|n| !matcher.contains(n));
reqs.dedup(); reqs.dedup();
debugln!("Validator::missing_required_error: reqs={:#?}", reqs); debugln!("Validator::missing_required_error: reqs={:#?}", reqs);
let req_args = let req_args = Usage::new(self.0)
usage::get_required_usage_from(self.0, &reqs[..], Some(matcher), extra, true) .get_required_usage_from(&reqs[..], Some(matcher), extra, true)
.iter() .iter()
.fold(String::new(), |acc, s| { .fold(String::new(), |acc, s| {
acc + &format!("\n {}", c.error(s))[..] acc + &format!("\n {}", c.error(s))[..]
}); });
debugln!( debugln!(
"Validator::missing_required_error: req_args={:#?}", "Validator::missing_required_error: req_args={:#?}",
req_args req_args
); );
Err(Error::missing_required_argument( Err(Error::missing_required_argument(
&*req_args, &*req_args,
&*usage::create_error_usage(self.0, matcher, extra), &*Usage::new(self.0).create_error_usage(matcher, extra),
self.0.color(), self.0.app.color(),
)) ))
} }
#[inline]
fn is_missing_required_ok(&self, a: &AnyArg, matcher: &ArgMatcher) -> bool {
debugln!("Validator::is_missing_required_ok: a={}", a.name());
self.validate_arg_conflicts(a, matcher).unwrap_or(false)
|| self.validate_required_unless(a, matcher).unwrap_or(false)
}
} }

View file

@ -1,74 +0,0 @@
// Std
use std::rc::Rc;
use std::fmt as std_fmt;
use std::ffi::{OsStr, OsString};
// Internal
use args::settings::ArgSettings;
use map::{self, VecMap};
use INTERNAL_ERROR_MSG;
#[doc(hidden)]
pub trait AnyArg<'n, 'e>: std_fmt::Display {
fn name(&self) -> &'n str;
fn overrides(&self) -> Option<&[&'e str]>;
fn aliases(&self) -> Option<Vec<&'e str>>;
fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]>;
fn blacklist(&self) -> Option<&[&'e str]>;
fn required_unless(&self) -> Option<&[&'e str]>;
fn is_set(&self, ArgSettings) -> bool;
fn set(&mut self, ArgSettings);
fn has_switch(&self) -> bool;
fn max_vals(&self) -> Option<u64>;
fn min_vals(&self) -> Option<u64>;
fn num_vals(&self) -> Option<u64>;
fn possible_vals(&self) -> Option<&[&'e str]>;
fn validator(&self) -> Option<&Rc<Fn(String) -> Result<(), String>>>;
fn validator_os(&self) -> Option<&Rc<Fn(&OsStr) -> Result<(), OsString>>>;
fn short(&self) -> Option<char>;
fn long(&self) -> Option<&'e str>;
fn val_delim(&self) -> Option<char>;
fn takes_value(&self) -> bool;
fn val_names(&self) -> Option<&VecMap<&'e str>>;
fn help(&self) -> Option<&'e str>;
fn long_help(&self) -> Option<&'e str>;
fn default_val(&self) -> Option<&'e OsStr>;
fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>>;
fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)>;
fn longest_filter(&self) -> bool;
fn val_terminator(&self) -> Option<&'e str>;
}
pub trait DispOrder {
fn disp_ord(&self) -> usize;
}
impl<'n, 'e, 'z, T: ?Sized> AnyArg<'n, 'e> for &'z T where T: AnyArg<'n, 'e> + 'z {
fn name(&self) -> &'n str { (*self).name() }
fn overrides(&self) -> Option<&[&'e str]> { (*self).overrides() }
fn aliases(&self) -> Option<Vec<&'e str>> { (*self).aliases() }
fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> { (*self).requires() }
fn blacklist(&self) -> Option<&[&'e str]> { (*self).blacklist() }
fn required_unless(&self) -> Option<&[&'e str]> { (*self).required_unless() }
fn is_set(&self, a: ArgSettings) -> bool { (*self).is_set(a) }
fn set(&mut self, _: ArgSettings) { panic!(INTERNAL_ERROR_MSG) }
fn has_switch(&self) -> bool { (*self).has_switch() }
fn max_vals(&self) -> Option<u64> { (*self).max_vals() }
fn min_vals(&self) -> Option<u64> { (*self).min_vals() }
fn num_vals(&self) -> Option<u64> { (*self).num_vals() }
fn possible_vals(&self) -> Option<&[&'e str]> { (*self).possible_vals() }
fn validator(&self) -> Option<&Rc<Fn(String) -> Result<(), String>>> { (*self).validator() }
fn validator_os(&self) -> Option<&Rc<Fn(&OsStr) -> Result<(), OsString>>> { (*self).validator_os() }
fn short(&self) -> Option<char> { (*self).short() }
fn long(&self) -> Option<&'e str> { (*self).long() }
fn val_delim(&self) -> Option<char> { (*self).val_delim() }
fn takes_value(&self) -> bool { (*self).takes_value() }
fn val_names(&self) -> Option<&VecMap<&'e str>> { (*self).val_names() }
fn help(&self) -> Option<&'e str> { (*self).help() }
fn long_help(&self) -> Option<&'e str> { (*self).long_help() }
fn default_val(&self) -> Option<&'e OsStr> { (*self).default_val() }
fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> { (*self).default_vals_ifs() }
fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> { (*self).env() }
fn longest_filter(&self) -> bool { (*self).longest_filter() }
fn val_terminator(&self) -> Option<&'e str> { (*self).val_terminator() }
}

View file

@ -1,20 +1,23 @@
#[cfg(feature = "yaml")] #[cfg(feature = "yaml")]
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::rc::Rc; use std::rc::Rc;
use std::borrow::Cow;
use std::fmt::{self, Display, Formatter};
use std::ffi::{OsStr, OsString}; use std::ffi::{OsStr, OsString};
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use osstringext::OsStrExt3; use osstringext::OsStrExt3;
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStrExt;
use std::env; use std::env;
use std::cmp::{Ord, Ordering};
#[cfg(feature = "yaml")] #[cfg(feature = "yaml")]
use yaml_rust::Yaml; use yaml_rust::Yaml;
use map::VecMap; use map::VecMap;
use usage_parser::UsageParser; use usage_parser::UsageParser;
use args::settings::ArgSettings; use args::settings::{ArgFlags, ArgSettings};
use args::arg_builder::{Base, Switched, Valued}; use INTERNAL_ERROR_MSG;
/// The abstract representation of a command line argument. Used to set all the options and /// The abstract representation of a command line argument. Used to set all the options and
/// relationships that define a valid argument for the program. /// relationships that define a valid argument for the program.
@ -44,11 +47,62 @@ pub struct Arg<'a, 'b>
where where
'a: 'b, 'a: 'b,
{ {
#[doc(hidden)] pub b: Base<'a, 'b>, #[doc(hidden)]
#[doc(hidden)] pub s: Switched<'b>, pub name: &'a str,
#[doc(hidden)] pub v: Valued<'a, 'b>, #[doc(hidden)]
#[doc(hidden)] pub index: Option<u64>, pub help: Option<&'b str>,
#[doc(hidden)] pub r_ifs: Option<Vec<(&'a str, &'b str)>>, #[doc(hidden)]
pub long_help: Option<&'b str>,
#[doc(hidden)]
pub blacklist: Option<Vec<&'a str>>,
#[doc(hidden)]
pub settings: ArgFlags,
#[doc(hidden)]
pub r_unless: Option<Vec<&'a str>>,
#[doc(hidden)]
pub overrides: Option<Vec<&'a str>>,
#[doc(hidden)]
pub groups: Option<Vec<&'a str>>,
#[doc(hidden)]
pub requires: Option<Vec<(Option<&'b str>, &'a str)>>,
#[doc(hidden)]
pub short: Option<char>,
#[doc(hidden)]
pub long: Option<&'b str>,
#[doc(hidden)]
pub aliases: Option<Vec<(&'b str, bool)>>, // (name, visible)
#[doc(hidden)]
pub disp_ord: usize,
#[doc(hidden)]
pub unified_ord: usize,
#[doc(hidden)]
pub possible_vals: Option<Vec<&'b str>>,
#[doc(hidden)]
pub val_names: Option<VecMap<&'b str>>,
#[doc(hidden)]
pub num_vals: Option<u64>,
#[doc(hidden)]
pub max_vals: Option<u64>,
#[doc(hidden)]
pub min_vals: Option<u64>,
#[doc(hidden)]
pub validator: Option<Rc<Fn(String) -> Result<(), String>>>,
#[doc(hidden)]
pub validator_os: Option<Rc<Fn(&OsStr) -> Result<(), OsString>>>,
#[doc(hidden)]
pub val_delim: Option<char>,
#[doc(hidden)]
pub default_val: Option<&'b OsStr>,
#[doc(hidden)]
pub default_vals_ifs: Option<VecMap<(&'a str, Option<&'b OsStr>, &'b OsStr)>>,
#[doc(hidden)]
pub env: Option<(&'a OsStr, Option<OsString>)>,
#[doc(hidden)]
pub terminator: Option<&'b str>,
#[doc(hidden)]
pub index: Option<u64>,
#[doc(hidden)]
pub r_ifs: Option<Vec<(&'a str, &'b str)>>,
} }
impl<'a, 'b> Arg<'a, 'b> { impl<'a, 'b> Arg<'a, 'b> {
@ -71,7 +125,9 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg`]: ./struct.Arg.html /// [`Arg`]: ./struct.Arg.html
pub fn with_name(n: &'a str) -> Self { pub fn with_name(n: &'a str) -> Self {
Arg { Arg {
b: Base::new(n), name: n,
disp_ord: 999,
unified_ord: 999,
..Default::default() ..Default::default()
} }
} }
@ -146,8 +202,7 @@ impl<'a, 'b> Arg<'a, 'b> {
} }
s => panic!( s => panic!(
"Unknown Arg setting '{}' in YAML file for arg '{}'", "Unknown Arg setting '{}' in YAML file for arg '{}'",
s, s, name_str
name_str
), ),
} }
} }
@ -328,7 +383,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ``` /// ```
/// [`short`]: ./struct.Arg.html#method.short /// [`short`]: ./struct.Arg.html#method.short
pub fn short<S: AsRef<str>>(mut self, s: S) -> Self { pub fn short<S: AsRef<str>>(mut self, s: S) -> Self {
self.s.short = s.as_ref().trim_left_matches(|c| c == '-').chars().nth(0); self.short = s.as_ref().trim_left_matches(|c| c == '-').chars().nth(0);
self self
} }
@ -368,7 +423,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// assert!(m.is_present("cfg")); /// assert!(m.is_present("cfg"));
/// ``` /// ```
pub fn long(mut self, l: &'b str) -> Self { pub fn long(mut self, l: &'b str) -> Self {
self.s.long = Some(l.trim_left_matches(|c| c == '-')); self.long = Some(l.trim_left_matches(|c| c == '-'));
self self
} }
@ -394,10 +449,10 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ``` /// ```
/// [`Arg`]: ./struct.Arg.html /// [`Arg`]: ./struct.Arg.html
pub fn alias<S: Into<&'b str>>(mut self, name: S) -> Self { pub fn alias<S: Into<&'b str>>(mut self, name: S) -> Self {
if let Some(ref mut als) = self.s.aliases { if let Some(ref mut als) = self.aliases {
als.push((name.into(), false)); als.push((name.into(), false));
} else { } else {
self.s.aliases = Some(vec![(name.into(), false)]); self.aliases = Some(vec![(name.into(), false)]);
} }
self self
} }
@ -424,12 +479,12 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ``` /// ```
/// [`Arg`]: ./struct.Arg.html /// [`Arg`]: ./struct.Arg.html
pub fn aliases(mut self, names: &[&'b str]) -> Self { pub fn aliases(mut self, names: &[&'b str]) -> Self {
if let Some(ref mut als) = self.s.aliases { if let Some(ref mut als) = self.aliases {
for n in names { for n in names {
als.push((n, false)); als.push((n, false));
} }
} else { } else {
self.s.aliases = Some(names.iter().map(|n| (*n, false)).collect::<Vec<_>>()); self.aliases = Some(names.iter().map(|n| (*n, false)).collect::<Vec<_>>());
} }
self self
} }
@ -455,10 +510,10 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg`]: ./struct.Arg.html /// [`Arg`]: ./struct.Arg.html
/// [`App::alias`]: ./struct.Arg.html#method.alias /// [`App::alias`]: ./struct.Arg.html#method.alias
pub fn visible_alias<S: Into<&'b str>>(mut self, name: S) -> Self { pub fn visible_alias<S: Into<&'b str>>(mut self, name: S) -> Self {
if let Some(ref mut als) = self.s.aliases { if let Some(ref mut als) = self.aliases {
als.push((name.into(), true)); als.push((name.into(), true));
} else { } else {
self.s.aliases = Some(vec![(name.into(), true)]); self.aliases = Some(vec![(name.into(), true)]);
} }
self self
} }
@ -482,12 +537,12 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg`]: ./struct.Arg.html /// [`Arg`]: ./struct.Arg.html
/// [`App::aliases`]: ./struct.Arg.html#method.aliases /// [`App::aliases`]: ./struct.Arg.html#method.aliases
pub fn visible_aliases(mut self, names: &[&'b str]) -> Self { pub fn visible_aliases(mut self, names: &[&'b str]) -> Self {
if let Some(ref mut als) = self.s.aliases { if let Some(ref mut als) = self.aliases {
for n in names { for n in names {
als.push((n, true)); als.push((n, true));
} }
} else { } else {
self.s.aliases = Some(names.iter().map(|n| (*n, true)).collect::<Vec<_>>()); self.aliases = Some(names.iter().map(|n| (*n, true)).collect::<Vec<_>>());
} }
self self
} }
@ -543,7 +598,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ``` /// ```
/// [`Arg::long_help`]: ./struct.Arg.html#method.long_help /// [`Arg::long_help`]: ./struct.Arg.html#method.long_help
pub fn help(mut self, h: &'b str) -> Self { pub fn help(mut self, h: &'b str) -> Self {
self.b.help = Some(h); self.help = Some(h);
self self
} }
@ -614,7 +669,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ``` /// ```
/// [`Arg::help`]: ./struct.Arg.html#method.help /// [`Arg::help`]: ./struct.Arg.html#method.help
pub fn long_help(mut self, h: &'b str) -> Self { pub fn long_help(mut self, h: &'b str) -> Self {
self.b.long_help = Some(h); self.long_help = Some(h);
self self
} }
@ -940,10 +995,10 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::required`]: ./struct.Arg.html#method.required /// [`Arg::required`]: ./struct.Arg.html#method.required
/// [`Arg::required_unless(name)`]: ./struct.Arg.html#method.required_unless /// [`Arg::required_unless(name)`]: ./struct.Arg.html#method.required_unless
pub fn required_unless(mut self, name: &'a str) -> Self { pub fn required_unless(mut self, name: &'a str) -> Self {
if let Some(ref mut vec) = self.b.r_unless { if let Some(ref mut vec) = self.r_unless {
vec.push(name); vec.push(name);
} else { } else {
self.b.r_unless = Some(vec![name]); self.r_unless = Some(vec![name]);
} }
self.required(true) self.required(true)
} }
@ -1012,12 +1067,12 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::required_unless_one`]: ./struct.Arg.html#method.required_unless_one /// [`Arg::required_unless_one`]: ./struct.Arg.html#method.required_unless_one
/// [`Arg::required_unless_all(names)`]: ./struct.Arg.html#method.required_unless_all /// [`Arg::required_unless_all(names)`]: ./struct.Arg.html#method.required_unless_all
pub fn required_unless_all(mut self, names: &[&'a str]) -> Self { pub fn required_unless_all(mut self, names: &[&'a str]) -> Self {
if let Some(ref mut vec) = self.b.r_unless { if let Some(ref mut vec) = self.r_unless {
for s in names { for s in names {
vec.push(s); vec.push(s);
} }
} else { } else {
self.b.r_unless = Some(names.iter().map(|s| *s).collect::<Vec<_>>()); self.r_unless = Some(names.iter().map(|s| *s).collect::<Vec<_>>());
} }
self.setb(ArgSettings::RequiredUnlessAll); self.setb(ArgSettings::RequiredUnlessAll);
self.required(true) self.required(true)
@ -1088,12 +1143,12 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::required_unless_one(names)`]: ./struct.Arg.html#method.required_unless_one /// [`Arg::required_unless_one(names)`]: ./struct.Arg.html#method.required_unless_one
/// [`Arg::required_unless_all`]: ./struct.Arg.html#method.required_unless_all /// [`Arg::required_unless_all`]: ./struct.Arg.html#method.required_unless_all
pub fn required_unless_one(mut self, names: &[&'a str]) -> Self { pub fn required_unless_one(mut self, names: &[&'a str]) -> Self {
if let Some(ref mut vec) = self.b.r_unless { if let Some(ref mut vec) = self.r_unless {
for s in names { for s in names {
vec.push(s); vec.push(s);
} }
} else { } else {
self.b.r_unless = Some(names.iter().map(|s| *s).collect::<Vec<_>>()); self.r_unless = Some(names.iter().map(|s| *s).collect::<Vec<_>>());
} }
self.required(true) self.required(true)
} }
@ -1136,10 +1191,10 @@ impl<'a, 'b> Arg<'a, 'b> {
/// assert_eq!(res.unwrap_err().kind, ErrorKind::ArgumentConflict); /// assert_eq!(res.unwrap_err().kind, ErrorKind::ArgumentConflict);
/// ``` /// ```
pub fn conflicts_with(mut self, name: &'a str) -> Self { pub fn conflicts_with(mut self, name: &'a str) -> Self {
if let Some(ref mut vec) = self.b.blacklist { if let Some(ref mut vec) = self.blacklist {
vec.push(name); vec.push(name);
} else { } else {
self.b.blacklist = Some(vec![name]); self.blacklist = Some(vec![name]);
} }
self self
} }
@ -1186,12 +1241,12 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ``` /// ```
/// [`Arg::conflicts_with`]: ./struct.Arg.html#method.conflicts_with /// [`Arg::conflicts_with`]: ./struct.Arg.html#method.conflicts_with
pub fn conflicts_with_all(mut self, names: &[&'a str]) -> Self { pub fn conflicts_with_all(mut self, names: &[&'a str]) -> Self {
if let Some(ref mut vec) = self.b.blacklist { if let Some(ref mut vec) = self.blacklist {
for s in names { for s in names {
vec.push(s); vec.push(s);
} }
} else { } else {
self.b.blacklist = Some(names.iter().map(|s| *s).collect::<Vec<_>>()); self.blacklist = Some(names.iter().map(|s| *s).collect::<Vec<_>>());
} }
self self
} }
@ -1223,10 +1278,10 @@ impl<'a, 'b> Arg<'a, 'b> {
/// assert!(!m.is_present("flag")); /// assert!(!m.is_present("flag"));
/// ``` /// ```
pub fn overrides_with(mut self, name: &'a str) -> Self { pub fn overrides_with(mut self, name: &'a str) -> Self {
if let Some(ref mut vec) = self.b.overrides { if let Some(ref mut vec) = self.overrides {
vec.push(name.as_ref()); vec.push(name.as_ref());
} else { } else {
self.b.overrides = Some(vec![name.as_ref()]); self.overrides = Some(vec![name.as_ref()]);
} }
self self
} }
@ -1259,12 +1314,12 @@ impl<'a, 'b> Arg<'a, 'b> {
/// assert!(!m.is_present("flag")); /// assert!(!m.is_present("flag"));
/// ``` /// ```
pub fn overrides_with_all(mut self, names: &[&'a str]) -> Self { pub fn overrides_with_all(mut self, names: &[&'a str]) -> Self {
if let Some(ref mut vec) = self.b.overrides { if let Some(ref mut vec) = self.overrides {
for s in names { for s in names {
vec.push(s); vec.push(s);
} }
} else { } else {
self.b.overrides = Some(names.iter().map(|s| *s).collect::<Vec<_>>()); self.overrides = Some(names.iter().map(|s| *s).collect::<Vec<_>>());
} }
self self
} }
@ -1325,12 +1380,12 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with /// [Conflicting]: ./struct.Arg.html#method.conflicts_with
/// [override]: ./struct.Arg.html#method.overrides_with /// [override]: ./struct.Arg.html#method.overrides_with
pub fn requires(mut self, name: &'a str) -> Self { pub fn requires(mut self, name: &'a str) -> Self {
if let Some(ref mut vec) = self.b.requires { if let Some(ref mut vec) = self.requires {
vec.push((None, name)); vec.push((None, name));
} else { } else {
let mut vec = vec![]; let mut vec = vec![];
vec.push((None, name)); vec.push((None, name));
self.b.requires = Some(vec); self.requires = Some(vec);
} }
self self
} }
@ -1395,10 +1450,10 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with /// [Conflicting]: ./struct.Arg.html#method.conflicts_with
/// [override]: ./struct.Arg.html#method.overrides_with /// [override]: ./struct.Arg.html#method.overrides_with
pub fn requires_if(mut self, val: &'b str, arg: &'a str) -> Self { pub fn requires_if(mut self, val: &'b str, arg: &'a str) -> Self {
if let Some(ref mut vec) = self.b.requires { if let Some(ref mut vec) = self.requires {
vec.push((Some(val), arg)); vec.push((Some(val), arg));
} else { } else {
self.b.requires = Some(vec![(Some(val), arg)]); self.requires = Some(vec![(Some(val), arg)]);
} }
self self
} }
@ -1455,7 +1510,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with /// [Conflicting]: ./struct.Arg.html#method.conflicts_with
/// [override]: ./struct.Arg.html#method.overrides_with /// [override]: ./struct.Arg.html#method.overrides_with
pub fn requires_ifs(mut self, ifs: &[(&'b str, &'a str)]) -> Self { pub fn requires_ifs(mut self, ifs: &[(&'b str, &'a str)]) -> Self {
if let Some(ref mut vec) = self.b.requires { if let Some(ref mut vec) = self.requires {
for &(val, arg) in ifs { for &(val, arg) in ifs {
vec.push((Some(val), arg)); vec.push((Some(val), arg));
} }
@ -1464,7 +1519,7 @@ impl<'a, 'b> Arg<'a, 'b> {
for &(val, arg) in ifs { for &(val, arg) in ifs {
vec.push((Some(val), arg)); vec.push((Some(val), arg));
} }
self.b.requires = Some(vec); self.requires = Some(vec);
} }
self self
} }
@ -1699,7 +1754,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [override]: ./struct.Arg.html#method.overrides_with /// [override]: ./struct.Arg.html#method.overrides_with
/// [`Arg::requires_all(&[arg, arg2])`]: ./struct.Arg.html#method.requires_all /// [`Arg::requires_all(&[arg, arg2])`]: ./struct.Arg.html#method.requires_all
pub fn requires_all(mut self, names: &[&'a str]) -> Self { pub fn requires_all(mut self, names: &[&'a str]) -> Self {
if let Some(ref mut vec) = self.b.requires { if let Some(ref mut vec) = self.requires {
for s in names { for s in names {
vec.push((None, s)); vec.push((None, s));
} }
@ -1708,7 +1763,7 @@ impl<'a, 'b> Arg<'a, 'b> {
for s in names { for s in names {
vec.push((None, *s)); vec.push((None, *s));
} }
self.b.requires = Some(vec); self.requires = Some(vec);
} }
self self
} }
@ -2127,7 +2182,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`max_values`]: ./struct.Arg.html#method.max_values /// [`max_values`]: ./struct.Arg.html#method.max_values
pub fn value_terminator(mut self, term: &'b str) -> Self { pub fn value_terminator(mut self, term: &'b str) -> Self {
self.setb(ArgSettings::TakesValue); self.setb(ArgSettings::TakesValue);
self.v.terminator = Some(term); self.terminator = Some(term);
self self
} }
@ -2319,12 +2374,12 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [options]: ./struct.Arg.html#method.takes_value /// [options]: ./struct.Arg.html#method.takes_value
/// [positional arguments]: ./struct.Arg.html#method.index /// [positional arguments]: ./struct.Arg.html#method.index
pub fn possible_values(mut self, names: &[&'b str]) -> Self { pub fn possible_values(mut self, names: &[&'b str]) -> Self {
if let Some(ref mut vec) = self.v.possible_vals { if let Some(ref mut vec) = self.possible_vals {
for s in names { for s in names {
vec.push(s); vec.push(s);
} }
} else { } else {
self.v.possible_vals = Some(names.iter().map(|s| *s).collect::<Vec<_>>()); self.possible_vals = Some(names.iter().map(|s| *s).collect::<Vec<_>>());
} }
self self
} }
@ -2383,10 +2438,10 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [options]: ./struct.Arg.html#method.takes_value /// [options]: ./struct.Arg.html#method.takes_value
/// [positional arguments]: ./struct.Arg.html#method.index /// [positional arguments]: ./struct.Arg.html#method.index
pub fn possible_value(mut self, name: &'b str) -> Self { pub fn possible_value(mut self, name: &'b str) -> Self {
if let Some(ref mut vec) = self.v.possible_vals { if let Some(ref mut vec) = self.possible_vals {
vec.push(name); vec.push(name);
} else { } else {
self.v.possible_vals = Some(vec![name]); self.possible_vals = Some(vec![name]);
} }
self self
} }
@ -2475,10 +2530,10 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ``` /// ```
/// [`ArgGroup`]: ./struct.ArgGroup.html /// [`ArgGroup`]: ./struct.ArgGroup.html
pub fn group(mut self, name: &'a str) -> Self { pub fn group(mut self, name: &'a str) -> Self {
if let Some(ref mut vec) = self.b.groups { if let Some(ref mut vec) = self.groups {
vec.push(name); vec.push(name);
} else { } else {
self.b.groups = Some(vec![name]); self.groups = Some(vec![name]);
} }
self self
} }
@ -2515,12 +2570,12 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ``` /// ```
/// [`ArgGroup`]: ./struct.ArgGroup.html /// [`ArgGroup`]: ./struct.ArgGroup.html
pub fn groups(mut self, names: &[&'a str]) -> Self { pub fn groups(mut self, names: &[&'a str]) -> Self {
if let Some(ref mut vec) = self.b.groups { if let Some(ref mut vec) = self.groups {
for s in names { for s in names {
vec.push(s); vec.push(s);
} }
} else { } else {
self.b.groups = Some(names.into_iter().map(|s| *s).collect::<Vec<_>>()); self.groups = Some(names.into_iter().map(|s| *s).collect::<Vec<_>>());
} }
self self
} }
@ -2563,7 +2618,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
pub fn number_of_values(mut self, qty: u64) -> Self { pub fn number_of_values(mut self, qty: u64) -> Self {
self.setb(ArgSettings::TakesValue); self.setb(ArgSettings::TakesValue);
self.v.num_vals = Some(qty); self.num_vals = Some(qty);
self self
} }
@ -2607,7 +2662,7 @@ impl<'a, 'b> Arg<'a, 'b> {
where where
F: Fn(String) -> Result<(), String> + 'static, F: Fn(String) -> Result<(), String> + 'static,
{ {
self.v.validator = Some(Rc::new(f)); self.validator = Some(Rc::new(f));
self self
} }
@ -2645,7 +2700,7 @@ impl<'a, 'b> Arg<'a, 'b> {
where where
F: Fn(&OsStr) -> Result<(), OsString> + 'static, F: Fn(&OsStr) -> Result<(), OsString> + 'static,
{ {
self.v.validator_os = Some(Rc::new(f)); self.validator_os = Some(Rc::new(f));
self self
} }
@ -2707,7 +2762,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
pub fn max_values(mut self, qty: u64) -> Self { pub fn max_values(mut self, qty: u64) -> Self {
self.setb(ArgSettings::TakesValue); self.setb(ArgSettings::TakesValue);
self.v.max_vals = Some(qty); self.max_vals = Some(qty);
self self
} }
@ -2769,7 +2824,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ``` /// ```
/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
pub fn min_values(mut self, qty: u64) -> Self { pub fn min_values(mut self, qty: u64) -> Self {
self.v.min_vals = Some(qty); self.min_vals = Some(qty);
self.set(ArgSettings::TakesValue) self.set(ArgSettings::TakesValue)
} }
@ -2821,14 +2876,14 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::value_delimiter`]: ./struct.Arg.html#method.value_delimiter /// [`Arg::value_delimiter`]: ./struct.Arg.html#method.value_delimiter
pub fn use_delimiter(mut self, d: bool) -> Self { pub fn use_delimiter(mut self, d: bool) -> Self {
if d { if d {
if self.v.val_delim.is_none() { if self.val_delim.is_none() {
self.v.val_delim = Some(','); self.val_delim = Some(',');
} }
self.setb(ArgSettings::TakesValue); self.setb(ArgSettings::TakesValue);
self.setb(ArgSettings::UseValueDelimiter); self.setb(ArgSettings::UseValueDelimiter);
self.unset(ArgSettings::ValueDelimiterNotSet) self.unset(ArgSettings::ValueDelimiterNotSet)
} else { } else {
self.v.val_delim = None; self.val_delim = None;
self.unsetb(ArgSettings::UseValueDelimiter); self.unsetb(ArgSettings::UseValueDelimiter);
self.unset(ArgSettings::ValueDelimiterNotSet) self.unset(ArgSettings::ValueDelimiterNotSet)
} }
@ -2946,7 +3001,7 @@ impl<'a, 'b> Arg<'a, 'b> {
self.unsetb(ArgSettings::ValueDelimiterNotSet); self.unsetb(ArgSettings::ValueDelimiterNotSet);
self.setb(ArgSettings::TakesValue); self.setb(ArgSettings::TakesValue);
self.setb(ArgSettings::UseValueDelimiter); self.setb(ArgSettings::UseValueDelimiter);
self.v.val_delim = Some( self.val_delim = Some(
d.chars() d.chars()
.nth(0) .nth(0)
.expect("Failed to get value_delimiter from arg"), .expect("Failed to get value_delimiter from arg"),
@ -3019,7 +3074,7 @@ impl<'a, 'b> Arg<'a, 'b> {
self.unsetb(ArgSettings::ValueDelimiterNotSet); self.unsetb(ArgSettings::ValueDelimiterNotSet);
self.setb(ArgSettings::UseValueDelimiter); self.setb(ArgSettings::UseValueDelimiter);
} }
if let Some(ref mut vals) = self.v.val_names { if let Some(ref mut vals) = self.val_names {
let mut l = vals.len(); let mut l = vals.len();
for s in names { for s in names {
vals.insert(l, s); vals.insert(l, s);
@ -3030,7 +3085,7 @@ impl<'a, 'b> Arg<'a, 'b> {
for (i, n) in names.iter().enumerate() { for (i, n) in names.iter().enumerate() {
vm.insert(i, *n); vm.insert(i, *n);
} }
self.v.val_names = Some(vm); self.val_names = Some(vm);
} }
self self
} }
@ -3083,13 +3138,13 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
pub fn value_name(mut self, name: &'b str) -> Self { pub fn value_name(mut self, name: &'b str) -> Self {
self.setb(ArgSettings::TakesValue); self.setb(ArgSettings::TakesValue);
if let Some(ref mut vals) = self.v.val_names { if let Some(ref mut vals) = self.val_names {
let l = vals.len(); let l = vals.len();
vals.insert(l, name); vals.insert(l, name);
} else { } else {
let mut vm = VecMap::new(); let mut vm = VecMap::new();
vm.insert(0, name); vm.insert(0, name);
self.v.val_names = Some(vm); self.val_names = Some(vm);
} }
self self
} }
@ -3167,7 +3222,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html /// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
pub fn default_value_os(mut self, val: &'a OsStr) -> Self { pub fn default_value_os(mut self, val: &'a OsStr) -> Self {
self.setb(ArgSettings::TakesValue); self.setb(ArgSettings::TakesValue);
self.v.default_val = Some(val); self.default_val = Some(val);
self self
} }
@ -3286,13 +3341,13 @@ impl<'a, 'b> Arg<'a, 'b> {
default: &'b OsStr, default: &'b OsStr,
) -> Self { ) -> Self {
self.setb(ArgSettings::TakesValue); self.setb(ArgSettings::TakesValue);
if let Some(ref mut vm) = self.v.default_vals_ifs { if let Some(ref mut vm) = self.default_vals_ifs {
let l = vm.len(); let l = vm.len();
vm.insert(l, (arg, val, default)); vm.insert(l, (arg, val, default));
} else { } else {
let mut vm = VecMap::new(); let mut vm = VecMap::new();
vm.insert(0, (arg, val, default)); vm.insert(0, (arg, val, default));
self.v.default_vals_ifs = Some(vm); self.default_vals_ifs = Some(vm);
} }
self self
} }
@ -3511,7 +3566,7 @@ impl<'a, 'b> Arg<'a, 'b> {
pub fn env_os(mut self, name: &'a OsStr) -> Self { pub fn env_os(mut self, name: &'a OsStr) -> Self {
self.setb(ArgSettings::TakesValue); self.setb(ArgSettings::TakesValue);
self.v.env = Some((name, env::var_os(name))); self.env = Some((name, env::var_os(name)));
self self
} }
@ -3634,13 +3689,13 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [positional arguments]: ./struct.Arg.html#method.index /// [positional arguments]: ./struct.Arg.html#method.index
/// [index]: ./struct.Arg.html#method.index /// [index]: ./struct.Arg.html#method.index
pub fn display_order(mut self, ord: usize) -> Self { pub fn display_order(mut self, ord: usize) -> Self {
self.s.disp_ord = ord; self.disp_ord = ord;
self self
} }
/// Checks if one of the [`ArgSettings`] settings is set for the argument /// Checks if one of the [`ArgSettings`] settings is set for the argument
/// [`ArgSettings`]: ./enum.ArgSettings.html /// [`ArgSettings`]: ./enum.ArgSettings.html
pub fn is_set(&self, s: ArgSettings) -> bool { self.b.is_set(s) } pub fn is_set(&self, s: ArgSettings) -> bool { self.settings.is_set(s) }
/// Sets one of the [`ArgSettings`] settings for the argument /// Sets one of the [`ArgSettings`] settings for the argument
/// [`ArgSettings`]: ./enum.ArgSettings.html /// [`ArgSettings`]: ./enum.ArgSettings.html
@ -3657,24 +3712,373 @@ impl<'a, 'b> Arg<'a, 'b> {
} }
#[doc(hidden)] #[doc(hidden)]
pub fn setb(&mut self, s: ArgSettings) { self.b.set(s); } pub fn _build(&mut self) {
if self.index.is_some() || (self.short.is_none() && self.long.is_none()) {
if self.max_vals.is_some() || self.min_vals.is_some()
|| (self.num_vals.is_some() && self.num_vals.unwrap() > 1)
{
self.setb(ArgSettings::Multiple);
}
} else if self.is_set(ArgSettings::TakesValue) {
if let Some(ref vec) = self.val_names {
if vec.len() > 1 {
self.num_vals = Some(vec.len() as u64);
}
}
}
}
#[doc(hidden)] #[doc(hidden)]
pub fn unsetb(&mut self, s: ArgSettings) { self.b.unset(s); } pub fn setb(&mut self, s: ArgSettings) { self.settings.set(s); }
}
impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for Arg<'a, 'b> { #[doc(hidden)]
fn from(a: &'z Arg<'a, 'b>) -> Self { pub fn unsetb(&mut self, s: ArgSettings) { self.settings.unset(s); }
Arg {
b: a.b.clone(), #[doc(hidden)]
v: a.v.clone(), pub fn has_switch(&self) -> bool { self.short.is_some() || self.long.is_some() }
s: a.s.clone(),
index: a.index, #[doc(hidden)]
r_ifs: a.r_ifs.clone(), pub fn longest_filter(&self) -> bool {
self.is_set(ArgSettings::TakesValue) || self.long.is_some() || self.short.is_none()
}
// Used for positionals when printing
#[doc(hidden)]
pub fn multiple_str(&self) -> &str {
let mult_vals = self.val_names
.as_ref()
.map_or(true, |names| names.len() < 2);
if self.is_set(ArgSettings::Multiple) && mult_vals {
"..."
} else {
""
}
}
// Used for positionals when printing
#[doc(hidden)]
pub fn name_no_brackets(&self) -> Cow<str> {
debugln!("PosBuilder::name_no_brackets:{}", self.name);
let mut delim = String::new();
delim.push(if self.is_set(ArgSettings::RequireDelimiter) {
self.val_delim.expect(INTERNAL_ERROR_MSG)
} else {
' '
});
if let Some(ref names) = self.val_names {
debugln!("PosBuilder:name_no_brackets: val_names={:#?}", names);
if names.len() > 1 {
Cow::Owned(
names
.values()
.map(|n| format!("<{}>", n))
.collect::<Vec<_>>()
.join(&*delim),
)
} else {
Cow::Borrowed(names.values().next().expect(INTERNAL_ERROR_MSG))
}
} else {
debugln!("PosBuilder:name_no_brackets: just name");
Cow::Borrowed(self.name)
} }
} }
} }
impl<'n, 'e> PartialEq for Arg<'n, 'e> { impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for Arg<'a, 'b> {
fn eq(&self, other: &Arg<'n, 'e>) -> bool { self.b == other.b } fn from(a: &'z Arg<'a, 'b>) -> Self { a.clone() }
}
impl<'n, 'e> PartialEq for Arg<'n, 'e> {
fn eq(&self, other: &Arg<'n, 'e>) -> bool { self.name == other.name }
}
impl<'n, 'e> Display for Arg<'n, 'e> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if self.index.is_some() || (self.long.is_none() && self.short.is_none()) {
// Positional
let mut delim = String::new();
delim.push(if self.is_set(ArgSettings::RequireDelimiter) {
self.val_delim.expect(INTERNAL_ERROR_MSG)
} else {
' '
});
if let Some(ref names) = self.val_names {
write!(
f,
"{}",
names
.values()
.map(|n| format!("<{}>", n))
.collect::<Vec<_>>()
.join(&*delim)
)?;
} else {
write!(f, "<{}>", self.name)?;
}
if self.settings.is_set(ArgSettings::Multiple)
&& (self.val_names.is_none()
|| (self.val_names.is_some()
&& self.val_names.as_ref().unwrap().len() == 1))
{
write!(f, "...")?;
}
return Ok(());
} else if !self.is_set(ArgSettings::TakesValue) {
// Flag
if let Some(l) = self.long {
write!(f, "--{}", l)?;
} else if let Some(s) = self.short {
write!(f, "-{}", s)?;
}
return Ok(());
}
let sep = if self.is_set(ArgSettings::RequireEquals) {
"="
} else {
" "
};
// Write the name such --long or -l
if let Some(l) = self.long {
write!(f, "--{}{}", l, sep)?;
} else {
write!(f, "-{}{}", self.short.unwrap(), sep)?;
}
let delim = if self.is_set(ArgSettings::RequireDelimiter) {
self.val_delim.expect(INTERNAL_ERROR_MSG)
} else {
' '
};
// Write the values such as <name1> <name2>
if let Some(ref vec) = self.val_names {
let mut it = vec.iter().peekable();
while let Some((_, val)) = it.next() {
write!(f, "<{}>", val)?;
if it.peek().is_some() {
write!(f, "{}", delim)?;
}
}
let num = vec.len();
if self.is_set(ArgSettings::Multiple) && num == 1 {
write!(f, "...")?;
}
} else if let Some(num) = self.num_vals {
let mut it = (0..num).peekable();
while let Some(_) = it.next() {
write!(f, "<{}>", self.name)?;
if it.peek().is_some() {
write!(f, "{}", delim)?;
}
}
if self.is_set(ArgSettings::Multiple) && num == 1 {
write!(f, "...")?;
}
} else {
write!(
f,
"<{}>{}",
self.name,
if self.is_set(ArgSettings::Multiple) {
"..."
} else {
""
}
)?;
}
Ok(())
}
}
impl<'n, 'e> PartialOrd for Arg<'n, 'e> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
}
impl<'n, 'e> Ord for Arg<'n, 'e> {
fn cmp(&self, other: &Arg) -> Ordering { self.name.cmp(&other.name) }
}
impl<'n, 'e> Eq for Arg<'n, 'e> {}
impl<'n, 'e> fmt::Debug for Arg<'n, 'e> {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
write!(
f,
"Arg {{ name: {:?}, help: {:?}, long_help: {:?}, conflicts_with: {:?}, \
settings: {:?}, required_unless: {:?}, overrides_with: {:?}, groups: {:?}, \
requires: {:?}, requires_ifs: {:?}, short: {:?}, index: {:?}, long: {:?}, \
aliases: {:?}, possible_values: {:?}, value_names: {:?}, number_of_values: {:?}, \
max_values: {:?}, min_values: {:?}, value_delimiter: {:?}, default_value_ifs: {:?}, \
value_terminator: {:?}, display_order: {:?}, env: {:?}, unified_ord: {:?}, \
default_value: {:?}, validator: {}, validator_os: {} \
}}",
self.name,
self.help,
self.long_help,
self.blacklist,
self.settings,
self.r_unless,
self.overrides,
self.groups,
self.requires,
self.r_ifs,
self.short,
self.index,
self.long,
self.aliases,
self.possible_vals,
self.val_names,
self.num_vals,
self.max_vals,
self.min_vals,
self.val_delim,
self.default_vals_ifs,
self.terminator,
self.disp_ord,
self.env,
self.unified_ord,
self.default_val,
self.validator.as_ref().map_or("None", |_| "Some(Fn)"),
self.validator_os.as_ref().map_or("None", |_| "Some(Fn)")
)
}
}
// Flags
#[cfg(test)]
mod test {
use map::VecMap;
use args::settings::ArgSettings;
use super::Arg;
#[test]
fn flag_display() {
let mut f = Arg::with_name("flg");
f.settings.set(ArgSettings::Multiple);
f.long = Some("flag");
assert_eq!(&*format!("{}", f), "--flag");
let mut f2 = Arg::with_name("flg");
f2.short = Some('f');
assert_eq!(&*format!("{}", f2), "-f");
}
#[test]
fn flag_display_single_alias() {
let mut f = Arg::with_name("flg");
f.long = Some("flag");
f.aliases = Some(vec![("als", true)]);
assert_eq!(&*format!("{}", f), "--flag");
}
#[test]
fn flag_display_multiple_aliases() {
let mut f = Arg::with_name("flg");
f.short = Some('f');
f.aliases = Some(vec![
("alias_not_visible", false),
("f2", true),
("f3", true),
("f4", true),
]);
assert_eq!(&*format!("{}", f), "-f");
}
// Options
#[test]
fn option_display1() {
let o = Arg::with_name("opt")
.long("option")
.takes_value(true)
.multiple(true);
assert_eq!(&*format!("{}", o), "--option <opt>...");
}
#[test]
fn option_display2() {
let o2 = Arg::with_name("opt")
.short("o")
.value_names(&["file", "name"]);
assert_eq!(&*format!("{}", o2), "-o <file> <name>");
}
#[test]
fn option_display3() {
let o2 = Arg::with_name("opt")
.short("o")
.multiple(true)
.value_names(&["file", "name"]);
assert_eq!(&*format!("{}", o2), "-o <file> <name>");
}
#[test]
fn option_display_single_alias() {
let o = Arg::with_name("opt")
.takes_value(true)
.long("option")
.visible_alias("als");
assert_eq!(&*format!("{}", o), "--option <opt>");
}
#[test]
fn option_display_multiple_aliases() {
let o = Arg::with_name("opt")
.long("option")
.takes_value(true)
.visible_aliases(&["als2", "als3", "als4"])
.alias("als_not_visible");
assert_eq!(&*format!("{}", o), "--option <opt>");
}
// Positionals
#[test]
fn positiona_display_mult() {
let mut p = Arg::with_name("pos").index(1);
p.settings.set(ArgSettings::Multiple);
assert_eq!(&*format!("{}", p), "<pos>...");
}
#[test]
fn positional_display_required() {
let mut p2 = Arg::with_name("pos").index(1);
p2.settings.set(ArgSettings::Required);
assert_eq!(&*format!("{}", p2), "<pos>");
}
#[test]
fn positional_display_val_names() {
let mut p2 = Arg::with_name("pos").index(1);
let mut vm = VecMap::new();
vm.insert(0, "file1");
vm.insert(1, "file2");
p2.val_names = Some(vm);
assert_eq!(&*format!("{}", p2), "<file1> <file2>");
}
#[test]
fn positional_display_val_names_req() {
let mut p2 = Arg::with_name("pos").index(1);
p2.settings.set(ArgSettings::Required);
let mut vm = VecMap::new();
vm.insert(0, "file1");
vm.insert(1, "file2");
p2.val_names = Some(vm);
assert_eq!(&*format!("{}", p2), "<file1> <file2>");
}
} }

View file

@ -1,38 +0,0 @@
use args::{Arg, ArgFlags, ArgSettings};
#[derive(Debug, Clone, Default)]
pub struct Base<'a, 'b>
where
'a: 'b,
{
pub name: &'a str,
pub help: Option<&'b str>,
pub long_help: Option<&'b str>,
pub blacklist: Option<Vec<&'a str>>,
pub settings: ArgFlags,
pub r_unless: Option<Vec<&'a str>>,
pub overrides: Option<Vec<&'a str>>,
pub groups: Option<Vec<&'a str>>,
pub requires: Option<Vec<(Option<&'b str>, &'a str)>>,
}
impl<'n, 'e> Base<'n, 'e> {
pub fn new(name: &'n str) -> Self {
Base {
name: name,
..Default::default()
}
}
pub fn set(&mut self, s: ArgSettings) { self.settings.set(s); }
pub fn unset(&mut self, s: ArgSettings) { self.settings.unset(s); }
pub fn is_set(&self, s: ArgSettings) -> bool { self.settings.is_set(s) }
}
impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for Base<'n, 'e> {
fn from(a: &'z Arg<'n, 'e>) -> Self { a.b.clone() }
}
impl<'n, 'e> PartialEq for Base<'n, 'e> {
fn eq(&self, other: &Base<'n, 'e>) -> bool { self.name == other.name }
}

View file

@ -1,159 +0,0 @@
// Std
use std::convert::From;
use std::fmt::{Display, Formatter, Result};
use std::rc::Rc;
use std::result::Result as StdResult;
use std::ffi::{OsStr, OsString};
use std::mem;
// Internal
use Arg;
use args::{AnyArg, ArgSettings, Base, DispOrder, Switched};
use map::{self, VecMap};
#[derive(Default, Clone, Debug)]
#[doc(hidden)]
pub struct FlagBuilder<'n, 'e>
where
'n: 'e,
{
pub b: Base<'n, 'e>,
pub s: Switched<'e>,
}
impl<'n, 'e> FlagBuilder<'n, 'e> {
pub fn new(name: &'n str) -> Self {
FlagBuilder {
b: Base::new(name),
..Default::default()
}
}
}
impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for FlagBuilder<'a, 'b> {
fn from(a: &'z Arg<'a, 'b>) -> Self {
FlagBuilder {
b: Base::from(a),
s: Switched::from(a),
}
}
}
impl<'a, 'b> From<Arg<'a, 'b>> for FlagBuilder<'a, 'b> {
fn from(mut a: Arg<'a, 'b>) -> Self {
FlagBuilder {
b: mem::replace(&mut a.b, Base::default()),
s: mem::replace(&mut a.s, Switched::default()),
}
}
}
impl<'n, 'e> Display for FlagBuilder<'n, 'e> {
fn fmt(&self, f: &mut Formatter) -> Result {
if let Some(l) = self.s.long {
write!(f, "--{}", l)?;
} else {
write!(f, "-{}", self.s.short.unwrap())?;
}
Ok(())
}
}
impl<'n, 'e> AnyArg<'n, 'e> for FlagBuilder<'n, 'e> {
fn name(&self) -> &'n str { self.b.name }
fn overrides(&self) -> Option<&[&'e str]> { self.b.overrides.as_ref().map(|o| &o[..]) }
fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> {
self.b.requires.as_ref().map(|o| &o[..])
}
fn blacklist(&self) -> Option<&[&'e str]> { self.b.blacklist.as_ref().map(|o| &o[..]) }
fn required_unless(&self) -> Option<&[&'e str]> { self.b.r_unless.as_ref().map(|o| &o[..]) }
fn is_set(&self, s: ArgSettings) -> bool { self.b.settings.is_set(s) }
fn has_switch(&self) -> bool { true }
fn takes_value(&self) -> bool { false }
fn set(&mut self, s: ArgSettings) { self.b.settings.set(s) }
fn max_vals(&self) -> Option<u64> { None }
fn val_names(&self) -> Option<&VecMap<&'e str>> { None }
fn num_vals(&self) -> Option<u64> { None }
fn possible_vals(&self) -> Option<&[&'e str]> { None }
fn validator(&self) -> Option<&Rc<Fn(String) -> StdResult<(), String>>> { None }
fn validator_os(&self) -> Option<&Rc<Fn(&OsStr) -> StdResult<(), OsString>>> { None }
fn min_vals(&self) -> Option<u64> { None }
fn short(&self) -> Option<char> { self.s.short }
fn long(&self) -> Option<&'e str> { self.s.long }
fn val_delim(&self) -> Option<char> { None }
fn help(&self) -> Option<&'e str> { self.b.help }
fn long_help(&self) -> Option<&'e str> { self.b.long_help }
fn val_terminator(&self) -> Option<&'e str> { None }
fn default_val(&self) -> Option<&'e OsStr> { None }
fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
None
}
fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> { None }
fn longest_filter(&self) -> bool { self.s.long.is_some() }
fn aliases(&self) -> Option<Vec<&'e str>> {
if let Some(ref aliases) = self.s.aliases {
let vis_aliases: Vec<_> = aliases
.iter()
.filter_map(|&(n, v)| if v { Some(n) } else { None })
.collect();
if vis_aliases.is_empty() {
None
} else {
Some(vis_aliases)
}
} else {
None
}
}
}
impl<'n, 'e> DispOrder for FlagBuilder<'n, 'e> {
fn disp_ord(&self) -> usize { self.s.disp_ord }
}
impl<'n, 'e> PartialEq for FlagBuilder<'n, 'e> {
fn eq(&self, other: &FlagBuilder<'n, 'e>) -> bool { self.b == other.b }
}
#[cfg(test)]
mod test {
use args::settings::ArgSettings;
use super::FlagBuilder;
#[test]
fn flagbuilder_display() {
let mut f = FlagBuilder::new("flg");
f.b.settings.set(ArgSettings::Multiple);
f.s.long = Some("flag");
assert_eq!(&*format!("{}", f), "--flag");
let mut f2 = FlagBuilder::new("flg");
f2.s.short = Some('f');
assert_eq!(&*format!("{}", f2), "-f");
}
#[test]
fn flagbuilder_display_single_alias() {
let mut f = FlagBuilder::new("flg");
f.s.long = Some("flag");
f.s.aliases = Some(vec![("als", true)]);
assert_eq!(&*format!("{}", f), "--flag");
}
#[test]
fn flagbuilder_display_multiple_aliases() {
let mut f = FlagBuilder::new("flg");
f.s.short = Some('f');
f.s.aliases = Some(vec![
("alias_not_visible", false),
("f2", true),
("f3", true),
("f4", true),
]);
assert_eq!(&*format!("{}", f), "-f");
}
}

View file

@ -1,13 +0,0 @@
pub use self::flag::FlagBuilder;
pub use self::option::OptBuilder;
pub use self::positional::PosBuilder;
pub use self::base::Base;
pub use self::switched::Switched;
pub use self::valued::Valued;
mod flag;
mod positional;
mod option;
mod base;
mod valued;
mod switched;

View file

@ -1,244 +0,0 @@
// Std
use std::fmt::{Display, Formatter, Result};
use std::rc::Rc;
use std::result::Result as StdResult;
use std::ffi::{OsStr, OsString};
use std::mem;
// Internal
use args::{AnyArg, Arg, ArgSettings, Base, DispOrder, Switched, Valued};
use map::{self, VecMap};
use INTERNAL_ERROR_MSG;
#[allow(missing_debug_implementations)]
#[doc(hidden)]
#[derive(Default, Clone)]
pub struct OptBuilder<'n, 'e>
where
'n: 'e,
{
pub b: Base<'n, 'e>,
pub s: Switched<'e>,
pub v: Valued<'n, 'e>,
}
impl<'n, 'e> OptBuilder<'n, 'e> {
pub fn new(name: &'n str) -> Self {
OptBuilder {
b: Base::new(name),
..Default::default()
}
}
}
impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for OptBuilder<'n, 'e> {
fn from(a: &'z Arg<'n, 'e>) -> Self {
OptBuilder {
b: Base::from(a),
s: Switched::from(a),
v: Valued::from(a),
}
}
}
impl<'n, 'e> From<Arg<'n, 'e>> for OptBuilder<'n, 'e> {
fn from(mut a: Arg<'n, 'e>) -> Self {
a.v.fill_in();
OptBuilder {
b: mem::replace(&mut a.b, Base::default()),
s: mem::replace(&mut a.s, Switched::default()),
v: mem::replace(&mut a.v, Valued::default()),
}
}
}
impl<'n, 'e> Display for OptBuilder<'n, 'e> {
fn fmt(&self, f: &mut Formatter) -> Result {
debugln!("OptBuilder::fmt:{}", self.b.name);
let sep = if self.b.is_set(ArgSettings::RequireEquals) {
"="
} else {
" "
};
// Write the name such --long or -l
if let Some(l) = self.s.long {
write!(f, "--{}{}", l, sep)?;
} else {
write!(f, "-{}{}", self.s.short.unwrap(), sep)?;
}
let delim = if self.is_set(ArgSettings::RequireDelimiter) {
self.v.val_delim.expect(INTERNAL_ERROR_MSG)
} else {
' '
};
// Write the values such as <name1> <name2>
if let Some(ref vec) = self.v.val_names {
let mut it = vec.iter().peekable();
while let Some((_, val)) = it.next() {
write!(f, "<{}>", val)?;
if it.peek().is_some() {
write!(f, "{}", delim)?;
}
}
let num = vec.len();
if self.is_set(ArgSettings::Multiple) && num == 1 {
write!(f, "...")?;
}
} else if let Some(num) = self.v.num_vals {
let mut it = (0..num).peekable();
while let Some(_) = it.next() {
write!(f, "<{}>", self.b.name)?;
if it.peek().is_some() {
write!(f, "{}", delim)?;
}
}
if self.is_set(ArgSettings::Multiple) && num == 1 {
write!(f, "...")?;
}
} else {
write!(
f,
"<{}>{}",
self.b.name,
if self.is_set(ArgSettings::Multiple) {
"..."
} else {
""
}
)?;
}
Ok(())
}
}
impl<'n, 'e> AnyArg<'n, 'e> for OptBuilder<'n, 'e> {
fn name(&self) -> &'n str { self.b.name }
fn overrides(&self) -> Option<&[&'e str]> { self.b.overrides.as_ref().map(|o| &o[..]) }
fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> {
self.b.requires.as_ref().map(|o| &o[..])
}
fn blacklist(&self) -> Option<&[&'e str]> { self.b.blacklist.as_ref().map(|o| &o[..]) }
fn required_unless(&self) -> Option<&[&'e str]> { self.b.r_unless.as_ref().map(|o| &o[..]) }
fn val_names(&self) -> Option<&VecMap<&'e str>> { self.v.val_names.as_ref() }
fn is_set(&self, s: ArgSettings) -> bool { self.b.settings.is_set(s) }
fn has_switch(&self) -> bool { true }
fn set(&mut self, s: ArgSettings) { self.b.settings.set(s) }
fn max_vals(&self) -> Option<u64> { self.v.max_vals }
fn val_terminator(&self) -> Option<&'e str> { self.v.terminator }
fn num_vals(&self) -> Option<u64> { self.v.num_vals }
fn possible_vals(&self) -> Option<&[&'e str]> { self.v.possible_vals.as_ref().map(|o| &o[..]) }
fn validator(&self) -> Option<&Rc<Fn(String) -> StdResult<(), String>>> {
self.v.validator.as_ref()
}
fn validator_os(&self) -> Option<&Rc<Fn(&OsStr) -> StdResult<(), OsString>>> {
self.v.validator_os.as_ref()
}
fn min_vals(&self) -> Option<u64> { self.v.min_vals }
fn short(&self) -> Option<char> { self.s.short }
fn long(&self) -> Option<&'e str> { self.s.long }
fn val_delim(&self) -> Option<char> { self.v.val_delim }
fn takes_value(&self) -> bool { true }
fn help(&self) -> Option<&'e str> { self.b.help }
fn long_help(&self) -> Option<&'e str> { self.b.long_help }
fn default_val(&self) -> Option<&'e OsStr> { self.v.default_val }
fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
self.v.default_vals_ifs.as_ref().map(|vm| vm.values())
}
fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> {
self.v
.env
.as_ref()
.map(|&(key, ref value)| (key, value.as_ref()))
}
fn longest_filter(&self) -> bool { true }
fn aliases(&self) -> Option<Vec<&'e str>> {
if let Some(ref aliases) = self.s.aliases {
let vis_aliases: Vec<_> = aliases
.iter()
.filter_map(|&(n, v)| if v { Some(n) } else { None })
.collect();
if vis_aliases.is_empty() {
None
} else {
Some(vis_aliases)
}
} else {
None
}
}
}
impl<'n, 'e> DispOrder for OptBuilder<'n, 'e> {
fn disp_ord(&self) -> usize { self.s.disp_ord }
}
impl<'n, 'e> PartialEq for OptBuilder<'n, 'e> {
fn eq(&self, other: &OptBuilder<'n, 'e>) -> bool { self.b == other.b }
}
#[cfg(test)]
mod test {
use args::settings::ArgSettings;
use super::OptBuilder;
use map::VecMap;
#[test]
fn optbuilder_display1() {
let mut o = OptBuilder::new("opt");
o.s.long = Some("option");
o.b.settings.set(ArgSettings::Multiple);
assert_eq!(&*format!("{}", o), "--option <opt>...");
}
#[test]
fn optbuilder_display2() {
let mut v_names = VecMap::new();
v_names.insert(0, "file");
v_names.insert(1, "name");
let mut o2 = OptBuilder::new("opt");
o2.s.short = Some('o');
o2.v.val_names = Some(v_names);
assert_eq!(&*format!("{}", o2), "-o <file> <name>");
}
#[test]
fn optbuilder_display3() {
let mut v_names = VecMap::new();
v_names.insert(0, "file");
v_names.insert(1, "name");
let mut o2 = OptBuilder::new("opt");
o2.s.short = Some('o');
o2.v.val_names = Some(v_names);
o2.b.settings.set(ArgSettings::Multiple);
assert_eq!(&*format!("{}", o2), "-o <file> <name>");
}
#[test]
fn optbuilder_display_single_alias() {
let mut o = OptBuilder::new("opt");
o.s.long = Some("option");
o.s.aliases = Some(vec![("als", true)]);
assert_eq!(&*format!("{}", o), "--option <opt>");
}
#[test]
fn optbuilder_display_multiple_aliases() {
let mut o = OptBuilder::new("opt");
o.s.long = Some("option");
o.s.aliases = Some(vec![
("als_not_visible", false),
("als2", true),
("als3", true),
("als4", true),
]);
assert_eq!(&*format!("{}", o), "--option <opt>");
}
}

View file

@ -1,229 +0,0 @@
// Std
use std::borrow::Cow;
use std::fmt::{Display, Formatter, Result};
use std::rc::Rc;
use std::result::Result as StdResult;
use std::ffi::{OsStr, OsString};
use std::mem;
// Internal
use Arg;
use args::{AnyArg, ArgSettings, Base, DispOrder, Valued};
use INTERNAL_ERROR_MSG;
use map::{self, VecMap};
#[allow(missing_debug_implementations)]
#[doc(hidden)]
#[derive(Clone, Default)]
pub struct PosBuilder<'n, 'e>
where
'n: 'e,
{
pub b: Base<'n, 'e>,
pub v: Valued<'n, 'e>,
pub index: u64,
}
impl<'n, 'e> PosBuilder<'n, 'e> {
pub fn new(name: &'n str, idx: u64) -> Self {
PosBuilder {
b: Base::new(name),
index: idx,
..Default::default()
}
}
pub fn from_arg_ref(a: &Arg<'n, 'e>, idx: u64) -> Self {
let mut pb = PosBuilder {
b: Base::from(a),
v: Valued::from(a),
index: idx,
};
if a.v.max_vals.is_some() || a.v.min_vals.is_some()
|| (a.v.num_vals.is_some() && a.v.num_vals.unwrap() > 1)
{
pb.b.settings.set(ArgSettings::Multiple);
}
pb
}
pub fn from_arg(mut a: Arg<'n, 'e>, idx: u64) -> Self {
if a.v.max_vals.is_some() || a.v.min_vals.is_some()
|| (a.v.num_vals.is_some() && a.v.num_vals.unwrap() > 1)
{
a.b.settings.set(ArgSettings::Multiple);
}
PosBuilder {
b: mem::replace(&mut a.b, Base::default()),
v: mem::replace(&mut a.v, Valued::default()),
index: idx,
}
}
pub fn multiple_str(&self) -> &str {
let mult_vals = self.v
.val_names
.as_ref()
.map_or(true, |names| names.len() < 2);
if self.is_set(ArgSettings::Multiple) && mult_vals {
"..."
} else {
""
}
}
pub fn name_no_brackets(&self) -> Cow<str> {
debugln!("PosBuilder::name_no_brackets;");
let mut delim = String::new();
delim.push(if self.is_set(ArgSettings::RequireDelimiter) {
self.v.val_delim.expect(INTERNAL_ERROR_MSG)
} else {
' '
});
if let Some(ref names) = self.v.val_names {
debugln!("PosBuilder:name_no_brackets: val_names={:#?}", names);
if names.len() > 1 {
Cow::Owned(
names
.values()
.map(|n| format!("<{}>", n))
.collect::<Vec<_>>()
.join(&*delim),
)
} else {
Cow::Borrowed(names.values().next().expect(INTERNAL_ERROR_MSG))
}
} else {
debugln!("PosBuilder:name_no_brackets: just name");
Cow::Borrowed(self.b.name)
}
}
}
impl<'n, 'e> Display for PosBuilder<'n, 'e> {
fn fmt(&self, f: &mut Formatter) -> Result {
let mut delim = String::new();
delim.push(if self.is_set(ArgSettings::RequireDelimiter) {
self.v.val_delim.expect(INTERNAL_ERROR_MSG)
} else {
' '
});
if let Some(ref names) = self.v.val_names {
write!(
f,
"{}",
names
.values()
.map(|n| format!("<{}>", n))
.collect::<Vec<_>>()
.join(&*delim)
)?;
} else {
write!(f, "<{}>", self.b.name)?;
}
if self.b.settings.is_set(ArgSettings::Multiple)
&& (self.v.val_names.is_none() || self.v.val_names.as_ref().unwrap().len() == 1)
{
write!(f, "...")?;
}
Ok(())
}
}
impl<'n, 'e> AnyArg<'n, 'e> for PosBuilder<'n, 'e> {
fn name(&self) -> &'n str { self.b.name }
fn overrides(&self) -> Option<&[&'e str]> { self.b.overrides.as_ref().map(|o| &o[..]) }
fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> {
self.b.requires.as_ref().map(|o| &o[..])
}
fn blacklist(&self) -> Option<&[&'e str]> { self.b.blacklist.as_ref().map(|o| &o[..]) }
fn required_unless(&self) -> Option<&[&'e str]> { self.b.r_unless.as_ref().map(|o| &o[..]) }
fn val_names(&self) -> Option<&VecMap<&'e str>> { self.v.val_names.as_ref() }
fn is_set(&self, s: ArgSettings) -> bool { self.b.settings.is_set(s) }
fn set(&mut self, s: ArgSettings) { self.b.settings.set(s) }
fn has_switch(&self) -> bool { false }
fn max_vals(&self) -> Option<u64> { self.v.max_vals }
fn val_terminator(&self) -> Option<&'e str> { self.v.terminator }
fn num_vals(&self) -> Option<u64> { self.v.num_vals }
fn possible_vals(&self) -> Option<&[&'e str]> { self.v.possible_vals.as_ref().map(|o| &o[..]) }
fn validator(&self) -> Option<&Rc<Fn(String) -> StdResult<(), String>>> {
self.v.validator.as_ref()
}
fn validator_os(&self) -> Option<&Rc<Fn(&OsStr) -> StdResult<(), OsString>>> {
self.v.validator_os.as_ref()
}
fn min_vals(&self) -> Option<u64> { self.v.min_vals }
fn short(&self) -> Option<char> { None }
fn long(&self) -> Option<&'e str> { None }
fn val_delim(&self) -> Option<char> { self.v.val_delim }
fn takes_value(&self) -> bool { true }
fn help(&self) -> Option<&'e str> { self.b.help }
fn long_help(&self) -> Option<&'e str> { self.b.long_help }
fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
self.v.default_vals_ifs.as_ref().map(|vm| vm.values())
}
fn default_val(&self) -> Option<&'e OsStr> { self.v.default_val }
fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> {
self.v
.env
.as_ref()
.map(|&(key, ref value)| (key, value.as_ref()))
}
fn longest_filter(&self) -> bool { true }
fn aliases(&self) -> Option<Vec<&'e str>> { None }
}
impl<'n, 'e> DispOrder for PosBuilder<'n, 'e> {
fn disp_ord(&self) -> usize { self.index as usize }
}
impl<'n, 'e> PartialEq for PosBuilder<'n, 'e> {
fn eq(&self, other: &PosBuilder<'n, 'e>) -> bool { self.b == other.b }
}
#[cfg(test)]
mod test {
use args::settings::ArgSettings;
use super::PosBuilder;
use map::VecMap;
#[test]
fn display_mult() {
let mut p = PosBuilder::new("pos", 1);
p.b.settings.set(ArgSettings::Multiple);
assert_eq!(&*format!("{}", p), "<pos>...");
}
#[test]
fn display_required() {
let mut p2 = PosBuilder::new("pos", 1);
p2.b.settings.set(ArgSettings::Required);
assert_eq!(&*format!("{}", p2), "<pos>");
}
#[test]
fn display_val_names() {
let mut p2 = PosBuilder::new("pos", 1);
let mut vm = VecMap::new();
vm.insert(0, "file1");
vm.insert(1, "file2");
p2.v.val_names = Some(vm);
assert_eq!(&*format!("{}", p2), "<file1> <file2>");
}
#[test]
fn display_val_names_req() {
let mut p2 = PosBuilder::new("pos", 1);
p2.b.settings.set(ArgSettings::Required);
let mut vm = VecMap::new();
vm.insert(0, "file1");
vm.insert(1, "file2");
p2.v.val_names = Some(vm);
assert_eq!(&*format!("{}", p2), "<file1> <file2>");
}
}

View file

@ -1,38 +0,0 @@
use Arg;
#[derive(Debug)]
pub struct Switched<'b> {
pub short: Option<char>,
pub long: Option<&'b str>,
pub aliases: Option<Vec<(&'b str, bool)>>, // (name, visible)
pub disp_ord: usize,
pub unified_ord: usize,
}
impl<'e> Default for Switched<'e> {
fn default() -> Self {
Switched {
short: None,
long: None,
aliases: None,
disp_ord: 999,
unified_ord: 999,
}
}
}
impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for Switched<'e> {
fn from(a: &'z Arg<'n, 'e>) -> Self { a.s.clone() }
}
impl<'e> Clone for Switched<'e> {
fn clone(&self) -> Self {
Switched {
short: self.short,
long: self.long,
aliases: self.aliases.clone(),
disp_ord: self.disp_ord,
unified_ord: self.unified_ord,
}
}
}

View file

@ -1,67 +0,0 @@
use std::rc::Rc;
use std::ffi::{OsStr, OsString};
use map::VecMap;
use Arg;
#[allow(missing_debug_implementations)]
#[derive(Clone)]
pub struct Valued<'a, 'b>
where
'a: 'b,
{
pub possible_vals: Option<Vec<&'b str>>,
pub val_names: Option<VecMap<&'b str>>,
pub num_vals: Option<u64>,
pub max_vals: Option<u64>,
pub min_vals: Option<u64>,
pub validator: Option<Rc<Fn(String) -> Result<(), String>>>,
pub validator_os: Option<Rc<Fn(&OsStr) -> Result<(), OsString>>>,
pub val_delim: Option<char>,
pub default_val: Option<&'b OsStr>,
pub default_vals_ifs: Option<VecMap<(&'a str, Option<&'b OsStr>, &'b OsStr)>>,
pub env: Option<(&'a OsStr, Option<OsString>)>,
pub terminator: Option<&'b str>,
}
impl<'n, 'e> Default for Valued<'n, 'e> {
fn default() -> Self {
Valued {
possible_vals: None,
num_vals: None,
min_vals: None,
max_vals: None,
val_names: None,
validator: None,
validator_os: None,
val_delim: None,
default_val: None,
default_vals_ifs: None,
env: None,
terminator: None,
}
}
}
impl<'n, 'e> Valued<'n, 'e> {
pub fn fill_in(&mut self) {
if let Some(ref vec) = self.val_names {
if vec.len() > 1 {
self.num_vals = Some(vec.len() as u64);
}
}
}
}
impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for Valued<'n, 'e> {
fn from(a: &'z Arg<'n, 'e>) -> Self {
let mut v = a.v.clone();
if let Some(ref vec) = a.v.val_names {
if vec.len() > 1 {
v.num_vals = Some(vec.len() as u64);
}
}
v
}
}

View file

@ -1,13 +1,13 @@
// Std // Std
use std::collections::hash_map::{Entry, Iter};
use std::collections::HashMap;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::ops::Deref; use std::collections::HashMap;
use std::mem; use std::mem;
// Third Party
use ordermap;
// Internal // Internal
use args::{ArgMatches, MatchedArg, SubCommand}; use args::{Arg, ArgMatches, MatchedArg, SubCommand};
use args::AnyArg;
use args::settings::ArgSettings; use args::settings::ArgSettings;
#[doc(hidden)] #[doc(hidden)]
@ -21,36 +21,13 @@ impl<'a> Default for ArgMatcher<'a> {
impl<'a> ArgMatcher<'a> { impl<'a> ArgMatcher<'a> {
pub fn new() -> Self { ArgMatcher::default() } pub fn new() -> Self { ArgMatcher::default() }
pub fn process_arg_overrides<'b>(&mut self, a: Option<&AnyArg<'a, 'b>>, overrides: &mut Vec<(&'b str, &'a str)>, required: &mut Vec<&'a str>) { pub fn is_present(&self, name: &str) -> bool { self.0.is_present(name) }
debugln!("ArgMatcher::process_arg_overrides:{:?};", a.map_or(None, |a| Some(a.name())));
if let Some(aa) = a {
if let Some(a_overrides) = aa.overrides() {
for overr in a_overrides {
debugln!("ArgMatcher::process_arg_overrides:iter:{};", overr);
if self.is_present(overr) {
debugln!("ArgMatcher::process_arg_overrides:iter:{}: removing from matches;", overr);
self.remove(overr);
for i in (0 .. required.len()).rev() {
if &required[i] == overr {
debugln!("ArgMatcher::process_arg_overrides:iter:{}: removing required;", overr);
required.swap_remove(i);
break;
}
}
} else {
overrides.push((overr, aa.name()));
}
}
}
}
}
pub fn is_present(&self, name: &str) -> bool {
self.0.is_present(name)
}
pub fn propagate_globals(&mut self, global_arg_vec: &[&'a str]) { pub fn propagate_globals(&mut self, global_arg_vec: &[&'a str]) {
debugln!( "ArgMatcher::get_global_values: global_arg_vec={:?}", global_arg_vec ); debugln!(
"ArgMatcher::get_global_values: global_arg_vec={:?}",
global_arg_vec
);
let mut vals_map = HashMap::new(); let mut vals_map = HashMap::new();
self.fill_in_global_values(global_arg_vec, &mut vals_map); self.fill_in_global_values(global_arg_vec, &mut vals_map);
} }
@ -97,6 +74,7 @@ impl<'a> ArgMatcher<'a> {
pub fn remove(&mut self, arg: &str) { self.0.args.remove(arg); } pub fn remove(&mut self, arg: &str) { self.0.args.remove(arg); }
#[allow(dead_code)]
pub fn remove_all(&mut self, args: &[&str]) { pub fn remove_all(&mut self, args: &[&str]) {
for &arg in args { for &arg in args {
self.0.args.remove(arg); self.0.args.remove(arg);
@ -111,15 +89,17 @@ impl<'a> ArgMatcher<'a> {
pub fn usage(&mut self, usage: String) { self.0.usage = Some(usage); } pub fn usage(&mut self, usage: String) { self.0.usage = Some(usage); }
pub fn arg_names(&'a self) -> Vec<&'a str> { self.0.args.keys().map(Deref::deref).collect() } pub fn arg_names(&'a self) -> ordermap::Keys<&'a str, MatchedArg> { self.0.args.keys() }
pub fn entry(&mut self, arg: &'a str) -> Entry<&'a str, MatchedArg> { self.0.args.entry(arg) } pub fn entry(&mut self, arg: &'a str) -> ordermap::Entry<&'a str, MatchedArg> {
self.0.args.entry(arg)
}
pub fn subcommand(&mut self, sc: SubCommand<'a>) { self.0.subcommand = Some(Box::new(sc)); } pub fn subcommand(&mut self, sc: SubCommand<'a>) { self.0.subcommand = Some(Box::new(sc)); }
pub fn subcommand_name(&self) -> Option<&str> { self.0.subcommand_name() } pub fn subcommand_name(&self) -> Option<&str> { self.0.subcommand_name() }
pub fn iter(&self) -> Iter<&str, MatchedArg> { self.0.args.iter() } pub fn iter(&self) -> ordermap::Iter<&str, MatchedArg> { self.0.args.iter() }
pub fn inc_occurrence_of(&mut self, arg: &'a str) { pub fn inc_occurrence_of(&mut self, arg: &'a str) {
debugln!("ArgMatcher::inc_occurrence_of: arg={}", arg); debugln!("ArgMatcher::inc_occurrence_of: arg={}", arg);
@ -147,23 +127,20 @@ impl<'a> ArgMatcher<'a> {
ma.vals.push(val.to_owned()); ma.vals.push(val.to_owned());
} }
pub fn needs_more_vals<'b, A>(&self, o: &A) -> bool pub fn needs_more_vals<'b>(&self, o: &Arg) -> bool {
where debugln!("ArgMatcher::needs_more_vals: o={}", o.name);
A: AnyArg<'a, 'b>, if let Some(ma) = self.get(o.name) {
{ if let Some(num) = o.num_vals {
debugln!("ArgMatcher::needs_more_vals: o={}", o.name());
if let Some(ma) = self.get(o.name()) {
if let Some(num) = o.num_vals() {
debugln!("ArgMatcher::needs_more_vals: num_vals...{}", num); debugln!("ArgMatcher::needs_more_vals: num_vals...{}", num);
return if o.is_set(ArgSettings::Multiple) { return if o.is_set(ArgSettings::Multiple) {
((ma.vals.len() as u64) % num) != 0 ((ma.vals.len() as u64) % num) != 0
} else { } else {
num != (ma.vals.len() as u64) num != (ma.vals.len() as u64)
}; };
} else if let Some(num) = o.max_vals() { } else if let Some(num) = o.max_vals {
debugln!("ArgMatcher::needs_more_vals: max_vals...{}", num); debugln!("ArgMatcher::needs_more_vals: max_vals...{}", num);
return !((ma.vals.len() as u64) > num); return !((ma.vals.len() as u64) > num);
} else if o.min_vals().is_some() { } else if o.min_vals.is_some() {
debugln!("ArgMatcher::needs_more_vals: min_vals...true"); debugln!("ArgMatcher::needs_more_vals: min_vals...true");
return true; return true;
} }

View file

@ -1,10 +1,12 @@
// Std // Std
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap;
use std::ffi::{OsStr, OsString}; use std::ffi::{OsStr, OsString};
use std::iter::Map; use std::iter::Map;
use std::slice::Iter; use std::slice::Iter;
// Third Party
use ordermap::OrderMap;
// Internal // Internal
use INVALID_UTF8; use INVALID_UTF8;
use args::MatchedArg; use args::MatchedArg;
@ -59,15 +61,18 @@ use args::SubCommand;
/// [`App::get_matches`]: ./struct.App.html#method.get_matches /// [`App::get_matches`]: ./struct.App.html#method.get_matches
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ArgMatches<'a> { pub struct ArgMatches<'a> {
#[doc(hidden)] pub args: HashMap<&'a str, MatchedArg>, #[doc(hidden)]
#[doc(hidden)] pub subcommand: Option<Box<SubCommand<'a>>>, pub args: OrderMap<&'a str, MatchedArg>,
#[doc(hidden)] pub usage: Option<String>, #[doc(hidden)]
pub subcommand: Option<Box<SubCommand<'a>>>,
#[doc(hidden)]
pub usage: Option<String>,
} }
impl<'a> Default for ArgMatches<'a> { impl<'a> Default for ArgMatches<'a> {
fn default() -> Self { fn default() -> Self {
ArgMatches { ArgMatches {
args: HashMap::new(), args: OrderMap::new(),
subcommand: None, subcommand: None,
usage: None, usage: None,
} }
@ -536,7 +541,6 @@ impl<'a> ArgMatches<'a> {
pub fn usage(&self) -> &str { self.usage.as_ref().map_or("", |u| &u[..]) } pub fn usage(&self) -> &str { self.usage.as_ref().map_or("", |u| &u[..]) }
} }
// The following were taken and adapated from vec_map source // The following were taken and adapated from vec_map source
// repo: https://github.com/contain-rs/vec-map // repo: https://github.com/contain-rs/vec-map
// commit: be5e1fa3c26e351761b33010ddbdaf5f05dbcc33 // commit: be5e1fa3c26e351761b33010ddbdaf5f05dbcc33

View file

@ -79,12 +79,18 @@ use yaml_rust::Yaml;
/// [requirement]: ./struct.Arg.html#method.requires /// [requirement]: ./struct.Arg.html#method.requires
#[derive(Default)] #[derive(Default)]
pub struct ArgGroup<'a> { pub struct ArgGroup<'a> {
#[doc(hidden)] pub name: &'a str, #[doc(hidden)]
#[doc(hidden)] pub args: Vec<&'a str>, pub name: &'a str,
#[doc(hidden)] pub required: bool, #[doc(hidden)]
#[doc(hidden)] pub requires: Option<Vec<&'a str>>, pub args: Vec<&'a str>,
#[doc(hidden)] pub conflicts: Option<Vec<&'a str>>, #[doc(hidden)]
#[doc(hidden)] pub multiple: bool, pub required: bool,
#[doc(hidden)]
pub requires: Option<Vec<&'a str>>,
#[doc(hidden)]
pub conflicts: Option<Vec<&'a str>>,
#[doc(hidden)]
pub multiple: bool,
} }
impl<'a> ArgGroup<'a> { impl<'a> ArgGroup<'a> {
@ -431,11 +437,7 @@ impl<'a> Debug for ArgGroup<'a> {
\trequires: {:?},\n\ \trequires: {:?},\n\
\tconflicts: {:?},\n\ \tconflicts: {:?},\n\
}}", }}",
self.name, self.name, self.args, self.required, self.requires, self.conflicts
self.args,
self.required,
self.requires,
self.conflicts
) )
} }
} }
@ -494,8 +496,7 @@ impl<'a> From<&'a BTreeMap<Yaml, Yaml>> for ArgGroup<'a> {
s => panic!( s => panic!(
"Unknown ArgGroup setting '{}' in YAML file for \ "Unknown ArgGroup setting '{}' in YAML file for \
ArgGroup '{}'", ArgGroup '{}'",
s, s, a.name
a.name
), ),
} }
} }

View file

@ -4,8 +4,10 @@ use std::ffi::OsString;
#[doc(hidden)] #[doc(hidden)]
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct MatchedArg { pub struct MatchedArg {
#[doc(hidden)] pub occurs: u64, #[doc(hidden)]
#[doc(hidden)] pub vals: Vec<OsString>, pub occurs: u64,
#[doc(hidden)]
pub vals: Vec<OsString>,
} }
impl Default for MatchedArg { impl Default for MatchedArg {

View file

@ -1,6 +1,4 @@
pub use self::any_arg::{AnyArg, DispOrder};
pub use self::arg::Arg; pub use self::arg::Arg;
pub use self::arg_builder::{Base, FlagBuilder, OptBuilder, PosBuilder, Switched, Valued};
pub use self::arg_matcher::ArgMatcher; pub use self::arg_matcher::ArgMatcher;
pub use self::arg_matches::{ArgMatches, OsValues, Values}; pub use self::arg_matches::{ArgMatches, OsValues, Values};
pub use self::group::ArgGroup; pub use self::group::ArgGroup;
@ -11,11 +9,9 @@ pub use self::subcommand::SubCommand;
#[macro_use] #[macro_use]
mod macros; mod macros;
mod arg; mod arg;
pub mod any_arg;
mod arg_matches; mod arg_matches;
mod arg_matcher; mod arg_matcher;
mod subcommand; mod subcommand;
mod arg_builder;
mod matched_arg; mod matched_arg;
mod group; mod group;
pub mod settings; pub mod settings;

View file

@ -29,8 +29,10 @@ use ArgMatches;
/// [arguments]: ./struct.Arg.html /// [arguments]: ./struct.Arg.html
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct SubCommand<'a> { pub struct SubCommand<'a> {
#[doc(hidden)] pub name: String, #[doc(hidden)]
#[doc(hidden)] pub matches: ArgMatches<'a>, pub name: String,
#[doc(hidden)]
pub matches: ArgMatches<'a>,
} }
impl<'a> SubCommand<'a> { impl<'a> SubCommand<'a> {

View file

@ -2,19 +2,16 @@
use std::io::Write; use std::io::Write;
// Internal // Internal
use app::parser::Parser; use app::App;
use args::{ArgSettings, OptBuilder}; use args::{Arg, ArgSettings};
use completions; use completions;
pub struct BashGen<'a, 'b> pub struct BashGen<'a, 'b>(&'b App<'a, 'b>)
where where
'a: 'b, 'a: 'b;
{
p: &'b Parser<'a, 'b>,
}
impl<'a, 'b> BashGen<'a, 'b> { impl<'a, 'b> BashGen<'a, 'b> {
pub fn new(p: &'b Parser<'a, 'b>) -> Self { BashGen { p: p } } pub fn new(app: &'b App<'a, 'b>) -> Self { BashGen(app) }
pub fn generate_to<W: Write>(&self, buf: &mut W) { pub fn generate_to<W: Write>(&self, buf: &mut W) {
w!( w!(
@ -62,10 +59,9 @@ impl<'a, 'b> BashGen<'a, 'b> {
complete -F _{name} -o bashdefault -o default {name} complete -F _{name} -o bashdefault -o default {name}
", ",
name = self.p.meta.bin_name.as_ref().unwrap(), name = self.0.bin_name.as_ref().unwrap(),
name_opts = self.all_options_for_path(self.p.meta.bin_name.as_ref().unwrap()), name_opts = self.all_options_for_path(self.0.bin_name.as_ref().unwrap()),
name_opts_details = name_opts_details = self.option_details_for_path(self.0.bin_name.as_ref().unwrap()),
self.option_details_for_path(self.p.meta.bin_name.as_ref().unwrap()),
subcmds = self.all_subcommands(), subcmds = self.all_subcommands(),
subcmd_details = self.subcommand_details() subcmd_details = self.subcommand_details()
).as_bytes() ).as_bytes()
@ -75,7 +71,7 @@ complete -F _{name} -o bashdefault -o default {name}
fn all_subcommands(&self) -> String { fn all_subcommands(&self) -> String {
debugln!("BashGen::all_subcommands;"); debugln!("BashGen::all_subcommands;");
let mut subcmds = String::new(); let mut subcmds = String::new();
let scs = completions::all_subcommand_names(self.p); let scs = completions::all_subcommand_names(self.0);
for sc in &scs { for sc in &scs {
subcmds = format!( subcmds = format!(
@ -95,7 +91,7 @@ complete -F _{name} -o bashdefault -o default {name}
fn subcommand_details(&self) -> String { fn subcommand_details(&self) -> String {
debugln!("BashGen::subcommand_details;"); debugln!("BashGen::subcommand_details;");
let mut subcmd_dets = String::new(); let mut subcmd_dets = String::new();
let mut scs = completions::get_all_subcommand_paths(self.p, true); let mut scs = completions::get_all_subcommand_paths(self.0, true);
scs.sort(); scs.sort();
scs.dedup(); scs.dedup();
@ -130,14 +126,14 @@ complete -F _{name} -o bashdefault -o default {name}
fn option_details_for_path(&self, path: &str) -> String { fn option_details_for_path(&self, path: &str) -> String {
debugln!("BashGen::option_details_for_path: path={}", path); debugln!("BashGen::option_details_for_path: path={}", path);
let mut p = self.p; let mut p = self.0;
for sc in path.split("__").skip(1) { for sc in path.split("__").skip(1) {
debugln!("BashGen::option_details_for_path:iter: sc={}", sc); debugln!("BashGen::option_details_for_path:iter: sc={}", sc);
p = &find_subcmd!(p, sc).unwrap().p; p = &find_subcmd!(p, sc).unwrap();
} }
let mut opts = String::new(); let mut opts = String::new();
for o in p.opts() { for o in opts!(p) {
if let Some(l) = o.s.long { if let Some(l) = o.long {
opts = format!( opts = format!(
"{} "{}
--{}) --{})
@ -149,7 +145,7 @@ complete -F _{name} -o bashdefault -o default {name}
self.vals_for(o) self.vals_for(o)
); );
} }
if let Some(s) = o.s.short { if let Some(s) = o.short {
opts = format!( opts = format!(
"{} "{}
-{}) -{})
@ -165,15 +161,14 @@ complete -F _{name} -o bashdefault -o default {name}
opts opts
} }
fn vals_for(&self, o: &OptBuilder) -> String { fn vals_for(&self, o: &Arg) -> String {
debugln!("BashGen::vals_for: o={}", o.b.name); debugln!("BashGen::vals_for: o={}", o.name);
use args::AnyArg;
let mut ret = String::new(); let mut ret = String::new();
let mut needs_quotes = true; let mut needs_quotes = true;
if let Some(vals) = o.possible_vals() { if let Some(ref vals) = o.possible_vals {
needs_quotes = false; needs_quotes = false;
ret = format!("$(compgen -W \"{}\" -- ${{cur}})", vals.join(" ")); ret = format!("$(compgen -W \"{}\" -- ${{cur}})", vals.join(" "));
} else if let Some(vec) = o.val_names() { } else if let Some(ref vec) = o.val_names {
let mut it = vec.iter().peekable(); let mut it = vec.iter().peekable();
while let Some((_, val)) = it.next() { while let Some((_, val)) = it.next() {
ret = format!( ret = format!(
@ -187,13 +182,13 @@ complete -F _{name} -o bashdefault -o default {name}
if o.is_set(ArgSettings::Multiple) && num == 1 { if o.is_set(ArgSettings::Multiple) && num == 1 {
ret = format!("{}...", ret); ret = format!("{}...", ret);
} }
} else if let Some(num) = o.num_vals() { } else if let Some(num) = o.num_vals {
let mut it = (0..num).peekable(); let mut it = (0..num).peekable();
while let Some(_) = it.next() { while let Some(_) = it.next() {
ret = format!( ret = format!(
"{}<{}>{}", "{}<{}>{}",
ret, ret,
o.name(), o.name,
if it.peek().is_some() { " " } else { "" } if it.peek().is_some() { " " } else { "" }
); );
} }
@ -201,7 +196,7 @@ complete -F _{name} -o bashdefault -o default {name}
ret = format!("{}...", ret); ret = format!("{}...", ret);
} }
} else { } else {
ret = format!("<{}>", o.name()); ret = format!("<{}>", o.name);
if o.is_set(ArgSettings::Multiple) { if o.is_set(ArgSettings::Multiple) {
ret = format!("{}...", ret); ret = format!("{}...", ret);
} }
@ -213,43 +208,20 @@ complete -F _{name} -o bashdefault -o default {name}
} }
fn all_options_for_path(&self, path: &str) -> String { fn all_options_for_path(&self, path: &str) -> String {
debugln!("BashGen::all_options_for_path: path={}", path); debugln!("BashGen::all_options_for_path: path={}", path);
let mut p = self.p; let mut p = self.0;
for sc in path.split("__").skip(1) { for sc in path.split("__").skip(1) {
debugln!("BashGen::all_options_for_path:iter: sc={}", sc); debugln!("BashGen::all_options_for_path:iter: sc={}", sc);
p = &find_subcmd!(p, sc).unwrap().p; p = &find_subcmd!(p, sc).unwrap();
} }
let mut opts = shorts!(p).fold(String::new(), |acc, s| format!("{} -{}", acc, s)); let opts = format!(
opts = format!( "{shorts} {longs} {pos} {subcmds}",
"{} {}", shorts = shorts!(p).fold(String::new(), |acc, s| format!("{} -{}", acc, s)),
opts, // Handles aliases too
longs!(p).fold(String::new(), |acc, l| format!("{} --{}", acc, l)) longs = longs!(p).fold(String::new(), |acc, l| format!("{} --{}", acc, l)),
pos = positionals!(p).fold(String::new(), |acc, p| format!("{} {}", acc, p)),
// Handles aliases too
subcmds = sc_names!(p).fold(String::new(), |acc, s| format!("{} {}", acc, s))
); );
opts = format!(
"{} {}",
opts,
p.positionals
.values()
.fold(String::new(), |acc, p| format!("{} {}", acc, p))
);
opts = format!(
"{} {}",
opts,
p.subcommands
.iter()
.fold(String::new(), |acc, s| format!("{} {}", acc, s.p.meta.name))
);
for sc in &p.subcommands {
if let Some(ref aliases) = sc.p.meta.aliases {
opts = format!(
"{} {}",
opts,
aliases
.iter()
.map(|&(n, _)| n)
.fold(String::new(), |acc, a| format!("{} {}", acc, a))
);
}
}
opts opts
} }
} }

View file

@ -2,20 +2,17 @@
use std::io::Write; use std::io::Write;
// Internal // Internal
use app::parser::Parser; use app::App;
pub struct FishGen<'a, 'b> pub struct FishGen<'a, 'b>(&'b App<'a, 'b>)
where where
'a: 'b, 'a: 'b;
{
p: &'b Parser<'a, 'b>,
}
impl<'a, 'b> FishGen<'a, 'b> { impl<'a, 'b> FishGen<'a, 'b> {
pub fn new(p: &'b Parser<'a, 'b>) -> Self { FishGen { p: p } } pub fn new(app: &'b App<'a, 'b>) -> Self { FishGen(app) }
pub fn generate_to<W: Write>(&self, buf: &mut W) { pub fn generate_to<W: Write>(&self, buf: &mut W) {
let command = self.p.meta.bin_name.as_ref().unwrap(); let command = self.0.bin_name.as_ref().unwrap();
// function to detect subcommand // function to detect subcommand
let detect_subcommand_function = r#"function __fish_using_command let detect_subcommand_function = r#"function __fish_using_command
@ -58,48 +55,47 @@ fn gen_fish_inner(root_command: &str, comp_gen: &FishGen, parent_cmds: &str, buf
let basic_template = format!( let basic_template = format!(
"complete -c {} -n \"__fish_using_command {}\"", "complete -c {} -n \"__fish_using_command {}\"",
root_command, root_command, parent_cmds
parent_cmds
); );
for option in comp_gen.p.opts() { for option in opts!(comp_gen.0) {
let mut template = basic_template.clone(); let mut template = basic_template.clone();
if let Some(data) = option.s.short { if let Some(data) = option.short {
template.push_str(format!(" -s {}", data).as_str()); template.push_str(format!(" -s {}", data).as_str());
} }
if let Some(data) = option.s.long { if let Some(data) = option.long {
template.push_str(format!(" -l {}", data).as_str()); template.push_str(format!(" -l {}", data).as_str());
} }
if let Some(data) = option.b.help { if let Some(data) = option.help {
template.push_str(format!(" -d '{}'", escape_string(data)).as_str()); template.push_str(format!(" -d '{}'", escape_string(data)).as_str());
} }
if let Some(ref data) = option.v.possible_vals { if let Some(ref data) = option.possible_vals {
template.push_str(format!(" -r -f -a \"{}\"", data.join(" ")).as_str()); template.push_str(format!(" -r -f -a \"{}\"", data.join(" ")).as_str());
} }
buffer.push_str(template.as_str()); buffer.push_str(template.as_str());
buffer.push_str("\n"); buffer.push_str("\n");
} }
for flag in comp_gen.p.flags() { for flag in flags!(comp_gen.0) {
let mut template = basic_template.clone(); let mut template = basic_template.clone();
if let Some(data) = flag.s.short { if let Some(data) = flag.short {
template.push_str(format!(" -s {}", data).as_str()); template.push_str(format!(" -s {}", data).as_str());
} }
if let Some(data) = flag.s.long { if let Some(data) = flag.long {
template.push_str(format!(" -l {}", data).as_str()); template.push_str(format!(" -l {}", data).as_str());
} }
if let Some(data) = flag.b.help { if let Some(data) = flag.help {
template.push_str(format!(" -d '{}'", escape_string(data)).as_str()); template.push_str(format!(" -d '{}'", escape_string(data)).as_str());
} }
buffer.push_str(template.as_str()); buffer.push_str(template.as_str());
buffer.push_str("\n"); buffer.push_str("\n");
} }
for subcommand in &comp_gen.p.subcommands { for subcommand in subcommands!(comp_gen.0) {
let mut template = basic_template.clone(); let mut template = basic_template.clone();
template.push_str(" -f"); template.push_str(" -f");
template.push_str(format!(" -a \"{}\"", &subcommand.p.meta.name).as_str()); template.push_str(format!(" -a \"{}\"", &subcommand.name).as_str());
if let Some(data) = subcommand.p.meta.about { if let Some(data) = subcommand.about {
template.push_str(format!(" -d '{}'", escape_string(data)).as_str()) template.push_str(format!(" -d '{}'", escape_string(data)).as_str())
} }
buffer.push_str(template.as_str()); buffer.push_str(template.as_str());
@ -107,14 +103,14 @@ fn gen_fish_inner(root_command: &str, comp_gen: &FishGen, parent_cmds: &str, buf
} }
// generate options of subcommands // generate options of subcommands
for subcommand in &comp_gen.p.subcommands { for subcommand in subcommands!(comp_gen.0) {
let sub_comp_gen = FishGen::new(&subcommand.p); let sub_comp_gen = FishGen::new(&subcommand);
// make new "parent_cmds" for different subcommands // make new "parent_cmds" for different subcommands
let mut sub_parent_cmds = parent_cmds.to_string(); let mut sub_parent_cmds = parent_cmds.to_string();
if !sub_parent_cmds.is_empty() { if !sub_parent_cmds.is_empty() {
sub_parent_cmds.push_str(" "); sub_parent_cmds.push_str(" ");
} }
sub_parent_cmds.push_str(&subcommand.p.meta.name); sub_parent_cmds.push_str(&subcommand.name);
gen_fish_inner(root_command, &sub_comp_gen, &sub_parent_cmds, buffer); gen_fish_inner(root_command, &sub_comp_gen, &sub_parent_cmds, buffer);
} }
} }

View file

@ -8,15 +8,15 @@ macro_rules! w {
} }
macro_rules! get_zsh_arg_conflicts { macro_rules! get_zsh_arg_conflicts {
($p:ident, $arg:ident, $msg:ident) => { ($app:expr, $arg:ident, $msg:ident) => {
if let Some(conf_vec) = $arg.blacklist() { if let Some(ref conf_vec) = $arg.blacklist {
let mut v = vec![]; let mut v = vec![];
for arg_name in conf_vec { for arg_name in conf_vec {
let arg = $p.find_any_arg(arg_name).expect($msg); let arg = find!($app, arg_name).expect($msg);
if let Some(s) = arg.short() { if let Some(s) = arg.short {
v.push(format!("-{}", s)); v.push(format!("-{}", s));
} }
if let Some(l) = arg.long() { if let Some(l) = arg.long {
v.push(format!("--{}", l)); v.push(format!("--{}", l));
} }
} }

View file

@ -10,29 +10,26 @@ mod shell;
use std::io::Write; use std::io::Write;
// Internal // Internal
use app::parser::Parser; use app::App;
use self::bash::BashGen; use self::bash::BashGen;
use self::fish::FishGen; use self::fish::FishGen;
use self::zsh::ZshGen; use self::zsh::ZshGen;
use self::powershell::PowerShellGen; use self::powershell::PowerShellGen;
pub use self::shell::Shell; pub use self::shell::Shell;
pub struct ComplGen<'a, 'b> pub struct ComplGen<'a, 'b>(&'b App<'a, 'b>)
where where
'a: 'b, 'a: 'b;
{
p: &'b Parser<'a, 'b>,
}
impl<'a, 'b> ComplGen<'a, 'b> { impl<'a, 'b> ComplGen<'a, 'b> {
pub fn new(p: &'b Parser<'a, 'b>) -> Self { ComplGen { p: p } } pub fn new(app: &'b App<'a, 'b>) -> Self { ComplGen(app) }
pub fn generate<W: Write>(&self, for_shell: Shell, buf: &mut W) { pub fn generate<W: Write>(&self, for_shell: Shell, buf: &mut W) {
match for_shell { match for_shell {
Shell::Bash => BashGen::new(self.p).generate_to(buf), Shell::Bash => BashGen::new(self.0).generate_to(buf),
Shell::Fish => FishGen::new(self.p).generate_to(buf), Shell::Fish => FishGen::new(self.0).generate_to(buf),
Shell::Zsh => ZshGen::new(self.p).generate_to(buf), Shell::Zsh => ZshGen::new(self.0).generate_to(buf),
Shell::PowerShell => PowerShellGen::new(self.p).generate_to(buf), Shell::PowerShell => PowerShellGen::new(self.0).generate_to(buf),
} }
} }
} }
@ -43,13 +40,13 @@ impl<'a, 'b> ComplGen<'a, 'b> {
// //
// Also note, aliases are treated as their own subcommands but duplicates of whatever they're // Also note, aliases are treated as their own subcommands but duplicates of whatever they're
// aliasing. // aliasing.
pub fn all_subcommand_names(p: &Parser) -> Vec<String> { pub fn all_subcommand_names(p: &App) -> Vec<String> {
debugln!("all_subcommand_names;"); debugln!("all_subcommand_names;");
let mut subcmds: Vec<_> = subcommands_of(p) let mut subcmds: Vec<_> = subcommands_of(p)
.iter() .iter()
.map(|&(ref n, _)| n.clone()) .map(|&(ref n, _)| n.clone())
.collect(); .collect();
for sc_v in p.subcommands.iter().map(|s| all_subcommand_names(&s.p)) { for sc_v in subcommands!(p).map(|s| all_subcommand_names(&s)) {
subcmds.extend(sc_v); subcmds.extend(sc_v);
} }
subcmds.sort(); subcmds.sort();
@ -63,10 +60,10 @@ pub fn all_subcommand_names(p: &Parser) -> Vec<String> {
// //
// Also note, aliases are treated as their own subcommands but duplicates of whatever they're // Also note, aliases are treated as their own subcommands but duplicates of whatever they're
// aliasing. // aliasing.
pub fn all_subcommands(p: &Parser) -> Vec<(String, String)> { pub fn all_subcommands(p: &App) -> Vec<(String, String)> {
debugln!("all_subcommands;"); debugln!("all_subcommands;");
let mut subcmds: Vec<_> = subcommands_of(p); let mut subcmds: Vec<_> = subcommands_of(p);
for sc_v in p.subcommands.iter().map(|s| all_subcommands(&s.p)) { for sc_v in subcommands!(p).map(|s| all_subcommands(&s)) {
subcmds.extend(sc_v); subcmds.extend(sc_v);
} }
subcmds subcmds
@ -78,11 +75,11 @@ pub fn all_subcommands(p: &Parser) -> Vec<(String, String)> {
// //
// Also note, aliases are treated as their own subcommands but duplicates of whatever they're // Also note, aliases are treated as their own subcommands but duplicates of whatever they're
// aliasing. // aliasing.
pub fn subcommands_of(p: &Parser) -> Vec<(String, String)> { pub fn subcommands_of(p: &App) -> Vec<(String, String)> {
debugln!( debugln!(
"subcommands_of: name={}, bin_name={}", "subcommands_of: name={}, bin_name={}",
p.meta.name, p.name,
p.meta.bin_name.as_ref().unwrap() p.bin_name.as_ref().unwrap()
); );
let mut subcmds = vec![]; let mut subcmds = vec![];
@ -93,11 +90,10 @@ pub fn subcommands_of(p: &Parser) -> Vec<(String, String)> {
if !p.has_subcommands() { if !p.has_subcommands() {
let mut ret = vec![]; let mut ret = vec![];
debugln!("subcommands_of: Looking for aliases..."); debugln!("subcommands_of: Looking for aliases...");
if let Some(ref aliases) = p.meta.aliases { if let Some(ref aliases) = p.aliases {
for &(n, _) in aliases { for &(n, _) in aliases {
debugln!("subcommands_of:iter:iter: Found alias...{}", n); debugln!("subcommands_of:iter:iter: Found alias...{}", n);
let mut als_bin_name: Vec<_> = let mut als_bin_name: Vec<_> = p.bin_name.as_ref().unwrap().split(' ').collect();
p.meta.bin_name.as_ref().unwrap().split(' ').collect();
als_bin_name.push(n); als_bin_name.push(n);
let old = als_bin_name.len() - 2; let old = als_bin_name.len() - 2;
als_bin_name.swap_remove(old); als_bin_name.swap_remove(old);
@ -106,42 +102,38 @@ pub fn subcommands_of(p: &Parser) -> Vec<(String, String)> {
} }
return ret; return ret;
} }
for sc in &p.subcommands { for sc in subcommands!(p) {
debugln!( debugln!(
"subcommands_of:iter: name={}, bin_name={}", "subcommands_of:iter: name={}, bin_name={}",
sc.p.meta.name, sc.name,
sc.p.meta.bin_name.as_ref().unwrap() sc.bin_name.as_ref().unwrap()
); );
debugln!("subcommands_of:iter: Looking for aliases..."); debugln!("subcommands_of:iter: Looking for aliases...");
if let Some(ref aliases) = sc.p.meta.aliases { if let Some(ref aliases) = sc.aliases {
for &(n, _) in aliases { for &(n, _) in aliases {
debugln!("subcommands_of:iter:iter: Found alias...{}", n); debugln!("subcommands_of:iter:iter: Found alias...{}", n);
let mut als_bin_name: Vec<_> = let mut als_bin_name: Vec<_> = p.bin_name.as_ref().unwrap().split(' ').collect();
p.meta.bin_name.as_ref().unwrap().split(' ').collect();
als_bin_name.push(n); als_bin_name.push(n);
let old = als_bin_name.len() - 2; let old = als_bin_name.len() - 2;
als_bin_name.swap_remove(old); als_bin_name.swap_remove(old);
subcmds.push((n.to_owned(), als_bin_name.join(" "))); subcmds.push((n.to_owned(), als_bin_name.join(" ")));
} }
} }
subcmds.push(( subcmds.push((sc.name.clone(), sc.bin_name.as_ref().unwrap().clone()));
sc.p.meta.name.clone(),
sc.p.meta.bin_name.as_ref().unwrap().clone(),
));
} }
subcmds subcmds
} }
pub fn get_all_subcommand_paths(p: &Parser, first: bool) -> Vec<String> { pub fn get_all_subcommand_paths(p: &App, first: bool) -> Vec<String> {
debugln!("get_all_subcommand_paths;"); debugln!("get_all_subcommand_paths;");
let mut subcmds = vec![]; let mut subcmds = vec![];
if !p.has_subcommands() { if !p.has_subcommands() {
if !first { if !first {
let name = &*p.meta.name; let name = &*p.name;
let path = p.meta.bin_name.as_ref().unwrap().clone().replace(" ", "__"); let path = p.bin_name.as_ref().unwrap().clone().replace(" ", "__");
let mut ret = vec![path.clone()]; let mut ret = vec![path.clone()];
if let Some(ref aliases) = p.meta.aliases { if let Some(ref aliases) = p.aliases {
for &(n, _) in aliases { for &(n, _) in aliases {
ret.push(path.replace(name, n)); ret.push(path.replace(name, n));
} }
@ -150,26 +142,17 @@ pub fn get_all_subcommand_paths(p: &Parser, first: bool) -> Vec<String> {
} }
return vec![]; return vec![];
} }
for sc in &p.subcommands { for sc in subcommands!(p) {
let name = &*sc.p.meta.name; let name = &*sc.name;
let path = sc.p let path = sc.bin_name.as_ref().unwrap().clone().replace(" ", "__");
.meta
.bin_name
.as_ref()
.unwrap()
.clone()
.replace(" ", "__");
subcmds.push(path.clone()); subcmds.push(path.clone());
if let Some(ref aliases) = sc.p.meta.aliases { if let Some(ref aliases) = sc.aliases {
for &(n, _) in aliases { for &(n, _) in aliases {
subcmds.push(path.replace(name, n)); subcmds.push(path.replace(name, n));
} }
} }
} }
for sc_v in p.subcommands for sc_v in subcommands!(p).map(|s| get_all_subcommand_paths(&s, false)) {
.iter()
.map(|s| get_all_subcommand_paths(&s.p, false))
{
subcmds.extend(sc_v); subcmds.extend(sc_v);
} }
subcmds subcmds

View file

@ -2,25 +2,22 @@
use std::io::Write; use std::io::Write;
// Internal // Internal
use app::parser::Parser; use app::App;
use INTERNAL_ERROR_MSG; use INTERNAL_ERROR_MSG;
pub struct PowerShellGen<'a, 'b> pub struct PowerShellGen<'a, 'b>(&'b App<'a, 'b>)
where where
'a: 'b, 'a: 'b;
{
p: &'b Parser<'a, 'b>,
}
impl<'a, 'b> PowerShellGen<'a, 'b> { impl<'a, 'b> PowerShellGen<'a, 'b> {
pub fn new(p: &'b Parser<'a, 'b>) -> Self { PowerShellGen { p: p } } pub fn new(app: &'b App<'a, 'b>) -> Self { PowerShellGen(app) }
pub fn generate_to<W: Write>(&self, buf: &mut W) { pub fn generate_to<W: Write>(&self, buf: &mut W) {
let bin_name = self.p.meta.bin_name.as_ref().unwrap(); let bin_name = self.0.bin_name.as_ref().unwrap();
let mut names = vec![]; let mut names = vec![];
let (subcommands_detection_cases, subcommands_cases) = let (subcommands_detection_cases, subcommands_cases) =
generate_inner(self.p, "", &mut names); generate_inner(self.0, "", &mut names);
let mut bin_names = vec![bin_name.to_string(), format!("./{0}", bin_name)]; let mut bin_names = vec![bin_name.to_string(), format!("./{0}", bin_name)];
if cfg!(windows) { if cfg!(windows) {
@ -76,7 +73,7 @@ impl<'a, 'b> PowerShellGen<'a, 'b> {
} }
fn generate_inner<'a, 'b, 'p>( fn generate_inner<'a, 'b, 'p>(
p: &'p Parser<'a, 'b>, p: &'p App<'a, 'b>,
previous_command_name: &str, previous_command_name: &str,
names: &mut Vec<&'p str>, names: &mut Vec<&'p str>,
) -> (String, String) { ) -> (String, String) {
@ -85,14 +82,14 @@ fn generate_inner<'a, 'b, 'p>(
format!( format!(
"{}_{}", "{}_{}",
previous_command_name, previous_command_name,
&p.meta.bin_name.as_ref().expect(INTERNAL_ERROR_MSG) &p.bin_name.as_ref().expect(INTERNAL_ERROR_MSG)
) )
} else { } else {
format!("{}_{}", previous_command_name, &p.meta.name) format!("{}_{}", previous_command_name, &p.name)
}; };
let mut subcommands_detection_cases = if !names.contains(&&*p.meta.name) { let mut subcommands_detection_cases = if !names.contains(&&*p.name) {
names.push(&*p.meta.name); names.push(&*p.name);
format!( format!(
r" r"
'{0}' {{ '{0}' {{
@ -100,7 +97,7 @@ fn generate_inner<'a, 'b, 'p>(
break break
}} }}
", ",
&p.meta.name &p.name
) )
} else { } else {
String::new() String::new()
@ -108,7 +105,7 @@ fn generate_inner<'a, 'b, 'p>(
let mut completions = String::new(); let mut completions = String::new();
for subcommand in &p.subcommands { for subcommand in &p.subcommands {
completions.push_str(&format!("'{}', ", &subcommand.p.meta.name)); completions.push_str(&format!("'{}', ", &subcommand.name));
} }
for short in shorts!(p) { for short in shorts!(p) {
completions.push_str(&format!("'-{}', ", short)); completions.push_str(&format!("'-{}', ", short));
@ -127,9 +124,9 @@ fn generate_inner<'a, 'b, 'p>(
completions.trim_right_matches(", ") completions.trim_right_matches(", ")
); );
for subcommand in &p.subcommands { for subcommand in subcommands!(p) {
let (subcommand_subcommands_detection_cases, subcommand_subcommands_cases) = let (subcommand_subcommands_detection_cases, subcommand_subcommands_cases) =
generate_inner(&subcommand.p, &command_name, names); generate_inner(&subcommand, &command_name, names);
subcommands_detection_cases.push_str(&subcommand_subcommands_detection_cases); subcommands_detection_cases.push_str(&subcommand_subcommands_detection_cases);
subcommands_cases.push_str(&subcommand_subcommands_cases); subcommands_cases.push_str(&subcommand_subcommands_cases);
} }

View file

@ -5,22 +5,18 @@ use std::ascii::AsciiExt;
// Internal // Internal
use app::App; use app::App;
use app::parser::Parser; use args::ArgSettings;
use args::{AnyArg, ArgSettings};
use completions; use completions;
use INTERNAL_ERROR_MSG; use INTERNAL_ERROR_MSG;
pub struct ZshGen<'a, 'b> pub struct ZshGen<'a, 'b>(&'b App<'a, 'b>)
where where
'a: 'b, 'a: 'b;
{
p: &'b Parser<'a, 'b>,
}
impl<'a, 'b> ZshGen<'a, 'b> { impl<'a, 'b> ZshGen<'a, 'b> {
pub fn new(p: &'b Parser<'a, 'b>) -> Self { pub fn new(app: &'b App<'a, 'b>) -> Self {
debugln!("ZshGen::new;"); debugln!("ZshGen::new;");
ZshGen { p: p } ZshGen(app)
} }
pub fn generate_to<W: Write>(&self, buf: &mut W) { pub fn generate_to<W: Write>(&self, buf: &mut W) {
@ -52,10 +48,10 @@ _{name}() {{
{subcommand_details} {subcommand_details}
_{name} \"$@\"", _{name} \"$@\"",
name = self.p.meta.bin_name.as_ref().unwrap(), name = self.0.bin_name.as_ref().unwrap(),
initial_args = get_args_of(self.p), initial_args = get_args_of(self.0),
subcommands = get_subcommands_of(self.p), subcommands = get_subcommands_of(self.0),
subcommand_details = subcommand_details(self.p) subcommand_details = subcommand_details(self.0)
).as_bytes() ).as_bytes()
); );
} }
@ -88,7 +84,7 @@ _{name} \"$@\"",
// ) // )
// _describe -t commands 'rustup commands' commands "$@" // _describe -t commands 'rustup commands' commands "$@"
// //
fn subcommand_details(p: &Parser) -> String { fn subcommand_details(p: &App) -> String {
debugln!("ZshGen::subcommand_details;"); debugln!("ZshGen::subcommand_details;");
// First we do ourself // First we do ourself
let mut ret = vec![ let mut ret = vec![
@ -101,8 +97,8 @@ _{bin_name_underscore}_commands() {{
) )
_describe -t commands '{bin_name} commands' commands \"$@\" _describe -t commands '{bin_name} commands' commands \"$@\"
}}", }}",
bin_name_underscore = p.meta.bin_name.as_ref().unwrap().replace(" ", "__"), bin_name_underscore = p.bin_name.as_ref().unwrap().replace(" ", "__"),
bin_name = p.meta.bin_name.as_ref().unwrap(), bin_name = p.bin_name.as_ref().unwrap(),
subcommands_and_args = subcommands_of(p) subcommands_and_args = subcommands_of(p)
), ),
]; ];
@ -142,7 +138,7 @@ _{bin_name_underscore}_commands() {{
// A snippet from rustup: // A snippet from rustup:
// 'show:Show the active and installed toolchains' // 'show:Show the active and installed toolchains'
// 'update:Update Rust toolchains' // 'update:Update Rust toolchains'
fn subcommands_of(p: &Parser) -> String { fn subcommands_of(p: &App) -> String {
debugln!("ZshGen::subcommands_of;"); debugln!("ZshGen::subcommands_of;");
let mut ret = vec![]; let mut ret = vec![];
fn add_sc(sc: &App, n: &str, ret: &mut Vec<String>) { fn add_sc(sc: &App, n: &str, ret: &mut Vec<String>) {
@ -150,9 +146,7 @@ fn subcommands_of(p: &Parser) -> String {
let s = format!( let s = format!(
"\"{name}:{help}\" \\", "\"{name}:{help}\" \\",
name = n, name = n,
help = sc.p help = sc.about
.meta
.about
.unwrap_or("") .unwrap_or("")
.replace("[", "\\[") .replace("[", "\\[")
.replace("]", "\\]") .replace("]", "\\]")
@ -163,13 +157,10 @@ fn subcommands_of(p: &Parser) -> String {
} }
// The subcommands // The subcommands
for sc in p.subcommands() { for sc in subcommands!(p) {
debugln!( debugln!("ZshGen::subcommands_of:iter: subcommand={}", sc.name);
"ZshGen::subcommands_of:iter: subcommand={}", add_sc(sc, &sc.name, &mut ret);
sc.p.meta.name if let Some(ref v) = sc.aliases {
);
add_sc(sc, &sc.p.meta.name, &mut ret);
if let Some(ref v) = sc.p.meta.aliases {
for alias in v.iter().filter(|&&(_, vis)| vis).map(|&(n, _)| n) { for alias in v.iter().filter(|&&(_, vis)| vis).map(|&(n, _)| n) {
add_sc(sc, alias, &mut ret); add_sc(sc, alias, &mut ret);
} }
@ -208,7 +199,7 @@ fn subcommands_of(p: &Parser) -> String {
// [name_hyphen] = The full space deliniated bin_name, but replace spaces with hyphens // [name_hyphen] = The full space deliniated bin_name, but replace spaces with hyphens
// [repeat] = From the same recursive calls, but for all subcommands // [repeat] = From the same recursive calls, but for all subcommands
// [subcommand_args] = The same as zsh::get_args_of // [subcommand_args] = The same as zsh::get_args_of
fn get_subcommands_of(p: &Parser) -> String { fn get_subcommands_of(p: &App) -> String {
debugln!("get_subcommands_of;"); debugln!("get_subcommands_of;");
debugln!( debugln!(
@ -247,19 +238,20 @@ fn get_subcommands_of(p: &Parser) -> String {
esac esac
;; ;;
esac", esac",
name = p.meta.name, name = p.name,
name_hyphen = p.meta.bin_name.as_ref().unwrap().replace(" ", "-"), name_hyphen = p.bin_name.as_ref().unwrap().replace(" ", "-"),
subcommands = subcmds.join("\n"), subcommands = subcmds.join("\n"),
pos = p.positionals().len() + 1 pos = positionals!(p).count() + 1
) )
} }
fn parser_of<'a, 'b>(p: &'b Parser<'a, 'b>, sc: &str) -> &'b Parser<'a, 'b> { fn parser_of<'a, 'b>(p: &'b App<'a, 'b>, mut sc: &str) -> &'b App<'a, 'b> {
debugln!("parser_of: sc={}", sc); debugln!("parser_of: sc={}", sc);
if sc == p.meta.bin_name.as_ref().unwrap_or(&String::new()) { if sc == p.bin_name.as_ref().unwrap_or(&String::new()) {
return p; return p;
} }
&p.find_subcommand(sc).expect(INTERNAL_ERROR_MSG).p sc = sc.split(" ").last().unwrap();
find_subcmd!(p, sc).expect(INTERNAL_ERROR_MSG)
} }
// Writes out the args section, which ends up being the flags, opts and postionals, and a jump to // Writes out the args section, which ends up being the flags, opts and postionals, and a jump to
@ -282,7 +274,7 @@ fn parser_of<'a, 'b>(p: &'b Parser<'a, 'b>, sc: &str) -> &'b Parser<'a, 'b> {
// -C: modify the $context internal variable // -C: modify the $context internal variable
// -s: Allow stacking of short args (i.e. -a -b -c => -abc) // -s: Allow stacking of short args (i.e. -a -b -c => -abc)
// -S: Do not complete anything after '--' and treat those as argument values // -S: Do not complete anything after '--' and treat those as argument values
fn get_args_of(p: &Parser) -> String { fn get_args_of(p: &App) -> String {
debugln!("get_args_of;"); debugln!("get_args_of;");
let mut ret = vec![String::from("_arguments \"${_arguments_options[@]}\" \\")]; let mut ret = vec![String::from("_arguments \"${_arguments_options[@]}\" \\")];
let opts = write_opts_of(p); let opts = write_opts_of(p);
@ -291,13 +283,13 @@ fn get_args_of(p: &Parser) -> String {
let sc_or_a = if p.has_subcommands() { let sc_or_a = if p.has_subcommands() {
format!( format!(
"\":: :_{name}_commands\" \\", "\":: :_{name}_commands\" \\",
name = p.meta.bin_name.as_ref().unwrap().replace(" ", "__") name = p.bin_name.as_ref().unwrap().replace(" ", "__")
) )
} else { } else {
String::new() String::new()
}; };
let sc = if p.has_subcommands() { let sc = if p.has_subcommands() {
format!("\"*::: :->{name}\" \\", name = p.meta.name) format!("\"*::: :->{name}\" \\", name = p.name)
} else { } else {
String::new() String::new()
}; };
@ -341,12 +333,12 @@ fn escape_value(string: &str) -> String {
.replace(" ", "\\ ") .replace(" ", "\\ ")
} }
fn write_opts_of(p: &Parser) -> String { fn write_opts_of(p: &App) -> String {
debugln!("write_opts_of;"); debugln!("write_opts_of;");
let mut ret = vec![]; let mut ret = vec![];
for o in p.opts() { for o in opts!(p) {
debugln!("write_opts_of:iter: o={}", o.name()); debugln!("write_opts_of:iter: o={}", o.name);
let help = o.help().map_or(String::new(), escape_help); let help = o.help.map_or(String::new(), escape_help);
let mut conflicts = get_zsh_arg_conflicts!(p, o, INTERNAL_ERROR_MSG); let mut conflicts = get_zsh_arg_conflicts!(p, o, INTERNAL_ERROR_MSG);
conflicts = if conflicts.is_empty() { conflicts = if conflicts.is_empty() {
String::new() String::new()
@ -359,13 +351,19 @@ fn write_opts_of(p: &Parser) -> String {
} else { } else {
"" ""
}; };
let pv = if let Some(pv_vec) = o.possible_vals() { let pv = if let Some(ref pv_vec) = o.possible_vals {
format!(": :({})", pv_vec.iter().map( format!(
|v| escape_value(*v)).collect::<Vec<String>>().join(" ")) ": :({})",
pv_vec
.iter()
.map(|v| escape_value(*v))
.collect::<Vec<String>>()
.join(" ")
)
} else { } else {
String::new() String::new()
}; };
if let Some(short) = o.short() { if let Some(short) = o.short {
let s = format!( let s = format!(
"'{conflicts}{multiple}-{arg}+[{help}]{possible_values}' \\", "'{conflicts}{multiple}-{arg}+[{help}]{possible_values}' \\",
conflicts = conflicts, conflicts = conflicts,
@ -378,7 +376,7 @@ fn write_opts_of(p: &Parser) -> String {
debugln!("write_opts_of:iter: Wrote...{}", &*s); debugln!("write_opts_of:iter: Wrote...{}", &*s);
ret.push(s); ret.push(s);
} }
if let Some(long) = o.long() { if let Some(long) = o.long {
let l = format!( let l = format!(
"'{conflicts}{multiple}--{arg}=[{help}]{possible_values}' \\", "'{conflicts}{multiple}--{arg}=[{help}]{possible_values}' \\",
conflicts = conflicts, conflicts = conflicts,
@ -396,12 +394,12 @@ fn write_opts_of(p: &Parser) -> String {
ret.join("\n") ret.join("\n")
} }
fn write_flags_of(p: &Parser) -> String { fn write_flags_of(p: &App) -> String {
debugln!("write_flags_of;"); debugln!("write_flags_of;");
let mut ret = vec![]; let mut ret = vec![];
for f in p.flags() { for f in flags!(p) {
debugln!("write_flags_of:iter: f={}", f.name()); debugln!("write_flags_of:iter: f={}", f.name);
let help = f.help().map_or(String::new(), escape_help); let help = f.help.map_or(String::new(), escape_help);
let mut conflicts = get_zsh_arg_conflicts!(p, f, INTERNAL_ERROR_MSG); let mut conflicts = get_zsh_arg_conflicts!(p, f, INTERNAL_ERROR_MSG);
conflicts = if conflicts.is_empty() { conflicts = if conflicts.is_empty() {
String::new() String::new()
@ -414,7 +412,7 @@ fn write_flags_of(p: &Parser) -> String {
} else { } else {
"" ""
}; };
if let Some(short) = f.short() { if let Some(short) = f.short {
let s = format!( let s = format!(
"'{conflicts}{multiple}-{arg}[{help}]' \\", "'{conflicts}{multiple}-{arg}[{help}]' \\",
multiple = multiple, multiple = multiple,
@ -427,7 +425,7 @@ fn write_flags_of(p: &Parser) -> String {
ret.push(s); ret.push(s);
} }
if let Some(long) = f.long() { if let Some(long) = f.long {
let l = format!( let l = format!(
"'{conflicts}{multiple}--{arg}[{help}]' \\", "'{conflicts}{multiple}--{arg}[{help}]' \\",
conflicts = conflicts, conflicts = conflicts,
@ -444,24 +442,33 @@ fn write_flags_of(p: &Parser) -> String {
ret.join("\n") ret.join("\n")
} }
fn write_positionals_of(p: &Parser) -> String { fn write_positionals_of(p: &App) -> String {
debugln!("write_positionals_of;"); debugln!("write_positionals_of;");
let mut ret = vec![]; let mut ret = vec![];
for arg in p.positionals() { for arg in positionals!(p) {
debugln!("write_positionals_of:iter: arg={}", arg.b.name); debugln!("write_positionals_of:iter: arg={}", arg.name);
let a = format!( let a = format!(
"'{optional}:{name}{help}:{action}' \\", "'{optional}:{name}{help}:{action}' \\",
optional = if !arg.b.is_set(ArgSettings::Required) { ":" } else { "" }, optional = if !arg.is_set(ArgSettings::Required) {
name = arg.b.name, ":"
help = arg.b } else {
.help ""
},
name = arg.name,
help = arg.help
.map_or("".to_owned(), |v| " -- ".to_owned() + v) .map_or("".to_owned(), |v| " -- ".to_owned() + v)
.replace("[", "\\[") .replace("[", "\\[")
.replace("]", "\\]"), .replace("]", "\\]"),
action = arg.possible_vals().map_or("_files".to_owned(), |values| { action = arg.possible_vals
format!("({})", .as_ref()
values.iter().map(|v| escape_value(*v)).collect::<Vec<String>>().join(" ")) .map_or("_files".to_owned(), |values| format!(
}) "({})",
values
.iter()
.map(|v| escape_value(*v))
.collect::<Vec<String>>()
.join(" ")
))
); );
debugln!("write_positionals_of:iter: Wrote...{}", a); debugln!("write_positionals_of:iter: Wrote...{}", a);

View file

@ -8,7 +8,7 @@ use std::process;
use std::result::Result as StdResult; use std::result::Result as StdResult;
// Internal // Internal
use args::AnyArg; use args::Arg;
use fmt::{ColorWhen, Colorizer, ColorizerOption}; use fmt::{ColorWhen, Colorizer, ColorizerOption};
use suggestions; use suggestions;
@ -405,7 +405,7 @@ impl Error {
#[doc(hidden)] #[doc(hidden)]
pub fn argument_conflict<'a, 'b, O, U>( pub fn argument_conflict<'a, 'b, O, U>(
arg: &AnyArg, arg: &Arg,
other: Option<O>, other: Option<O>,
usage: U, usage: U,
color: ColorWhen, color: ColorWhen,
@ -414,7 +414,7 @@ impl Error {
O: Into<String>, O: Into<String>,
U: Display, U: Display,
{ {
let mut v = vec![arg.name().to_owned()]; let mut v = vec![arg.name.to_owned()];
let c = Colorizer::new(ColorizerOption { let c = Colorizer::new(ColorizerOption {
use_stderr: true, use_stderr: true,
when: color, when: color,
@ -443,7 +443,7 @@ impl Error {
} }
#[doc(hidden)] #[doc(hidden)]
pub fn empty_value<'a, 'b, U>(arg: &AnyArg, usage: U, color: ColorWhen) -> Self pub fn empty_value<'a, 'b, U>(arg: &Arg, usage: U, color: ColorWhen) -> Self
where where
U: Display, U: Display,
{ {
@ -463,7 +463,7 @@ impl Error {
c.good("--help") c.good("--help")
), ),
kind: ErrorKind::EmptyValue, kind: ErrorKind::EmptyValue,
info: Some(vec![arg.name().to_owned()]), info: Some(vec![arg.name.to_owned()]),
} }
} }
@ -471,7 +471,7 @@ impl Error {
pub fn invalid_value<'a, 'b, B, G, U>( pub fn invalid_value<'a, 'b, B, G, U>(
bad_val: B, bad_val: B,
good_vals: &[G], good_vals: &[G],
arg: &AnyArg, arg: &Arg,
usage: U, usage: U,
color: ColorWhen, color: ColorWhen,
) -> Self ) -> Self
@ -509,7 +509,7 @@ impl Error {
c.good("--help") c.good("--help")
), ),
kind: ErrorKind::InvalidValue, kind: ErrorKind::InvalidValue,
info: Some(vec![arg.name().to_owned(), bad_val.as_ref().to_owned()]), info: Some(vec![arg.name.to_owned(), bad_val.as_ref().to_owned()]),
} }
} }
@ -632,7 +632,6 @@ impl Error {
} }
} }
#[doc(hidden)] #[doc(hidden)]
pub fn invalid_utf8<U>(usage: U, color: ColorWhen) -> Self pub fn invalid_utf8<U>(usage: U, color: ColorWhen) -> Self
where where
@ -657,7 +656,7 @@ impl Error {
} }
#[doc(hidden)] #[doc(hidden)]
pub fn too_many_values<'a, 'b, V, U>(val: V, arg: &AnyArg, usage: U, color: ColorWhen) -> Self pub fn too_many_values<'a, 'b, V, U>(val: V, arg: &Arg, usage: U, color: ColorWhen) -> Self
where where
V: AsRef<str> + Display + ToOwned, V: AsRef<str> + Display + ToOwned,
U: Display, U: Display,
@ -680,13 +679,13 @@ impl Error {
c.good("--help") c.good("--help")
), ),
kind: ErrorKind::TooManyValues, kind: ErrorKind::TooManyValues,
info: Some(vec![arg.name().to_owned(), v.to_owned()]), info: Some(vec![arg.name.to_owned(), v.to_owned()]),
} }
} }
#[doc(hidden)] #[doc(hidden)]
pub fn too_few_values<'a, 'b, U>( pub fn too_few_values<'a, 'b, U>(
arg: &AnyArg, arg: &Arg,
min_vals: u64, min_vals: u64,
curr_vals: usize, curr_vals: usize,
usage: U, usage: U,
@ -714,13 +713,12 @@ impl Error {
c.good("--help") c.good("--help")
), ),
kind: ErrorKind::TooFewValues, kind: ErrorKind::TooFewValues,
info: Some(vec![arg.name().to_owned()]), info: Some(vec![arg.name.to_owned()]),
} }
} }
#[doc(hidden)] #[doc(hidden)]
pub fn value_validation<'a, 'b>(arg: Option<&AnyArg>, err: String, color: ColorWhen) -> Self pub fn value_validation<'a, 'b>(arg: Option<&Arg>, err: String, color: ColorWhen) -> Self {
{
let c = Colorizer::new(ColorizerOption { let c = Colorizer::new(ColorizerOption {
use_stderr: true, use_stderr: true,
when: color, when: color,
@ -743,13 +741,13 @@ impl Error {
#[doc(hidden)] #[doc(hidden)]
pub fn value_validation_auto(err: String) -> Self { pub fn value_validation_auto(err: String) -> Self {
let n: Option<&AnyArg> = None; let n: Option<&Arg> = None;
Error::value_validation(n, err, ColorWhen::Auto) Error::value_validation(n, err, ColorWhen::Auto)
} }
#[doc(hidden)] #[doc(hidden)]
pub fn wrong_number_of_values<'a, 'b, S, U>( pub fn wrong_number_of_values<'a, 'b, S, U>(
arg: &AnyArg, arg: &Arg,
num_vals: u64, num_vals: u64,
curr_vals: usize, curr_vals: usize,
suffix: S, suffix: S,
@ -779,12 +777,12 @@ impl Error {
c.good("--help") c.good("--help")
), ),
kind: ErrorKind::WrongNumberOfValues, kind: ErrorKind::WrongNumberOfValues,
info: Some(vec![arg.name().to_owned()]), info: Some(vec![arg.name.to_owned()]),
} }
} }
#[doc(hidden)] #[doc(hidden)]
pub fn unexpected_multiple_usage<'a, 'b, U>(arg: &AnyArg, usage: U, color: ColorWhen) -> Self pub fn unexpected_multiple_usage<'a, 'b, U>(arg: &Arg, usage: U, color: ColorWhen) -> Self
where where
U: Display, U: Display,
{ {
@ -804,7 +802,7 @@ impl Error {
c.good("--help") c.good("--help")
), ),
kind: ErrorKind::UnexpectedMultipleUsage, kind: ErrorKind::UnexpectedMultipleUsage,
info: Some(vec![arg.name().to_owned()]), info: Some(vec![arg.name.to_owned()]),
} }
} }

View file

@ -152,7 +152,6 @@ impl<T: fmt::Display> Format<T> {
} }
} }
#[cfg(all(feature = "color", not(target_os = "windows")))] #[cfg(all(feature = "color", not(target_os = "windows")))]
impl<T: AsRef<str>> fmt::Display for Format<T> { impl<T: AsRef<str>> fmt::Display for Format<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", &self.format()) } fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", &self.format()) }

View file

@ -534,6 +534,7 @@ extern crate ansi_term;
extern crate atty; extern crate atty;
#[macro_use] #[macro_use]
extern crate bitflags; extern crate bitflags;
extern crate ordermap;
#[cfg(feature = "suggestions")] #[cfg(feature = "suggestions")]
extern crate strsim; extern crate strsim;
#[cfg(feature = "wrap_help")] #[cfg(feature = "wrap_help")]
@ -548,7 +549,7 @@ extern crate yaml_rust;
#[cfg(feature = "yaml")] #[cfg(feature = "yaml")]
pub use yaml_rust::YamlLoader; pub use yaml_rust::YamlLoader;
pub use args::{Arg, ArgGroup, ArgMatches, ArgSettings, OsValues, SubCommand, Values}; pub use args::{Arg, ArgGroup, ArgMatches, ArgSettings, OsValues, SubCommand, Values};
pub use app::{App, AppSettings}; pub use app::{App, AppSettings, Propagation};
pub use fmt::Format; pub use fmt::Format;
pub use errors::{Error, ErrorKind, Result}; pub use errors::{Error, ErrorKind, Result};
pub use completions::Shell; pub use completions::Shell;
@ -594,7 +595,6 @@ mod derive {
Self::try_from_argmatches(Self::into_app().get_matches_safe()?) Self::try_from_argmatches(Self::into_app().get_matches_safe()?)
} }
/// @TODO @release @docs /// @TODO @release @docs
fn try_parse_from<I, T>(argv: I) -> Result<Self, clap::Error> fn try_parse_from<I, T>(argv: I) -> Result<Self, clap::Error>
where where

View file

@ -852,38 +852,120 @@ macro_rules! write_nspaces {
}) })
} }
// convenience macro for remove an item from a vec macro_rules! args {
//macro_rules! vec_remove_all { ($app:expr, $how:ident) => {
// ($vec:expr, $to_rem:expr) => { $app.args.$how()
// debugln!("vec_remove_all! to_rem={:?}", $to_rem); };
// for i in (0 .. $vec.len()).rev() { ($app:expr) => {
// let should_remove = $to_rem.any(|name| name == &$vec[i]); args!($app, iter)
// if should_remove { $vec.swap_remove(i); } }
// } }
// };
//} macro_rules! args_mut {
($app:expr) => {
args!($app, iter_mut)
}
}
macro_rules! flags {
($app:expr, $how:ident) => {
$app.args.$how()
.filter(|a| !a.settings.is_set(::args::settings::ArgSettings::TakesValue))
.filter(|a| a.short.is_some() || a.long.is_some())
};
($app:expr) => {
flags!($app, iter)
}
}
#[allow(unused_macros)]
macro_rules! flags_mut {
($app:expr) => {
flags!($app, iter_mut)
}
}
macro_rules! opts {
($app:expr, $how:ident) => {
$app.args.$how()
.filter(|a| a.settings.is_set(::args::settings::ArgSettings::TakesValue))
.filter(|a| a.short.is_some() || a.long.is_some())
};
($app:expr) => {
opts!($app, iter)
}
}
#[allow(unused_macros)]
macro_rules! opts_mut {
($app:expr) => {
opts!($app, iter_mut)
}
}
macro_rules! positionals {
($app:expr, $how:ident) => {
$app.args.$how().filter(|a| !(a.short.is_some() || a.long.is_some()))
};
($app:expr) => {
positionals!($app, iter)
}
}
#[allow(unused_macros)]
macro_rules! positionals_mut {
($app:expr) => {
positionals!($app, iter_mut)
}
}
macro_rules! subcommands_cloned {
($app:expr, $how:ident) => {
$app.subcommands.$how().cloned()
};
($app:expr) => {
subcommands_cloned!($app, iter)
}
}
macro_rules! subcommands {
($app:expr, $how:ident) => {
$app.subcommands.$how()
};
($app:expr) => {
subcommands!($app, iter)
}
}
macro_rules! subcommands_mut {
($app:expr) => {
subcommands!($app, iter_mut)
}
}
macro_rules! groups {
($app:expr, $how:ident) => {
$app.groups.$how()
};
($app:expr) => {
groups!($app, iter)
}
}
macro_rules! groups_mut {
($app:expr) => {
groups!($app, iter_mut)
}
}
macro_rules! find_from { macro_rules! find_from {
($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{ ($app:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{
let mut ret = None; let mut ret = None;
for k in $matcher.arg_names() { for k in $matcher.arg_names() {
if let Some(f) = find_by_name!($_self, k, flags, iter) { if let Some(a) = find!($app, k) {
if let Some(ref v) = f.$from() { if let Some(ref v) = a.$from {
if v.contains($arg_name) { if v.contains($arg_name) {
ret = Some(f.to_string()); ret = Some(a.to_string());
}
}
}
if let Some(o) = find_by_name!($_self, k, opts, iter) {
if let Some(ref v) = o.$from() {
if v.contains(&$arg_name) {
ret = Some(o.to_string());
}
}
}
if let Some(pos) = find_by_name!($_self, k, positionals, values) {
if let Some(ref v) = pos.$from() {
if v.contains($arg_name) {
ret = Some(pos.b.name.to_owned());
} }
} }
} }
@ -892,188 +974,114 @@ macro_rules! find_from {
}}; }};
} }
//macro_rules! find_name_from {
// ($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{
// let mut ret = None;
// for k in $matcher.arg_names() {
// if let Some(f) = find_by_name!($_self, k, flags, iter) {
// if let Some(ref v) = f.$from() {
// if v.contains($arg_name) {
// ret = Some(f.b.name);
// }
// }
// }
// if let Some(o) = find_by_name!($_self, k, opts, iter) {
// if let Some(ref v) = o.$from() {
// if v.contains(&$arg_name) {
// ret = Some(o.b.name);
// }
// }
// }
// if let Some(pos) = find_by_name!($_self, k, positionals, values) {
// if let Some(ref v) = pos.$from() {
// if v.contains($arg_name) {
// ret = Some(pos.b.name);
// }
// }
// }
// }
// ret
// }};
//}
macro_rules! find_any_by_name {
($p:expr, $name:expr) => {
{
fn as_trait_obj<'a, 'b, T: AnyArg<'a, 'b>>(x: &T) -> &AnyArg<'a, 'b> { x }
find_by_name!($p, $name, flags, iter).map(as_trait_obj).or(
find_by_name!($p, $name, opts, iter).map(as_trait_obj).or(
find_by_name!($p, $name, positionals, values).map(as_trait_obj)
)
)
}
}
}
// Finds an arg by name // Finds an arg by name
macro_rules! find_by_name { macro_rules! find {
($p:expr, $name:expr, $what:ident, $how:ident) => { ($app:expr, $name:expr, $what:ident) => {
$p.$what.$how().find(|o| o.b.name == $name) $what!($app).find(|a| &a.name == $name)
};
($app:expr, $name:expr) => {
$app.args.iter().find(|a| &a.name == $name)
} }
} }
// Finds an option including if it's aliasesed macro_rules! find_by_long {
macro_rules! find_opt_by_long { ($app:expr, $long:expr, $what:ident) => {{
(@os $_self:ident, $long:expr) => {{ $what!($app)
_find_by_long!($_self, $long, opts) .filter(|a| a.long.is_some())
.find(|a| match_alias!(a, $long, a.long.unwrap()))
}}; }};
($_self:ident, $long:expr) => {{ ($app:expr, $long:expr) => {{
_find_by_long!($_self, $long, opts) $app.args.iter()
.filter(|a| a.long.is_some())
.find(|a| match_alias!(a, $long, a.long.unwrap()))
}}; }};
} }
macro_rules! find_flag_by_long { macro_rules! find_by_short {
(@os $_self:ident, $long:expr) => {{ ($app:expr, $short:expr, $what:ident) => {{
_find_by_long!($_self, $long, flags) $what!($app)
.find(|a| a.short == Some($short))
}}; }};
($_self:ident, $long:expr) => {{ ($app:expr, $short:expr) => {{
_find_by_long!($_self, $long, flags) $app.args.iter()
.find(|a| a.short == Some($short))
}}
}
macro_rules! find_subcmd_cloned {
($_self:expr, $sc:expr) => {{
subcommands_cloned!($_self)
.find(|a| match_alias!(a, $sc, &*a.name))
}}; }};
} }
macro_rules! _find_by_long {
($_self:ident, $long:expr, $what:ident) => {{
$_self.$what
.iter()
.filter(|a| a.s.long.is_some())
.find(|a| {
a.s.long.unwrap() == $long ||
(a.s.aliases.is_some() &&
a.s
.aliases
.as_ref()
.unwrap()
.iter()
.any(|&(alias, _)| alias == $long))
})
}}
}
// Finds an option
macro_rules! find_opt_by_short {
($_self:ident, $short:expr) => {{
_find_by_short!($_self, $short, opts)
}}
}
macro_rules! find_flag_by_short {
($_self:ident, $short:expr) => {{
_find_by_short!($_self, $short, flags)
}}
}
macro_rules! _find_by_short {
($_self:ident, $short:expr, $what:ident) => {{
$_self.$what
.iter()
.filter(|a| a.s.short.is_some())
.find(|a| a.s.short.unwrap() == $short)
}}
}
macro_rules! find_subcmd { macro_rules! find_subcmd {
($_self:expr, $sc:expr) => {{ ($app:expr, $sc:expr) => {{
$_self.subcommands subcommands!($app)
.iter() .find(|a| match_alias!(a, $sc, &*a.name))
.find(|s| {
&*s.p.meta.name == $sc ||
(s.p.meta.aliases.is_some() &&
s.p
.meta
.aliases
.as_ref()
.unwrap()
.iter()
.any(|&(n, _)| n == $sc))
})
}}; }};
} }
macro_rules! shorts { macro_rules! shorts {
($_self:ident) => {{ ($app:expr) => {{
_shorts_longs!($_self, short) _shorts_longs!($app, short)
}}; }};
} }
macro_rules! longs { macro_rules! longs {
($_self:ident) => {{ ($app:expr) => {{
_shorts_longs!($_self, long) $app.args.iter()
.filter(|a| a.long.is_some())
.map(|a| a.long.unwrap())
.chain($app.args.iter()
.filter(|a| a.aliases.is_some())
.flat_map(|a| a.aliases.as_ref().unwrap().iter().map(|als| als.0)))
}}; }};
} }
macro_rules! _shorts_longs { macro_rules! _shorts_longs {
($_self:ident, $what:ident) => {{ ($app:expr, $what:ident) => {{
$_self.flags $app.args.iter().filter_map(|a| a.$what)
.iter()
.filter(|f| f.s.$what.is_some())
.map(|f| f.s.$what.as_ref().unwrap())
.chain($_self.opts.iter()
.filter(|o| o.s.$what.is_some())
.map(|o| o.s.$what.as_ref().unwrap()))
}};
}
macro_rules! arg_names {
($_self:ident) => {{
_names!(@args $_self)
}};
}
macro_rules! sc_names {
($_self:ident) => {{
_names!(@sc $_self)
}}; }};
} }
macro_rules! _names { macro_rules! _names {
(@args $_self:ident) => {{ (@args $app:expr) => {{
$_self.flags $app.args.iter().map(|a| &*a.name)
.iter()
.map(|f| &*f.b.name)
.chain($_self.opts.iter()
.map(|o| &*o.b.name)
.chain($_self.positionals.values()
.map(|p| &*p.b.name)))
}}; }};
(@sc $_self:ident) => {{ (@sc $app:expr) => {{
$_self.subcommands $app.subcommands
.iter() .iter()
.map(|s| &*s.p.meta.name) .map(|s| &*s.name)
.chain($_self.subcommands .chain($app.subcommands
.iter() .iter()
.filter(|s| s.p.meta.aliases.is_some()) .filter(|s| s.aliases.is_some())
.flat_map(|s| s.p.meta.aliases.as_ref().unwrap().iter().map(|&(n, _)| n))) .flat_map(|s| s.aliases.as_ref().unwrap().iter().map(|&(n, _)| n)))
}}
}
macro_rules! arg_names {
($app:expr) => {{
_names!(@args $app)
}};
}
macro_rules! sc_names {
($app:expr) => {{
_names!(@sc $app)
}};
}
macro_rules! match_alias {
($a:expr, $to:expr, $what:expr) => {{
$what == $to ||
($a.aliases.is_some() &&
$a.aliases
.as_ref()
.unwrap()
.iter()
.any(|alias| alias.0 == $to))
}} }}
} }

View file

@ -1,10 +1,10 @@
use app::App;
// Third Party // Third Party
#[cfg(feature = "suggestions")] #[cfg(feature = "suggestions")]
use strsim; use strsim;
// Internal // Internal
use fmt::Format; use fmt::Format;
use app::App;
/// Produces a string from a given list of possible values which is similar to /// Produces a string from a given list of possible values which is similar to
/// the passed in value `v` with a certain confidence. /// the passed in value `v` with a certain confidence.
@ -42,14 +42,13 @@ where
/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase /// Returns a suffix that can be empty, or is the standard 'did you mean' phrase
#[cfg_attr(feature = "lints", allow(needless_lifetimes))] #[cfg_attr(feature = "lints", allow(needless_lifetimes))]
pub fn did_you_mean_flag_suffix<'z, T, I>( pub fn did_you_mean_flag_suffix<'z, I>(
arg: &str, arg: &str,
longs: I, longs: I,
subcommands: &'z [App], subcommands: &'z [App],
) -> (String, Option<&'z str>) ) -> (String, Option<&'z str>)
where where
T: AsRef<str> + 'z, I: IntoIterator<Item = &'z str>,
I: IntoIterator<Item = &'z T>,
{ {
match did_you_mean(arg, longs) { match did_you_mean(arg, longs) {
Some(candidate) => { Some(candidate) => {
@ -61,14 +60,9 @@ where
return (suffix, Some(candidate)); return (suffix, Some(candidate));
} }
None => for subcommand in subcommands { None => for subcommand in subcommands {
let opts = subcommand let longs = longs!(subcommand);
.p
.flags
.iter()
.filter_map(|f| f.s.long)
.chain(subcommand.p.opts.iter().filter_map(|o| o.s.long));
if let Some(candidate) = did_you_mean(arg, opts) { if let Some(candidate) = did_you_mean(arg, longs) {
let suffix = format!( let suffix = format!(
"\n\tDid you mean to put '{}{}' after the subcommand '{}'?", "\n\tDid you mean to put '{}{}' after the subcommand '{}'?",
Format::Good("--"), Format::Good("--"),

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
extern crate clap; extern crate clap;
extern crate regex; extern crate regex;
use clap::{App, Arg, SubCommand, AppSettings, ErrorKind}; use clap::{App, AppSettings, Arg, ErrorKind, Propagation, SubCommand};
include!("../clap-test.rs"); include!("../clap-test.rs");
@ -77,9 +77,7 @@ ARGS:
fn sub_command_negate_required() { fn sub_command_negate_required() {
App::new("sub_command_negate") App::new("sub_command_negate")
.setting(AppSettings::SubcommandsNegateReqs) .setting(AppSettings::SubcommandsNegateReqs)
.arg(Arg::with_name("test") .arg(Arg::with_name("test").required(true).index(1))
.required(true)
.index(1))
.subcommand(SubCommand::with_name("sub1")) .subcommand(SubCommand::with_name("sub1"))
.get_matches_from(vec!["myprog", "sub1"]); .get_matches_from(vec!["myprog", "sub1"]);
} }
@ -90,17 +88,15 @@ fn global_version() {
.setting(AppSettings::GlobalVersion) .setting(AppSettings::GlobalVersion)
.version("1.1") .version("1.1")
.subcommand(SubCommand::with_name("sub1")); .subcommand(SubCommand::with_name("sub1"));
app.p.propagate_settings(); app._propagate(Propagation::NextLevel);
assert_eq!(app.p.subcommands[0].p.meta.version, Some("1.1")); assert_eq!(app.subcommands[0].version, Some("1.1"));
} }
#[test] #[test]
fn sub_command_negate_required_2() { fn sub_command_negate_required_2() {
let result = App::new("sub_command_negate") let result = App::new("sub_command_negate")
.setting(AppSettings::SubcommandsNegateReqs) .setting(AppSettings::SubcommandsNegateReqs)
.arg(Arg::with_name("test") .arg(Arg::with_name("test").required(true).index(1))
.required(true)
.index(1))
.subcommand(SubCommand::with_name("sub1")) .subcommand(SubCommand::with_name("sub1"))
.get_matches_from_safe(vec![""]); .get_matches_from_safe(vec![""]);
assert!(result.is_err()); assert!(result.is_err());
@ -123,8 +119,7 @@ fn sub_command_required() {
fn arg_required_else_help() { fn arg_required_else_help() {
let result = App::new("arg_required") let result = App::new("arg_required")
.setting(AppSettings::ArgRequiredElseHelp) .setting(AppSettings::ArgRequiredElseHelp)
.arg(Arg::with_name("test") .arg(Arg::with_name("test").index(1))
.index(1))
.get_matches_from_safe(vec![""]); .get_matches_from_safe(vec![""]);
assert!(result.is_err()); assert!(result.is_err());
let err = result.err().unwrap(); let err = result.err().unwrap();
@ -135,8 +130,7 @@ fn arg_required_else_help() {
fn arg_required_else_help_over_reqs() { fn arg_required_else_help_over_reqs() {
let result = App::new("arg_required") let result = App::new("arg_required")
.setting(AppSettings::ArgRequiredElseHelp) .setting(AppSettings::ArgRequiredElseHelp)
.arg(Arg::with_name("test") .arg(Arg::with_name("test").index(1).required(true))
.index(1).required(true))
.get_matches_from_safe(vec![""]); .get_matches_from_safe(vec![""]);
assert!(result.is_err()); assert!(result.is_err());
let err = result.err().unwrap(); let err = result.err().unwrap();
@ -150,9 +144,7 @@ fn infer_subcommands_fail_no_args() {
.setting(AppSettings::InferSubcommands) .setting(AppSettings::InferSubcommands)
.subcommand(SubCommand::with_name("test")) .subcommand(SubCommand::with_name("test"))
.subcommand(SubCommand::with_name("temp")) .subcommand(SubCommand::with_name("temp"))
.get_matches_from_safe(vec![ .get_matches_from_safe(vec!["prog", "te"]);
"prog", "te"
]);
assert!(m.is_err(), "{:#?}", m.unwrap()); assert!(m.is_err(), "{:#?}", m.unwrap());
assert_eq!(m.unwrap_err().kind, ErrorKind::UnrecognizedSubcommand); assert_eq!(m.unwrap_err().kind, ErrorKind::UnrecognizedSubcommand);
} }
@ -164,9 +156,7 @@ fn infer_subcommands_fail_no_args() {
.setting(AppSettings::InferSubcommands) .setting(AppSettings::InferSubcommands)
.subcommand(SubCommand::with_name("test")) .subcommand(SubCommand::with_name("test"))
.subcommand(SubCommand::with_name("temp")) .subcommand(SubCommand::with_name("temp"))
.get_matches_from_safe(vec![ .get_matches_from_safe(vec!["prog", "te"]);
"prog", "te"
]);
assert!(m.is_err(), "{:#?}", m.unwrap()); assert!(m.is_err(), "{:#?}", m.unwrap());
assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidSubcommand); assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidSubcommand);
} }
@ -178,9 +168,7 @@ fn infer_subcommands_fail_with_args() {
.arg(Arg::with_name("some")) .arg(Arg::with_name("some"))
.subcommand(SubCommand::with_name("test")) .subcommand(SubCommand::with_name("test"))
.subcommand(SubCommand::with_name("temp")) .subcommand(SubCommand::with_name("temp"))
.get_matches_from_safe(vec![ .get_matches_from_safe(vec!["prog", "t"]);
"prog", "t"
]);
assert!(m.is_ok(), "{:?}", m.unwrap_err().kind); assert!(m.is_ok(), "{:?}", m.unwrap_err().kind);
assert_eq!(m.unwrap().value_of("some"), Some("t")); assert_eq!(m.unwrap().value_of("some"), Some("t"));
} }
@ -192,9 +180,7 @@ fn infer_subcommands_fail_with_args2() {
.arg(Arg::with_name("some")) .arg(Arg::with_name("some"))
.subcommand(SubCommand::with_name("test")) .subcommand(SubCommand::with_name("test"))
.subcommand(SubCommand::with_name("temp")) .subcommand(SubCommand::with_name("temp"))
.get_matches_from_safe(vec![ .get_matches_from_safe(vec!["prog", "te"]);
"prog", "te"
]);
assert!(m.is_ok(), "{:?}", m.unwrap_err().kind); assert!(m.is_ok(), "{:?}", m.unwrap_err().kind);
assert_eq!(m.unwrap().value_of("some"), Some("te")); assert_eq!(m.unwrap().value_of("some"), Some("te"));
} }
@ -204,9 +190,7 @@ fn infer_subcommands_pass() {
let m = App::new("prog") let m = App::new("prog")
.setting(AppSettings::InferSubcommands) .setting(AppSettings::InferSubcommands)
.subcommand(SubCommand::with_name("test")) .subcommand(SubCommand::with_name("test"))
.get_matches_from(vec![ .get_matches_from(vec!["prog", "te"]);
"prog", "te"
]);
assert_eq!(m.subcommand_name(), Some("test")); assert_eq!(m.subcommand_name(), Some("test"));
} }
@ -216,9 +200,7 @@ fn infer_subcommands_pass_close() {
.setting(AppSettings::InferSubcommands) .setting(AppSettings::InferSubcommands)
.subcommand(SubCommand::with_name("test")) .subcommand(SubCommand::with_name("test"))
.subcommand(SubCommand::with_name("temp")) .subcommand(SubCommand::with_name("temp"))
.get_matches_from(vec![ .get_matches_from(vec!["prog", "tes"]);
"prog", "tes"
]);
assert_eq!(m.subcommand_name(), Some("test")); assert_eq!(m.subcommand_name(), Some("test"));
} }
@ -229,9 +211,7 @@ fn infer_subcommands_fail_suggestions() {
.setting(AppSettings::InferSubcommands) .setting(AppSettings::InferSubcommands)
.subcommand(SubCommand::with_name("test")) .subcommand(SubCommand::with_name("test"))
.subcommand(SubCommand::with_name("temp")) .subcommand(SubCommand::with_name("temp"))
.get_matches_from_safe(vec![ .get_matches_from_safe(vec!["prog", "temps"]);
"prog", "temps"
]);
assert!(m.is_err(), "{:#?}", m.unwrap()); assert!(m.is_err(), "{:#?}", m.unwrap());
assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidSubcommand); assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidSubcommand);
} }
@ -243,9 +223,7 @@ fn infer_subcommands_fail_suggestions() {
.setting(AppSettings::InferSubcommands) .setting(AppSettings::InferSubcommands)
.subcommand(SubCommand::with_name("test")) .subcommand(SubCommand::with_name("test"))
.subcommand(SubCommand::with_name("temp")) .subcommand(SubCommand::with_name("temp"))
.get_matches_from_safe(vec![ .get_matches_from_safe(vec!["prog", "temps"]);
"prog", "temps"
]);
assert!(m.is_err(), "{:#?}", m.unwrap()); assert!(m.is_err(), "{:#?}", m.unwrap());
assert_eq!(m.unwrap_err().kind, ErrorKind::UnrecognizedSubcommand); assert_eq!(m.unwrap_err().kind, ErrorKind::UnrecognizedSubcommand);
} }
@ -254,9 +232,7 @@ fn infer_subcommands_fail_suggestions() {
fn no_bin_name() { fn no_bin_name() {
let result = App::new("arg_required") let result = App::new("arg_required")
.setting(AppSettings::NoBinaryName) .setting(AppSettings::NoBinaryName)
.arg(Arg::with_name("test") .arg(Arg::with_name("test").required(true).index(1))
.required(true)
.index(1))
.get_matches_from_safe(vec!["testing"]); .get_matches_from_safe(vec!["testing"]);
assert!(result.is_ok()); assert!(result.is_ok());
let matches = result.unwrap(); let matches = result.unwrap();
@ -271,11 +247,18 @@ fn unified_help() {
.about("tests stuff") .about("tests stuff")
.version("1.3") .version("1.3")
.setting(AppSettings::UnifiedHelpMessage) .setting(AppSettings::UnifiedHelpMessage)
.args_from_usage("-f, --flag 'some flag' .args_from_usage(
[arg1] 'some pos arg' "-f, --flag 'some flag'
--option [opt] 'some option'"); [arg1] 'some pos arg'
--option [opt] 'some option'",
);
assert!(test::compare_output(app, "test --help", UNIFIED_HELP, false)); assert!(test::compare_output(
app,
"test --help",
UNIFIED_HELP,
false
));
} }
#[test] #[test]
@ -285,10 +268,17 @@ fn skip_possible_values() {
.about("tests stuff") .about("tests stuff")
.version("1.3") .version("1.3")
.setting(AppSettings::HidePossibleValuesInHelp) .setting(AppSettings::HidePossibleValuesInHelp)
.args(&[Arg::from_usage("-o, --opt [opt] 'some option'").possible_values(&["one", "two"]), .args(&[
Arg::from_usage("[arg1] 'some pos arg'").possible_values(&["three", "four"])]); Arg::from_usage("-o, --opt [opt] 'some option'").possible_values(&["one", "two"]),
Arg::from_usage("[arg1] 'some pos arg'").possible_values(&["three", "four"]),
]);
assert!(test::compare_output(app, "test --help", SKIP_POS_VALS, false)); assert!(test::compare_output(
app,
"test --help",
SKIP_POS_VALS,
false
));
} }
#[test] #[test]
@ -296,17 +286,15 @@ fn global_setting() {
let mut app = App::new("test") let mut app = App::new("test")
.global_setting(AppSettings::ColoredHelp) .global_setting(AppSettings::ColoredHelp)
.subcommand(SubCommand::with_name("subcmd")); .subcommand(SubCommand::with_name("subcmd"));
app.p.propagate_settings(); app._propagate(Propagation::NextLevel);
assert!(app.p assert!(
.subcommands app.subcommands
.iter() .iter()
.filter(|s| s.p .filter(|s| s.name == "subcmd")
.meta .next()
.name == "subcmd") .unwrap()
.next() .is_set(AppSettings::ColoredHelp)
.unwrap() );
.p
.is_set(AppSettings::ColoredHelp));
} }
#[test] #[test]
@ -314,42 +302,42 @@ fn global_settings() {
let mut app = App::new("test") let mut app = App::new("test")
.global_settings(&[AppSettings::ColoredHelp, AppSettings::TrailingVarArg]) .global_settings(&[AppSettings::ColoredHelp, AppSettings::TrailingVarArg])
.subcommand(SubCommand::with_name("subcmd")); .subcommand(SubCommand::with_name("subcmd"));
app.p.propagate_settings(); app._propagate(Propagation::NextLevel);
assert!(app.p assert!(
.subcommands app.subcommands
.iter() .iter()
.filter(|s| s.p .filter(|s| s.name == "subcmd")
.meta .next()
.name == "subcmd") .unwrap()
.next() .is_set(AppSettings::ColoredHelp)
.unwrap() );
.p assert!(
.is_set(AppSettings::ColoredHelp)); app.subcommands
assert!(app.p .iter()
.subcommands .filter(|s| s.name == "subcmd")
.iter() .next()
.filter(|s| s.p .unwrap()
.meta .is_set(AppSettings::TrailingVarArg)
.name == "subcmd") );
.next()
.unwrap()
.p
.is_set(AppSettings::TrailingVarArg));
} }
#[test] #[test]
fn stop_delim_values_only_pos_follows() { fn stop_delim_values_only_pos_follows() {
let r = App::new("onlypos") let r = App::new("onlypos")
.setting(AppSettings::DontDelimitTrailingValues) .setting(AppSettings::DontDelimitTrailingValues)
.args(&[Arg::from_usage("-f [flag] 'some opt'"), .args(&[
Arg::from_usage("[arg]... 'some arg'")]) Arg::from_usage("-f [flag] 'some opt'"),
Arg::from_usage("[arg]... 'some arg'"),
])
.get_matches_from_safe(vec!["", "--", "-f", "-g,x"]); .get_matches_from_safe(vec!["", "--", "-f", "-g,x"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
assert!(m.is_present("arg")); assert!(m.is_present("arg"));
assert!(!m.is_present("f")); assert!(!m.is_present("f"));
assert_eq!(m.values_of("arg").unwrap().collect::<Vec<_>>(), &["-f", "-g,x"]); assert_eq!(
m.values_of("arg").unwrap().collect::<Vec<_>>(),
&["-f", "-g,x"]
);
} }
#[test] #[test]
@ -357,62 +345,75 @@ fn dont_delim_values_trailingvararg() {
let m = App::new("positional") let m = App::new("positional")
.setting(AppSettings::TrailingVarArg) .setting(AppSettings::TrailingVarArg)
.setting(AppSettings::DontDelimitTrailingValues) .setting(AppSettings::DontDelimitTrailingValues)
.arg( .arg(Arg::from_usage("[opt]... 'some pos'"))
Arg::from_usage("[opt]... 'some pos'"),
)
.get_matches_from(vec!["", "test", "--foo", "-Wl,-bar"]); .get_matches_from(vec!["", "test", "--foo", "-Wl,-bar"]);
assert!(m.is_present("opt")); assert!(m.is_present("opt"));
assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["test", "--foo", "-Wl,-bar"]); assert_eq!(
m.values_of("opt").unwrap().collect::<Vec<_>>(),
&["test", "--foo", "-Wl,-bar"]
);
} }
#[test] #[test]
fn delim_values_only_pos_follows() { fn delim_values_only_pos_follows() {
let r = App::new("onlypos") let r = App::new("onlypos")
.args(&[Arg::from_usage("-f [flag] 'some opt'"), .args(&[
Arg::from_usage("[arg]... 'some arg'")]) Arg::from_usage("-f [flag] 'some opt'"),
Arg::from_usage("[arg]... 'some arg'"),
])
.get_matches_from_safe(vec!["", "--", "-f", "-g,x"]); .get_matches_from_safe(vec!["", "--", "-f", "-g,x"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
assert!(m.is_present("arg")); assert!(m.is_present("arg"));
assert!(!m.is_present("f")); assert!(!m.is_present("f"));
assert_eq!(m.values_of("arg").unwrap().collect::<Vec<_>>(), &["-f", "-g,x"]); assert_eq!(
m.values_of("arg").unwrap().collect::<Vec<_>>(),
&["-f", "-g,x"]
);
} }
#[test] #[test]
fn delim_values_trailingvararg() { fn delim_values_trailingvararg() {
let m = App::new("positional") let m = App::new("positional")
.setting(AppSettings::TrailingVarArg) .setting(AppSettings::TrailingVarArg)
.arg( .arg(Arg::from_usage("[opt]... 'some pos'"))
Arg::from_usage("[opt]... 'some pos'"),
)
.get_matches_from(vec!["", "test", "--foo", "-Wl,-bar"]); .get_matches_from(vec!["", "test", "--foo", "-Wl,-bar"]);
assert!(m.is_present("opt")); assert!(m.is_present("opt"));
assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["test", "--foo", "-Wl,-bar"]); assert_eq!(
m.values_of("opt").unwrap().collect::<Vec<_>>(),
&["test", "--foo", "-Wl,-bar"]
);
} }
#[test] #[test]
fn delim_values_only_pos_follows_with_delim() { fn delim_values_only_pos_follows_with_delim() {
let r = App::new("onlypos") let r = App::new("onlypos")
.args(&[Arg::from_usage("-f [flag] 'some opt'"), .args(&[
Arg::from_usage("[arg]... 'some arg'").use_delimiter(true)]) Arg::from_usage("-f [flag] 'some opt'"),
Arg::from_usage("[arg]... 'some arg'").use_delimiter(true),
])
.get_matches_from_safe(vec!["", "--", "-f", "-g,x"]); .get_matches_from_safe(vec!["", "--", "-f", "-g,x"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
assert!(m.is_present("arg")); assert!(m.is_present("arg"));
assert!(!m.is_present("f")); assert!(!m.is_present("f"));
assert_eq!(m.values_of("arg").unwrap().collect::<Vec<_>>(), &["-f", "-g", "x"]); assert_eq!(
m.values_of("arg").unwrap().collect::<Vec<_>>(),
&["-f", "-g", "x"]
);
} }
#[test] #[test]
fn delim_values_trailingvararg_with_delim() { fn delim_values_trailingvararg_with_delim() {
let m = App::new("positional") let m = App::new("positional")
.setting(AppSettings::TrailingVarArg) .setting(AppSettings::TrailingVarArg)
.arg( .arg(Arg::from_usage("[opt]... 'some pos'").use_delimiter(true))
Arg::from_usage("[opt]... 'some pos'").use_delimiter(true),
)
.get_matches_from(vec!["", "test", "--foo", "-Wl,-bar"]); .get_matches_from(vec!["", "test", "--foo", "-Wl,-bar"]);
assert!(m.is_present("opt")); assert!(m.is_present("opt"));
assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["test", "--foo", "-Wl", "-bar"]); assert_eq!(
m.values_of("opt").unwrap().collect::<Vec<_>>(),
&["test", "--foo", "-Wl", "-bar"]
);
} }
#[test] #[test]
@ -420,8 +421,7 @@ fn leading_hyphen_short() {
let res = App::new("leadhy") let res = App::new("leadhy")
.setting(AppSettings::AllowLeadingHyphen) .setting(AppSettings::AllowLeadingHyphen)
.arg(Arg::with_name("some")) .arg(Arg::with_name("some"))
.arg(Arg::with_name("other") .arg(Arg::with_name("other").short("o"))
.short("o"))
.get_matches_from_safe(vec!["", "-bar", "-o"]); .get_matches_from_safe(vec!["", "-bar", "-o"]);
assert!(res.is_ok(), "Error: {:?}", res.unwrap_err().kind); assert!(res.is_ok(), "Error: {:?}", res.unwrap_err().kind);
let m = res.unwrap(); let m = res.unwrap();
@ -435,8 +435,7 @@ fn leading_hyphen_long() {
let res = App::new("leadhy") let res = App::new("leadhy")
.setting(AppSettings::AllowLeadingHyphen) .setting(AppSettings::AllowLeadingHyphen)
.arg(Arg::with_name("some")) .arg(Arg::with_name("some"))
.arg(Arg::with_name("other") .arg(Arg::with_name("other").short("o"))
.short("o"))
.get_matches_from_safe(vec!["", "--bar", "-o"]); .get_matches_from_safe(vec!["", "--bar", "-o"]);
assert!(res.is_ok(), "Error: {:?}", res.unwrap_err().kind); assert!(res.is_ok(), "Error: {:?}", res.unwrap_err().kind);
let m = res.unwrap(); let m = res.unwrap();
@ -449,11 +448,8 @@ fn leading_hyphen_long() {
fn leading_hyphen_opt() { fn leading_hyphen_opt() {
let res = App::new("leadhy") let res = App::new("leadhy")
.setting(AppSettings::AllowLeadingHyphen) .setting(AppSettings::AllowLeadingHyphen)
.arg(Arg::with_name("some") .arg(Arg::with_name("some").takes_value(true).long("opt"))
.takes_value(true) .arg(Arg::with_name("other").short("o"))
.long("opt"))
.arg(Arg::with_name("other")
.short("o"))
.get_matches_from_safe(vec!["", "--opt", "--bar", "-o"]); .get_matches_from_safe(vec!["", "--opt", "--bar", "-o"]);
assert!(res.is_ok(), "Error: {:?}", res.unwrap_err().kind); assert!(res.is_ok(), "Error: {:?}", res.unwrap_err().kind);
let m = res.unwrap(); let m = res.unwrap();
@ -467,9 +463,7 @@ fn allow_negative_numbers() {
let res = App::new("negnum") let res = App::new("negnum")
.setting(AppSettings::AllowNegativeNumbers) .setting(AppSettings::AllowNegativeNumbers)
.arg(Arg::with_name("panum")) .arg(Arg::with_name("panum"))
.arg(Arg::with_name("onum") .arg(Arg::with_name("onum").short("o").takes_value(true))
.short("o")
.takes_value(true))
.get_matches_from_safe(vec!["negnum", "-20", "-o", "-1.2"]); .get_matches_from_safe(vec!["negnum", "-20", "-o", "-1.2"]);
assert!(res.is_ok(), "Error: {:?}", res.unwrap_err().kind); assert!(res.is_ok(), "Error: {:?}", res.unwrap_err().kind);
let m = res.unwrap(); let m = res.unwrap();
@ -482,9 +476,7 @@ fn allow_negative_numbers_fail() {
let res = App::new("negnum") let res = App::new("negnum")
.setting(AppSettings::AllowNegativeNumbers) .setting(AppSettings::AllowNegativeNumbers)
.arg(Arg::with_name("panum")) .arg(Arg::with_name("panum"))
.arg(Arg::with_name("onum") .arg(Arg::with_name("onum").short("o").takes_value(true))
.short("o")
.takes_value(true))
.get_matches_from_safe(vec!["negnum", "--foo", "-o", "-1.2"]); .get_matches_from_safe(vec!["negnum", "--foo", "-o", "-1.2"]);
assert!(res.is_err()); assert!(res.is_err());
assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument) assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument)
@ -495,33 +487,33 @@ fn leading_double_hyphen_trailingvararg() {
let m = App::new("positional") let m = App::new("positional")
.setting(AppSettings::TrailingVarArg) .setting(AppSettings::TrailingVarArg)
.setting(AppSettings::AllowLeadingHyphen) .setting(AppSettings::AllowLeadingHyphen)
.arg( .arg(Arg::from_usage("[opt]... 'some pos'"))
Arg::from_usage("[opt]... 'some pos'"),
)
.get_matches_from(vec!["", "--foo", "-Wl", "bar"]); .get_matches_from(vec!["", "--foo", "-Wl", "bar"]);
assert!(m.is_present("opt")); assert!(m.is_present("opt"));
assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["--foo", "-Wl", "bar"]); assert_eq!(
m.values_of("opt").unwrap().collect::<Vec<_>>(),
&["--foo", "-Wl", "bar"]
);
} }
#[test] #[test]
fn test_unset_setting() { fn unset_setting() {
let m = App::new("unset_setting"); let m = App::new("unset_setting");
assert!(m.p.is_set(AppSettings::AllowInvalidUtf8)); assert!(m.is_set(AppSettings::AllowInvalidUtf8));
let m = m.unset_setting(AppSettings::AllowInvalidUtf8); let m = m.unset_setting(AppSettings::AllowInvalidUtf8);
assert!(!m.p.is_set(AppSettings::AllowInvalidUtf8)); assert!(!m.is_set(AppSettings::AllowInvalidUtf8));
} }
#[test] #[test]
fn test_unset_settings() { fn unset_settings() {
let m = App::new("unset_settings"); let m = App::new("unset_settings");
assert!(&m.p.is_set(AppSettings::AllowInvalidUtf8)); assert!(&m.is_set(AppSettings::AllowInvalidUtf8));
assert!(&m.p.is_set(AppSettings::ColorAuto)); assert!(&m.is_set(AppSettings::ColorAuto));
let m = m.unset_settings(&[AppSettings::AllowInvalidUtf8, let m = m.unset_settings(&[AppSettings::AllowInvalidUtf8, AppSettings::ColorAuto]);
AppSettings::ColorAuto]); assert!(!m.is_set(AppSettings::AllowInvalidUtf8), "{:?}", m.settings);
assert!(!m.p.is_set(AppSettings::AllowInvalidUtf8)); assert!(!m.is_set(AppSettings::ColorAuto));
assert!(!m.p.is_set(AppSettings::ColorAuto));
} }
#[test] #[test]
@ -545,38 +537,45 @@ fn dont_collapse_args() {
Arg::with_name("arg2").help("some"), Arg::with_name("arg2").help("some"),
Arg::with_name("arg3").help("some"), Arg::with_name("arg3").help("some"),
]); ]);
assert!(test::compare_output(app, "clap-test --help", DONT_COLLAPSE_ARGS, false)); assert!(test::compare_output(
app,
"clap-test --help",
DONT_COLLAPSE_ARGS,
false
));
} }
#[test] #[test]
fn require_eq() { fn require_eq() {
let app = App::new("clap-test") let app = App::new("clap-test").version("v1.4.8").arg(
.version("v1.4.8") Arg::with_name("opt")
.arg(
Arg::with_name("opt")
.long("opt") .long("opt")
.short("o") .short("o")
.required(true) .required(true)
.require_equals(true) .require_equals(true)
.value_name("FILE") .value_name("FILE")
.help("some"), .help("some"),
); );
assert!(test::compare_output(app, "clap-test --help", REQUIRE_EQUALS, false)); assert!(test::compare_output(
app,
"clap-test --help",
REQUIRE_EQUALS,
false
));
} }
#[test] #[test]
fn args_negate_subcommands_one_level() { fn args_negate_subcommands_one_level() {
let res = App::new("disablehelp") let res =
.setting(AppSettings::ArgsNegateSubcommands) App::new("disablehelp")
.setting(AppSettings::SubcommandsNegateReqs) .setting(AppSettings::ArgsNegateSubcommands)
.arg_from_usage("<arg1> 'some arg'") .setting(AppSettings::SubcommandsNegateReqs)
.arg_from_usage("<arg2> 'some arg'") .arg_from_usage("<arg1> 'some arg'")
.subcommand(SubCommand::with_name("sub1") .arg_from_usage("<arg2> 'some arg'")
.subcommand(SubCommand::with_name("sub2") .subcommand(SubCommand::with_name("sub1").subcommand(
.subcommand(SubCommand::with_name("sub3")) SubCommand::with_name("sub2").subcommand(SubCommand::with_name("sub3")),
) ))
) .get_matches_from_safe(vec!["", "pickles", "sub1"]);
.get_matches_from_safe(vec!["", "pickles", "sub1"]);
assert!(res.is_ok(), "error: {:?}", res.unwrap_err().kind); assert!(res.is_ok(), "error: {:?}", res.unwrap_err().kind);
let m = res.unwrap(); let m = res.unwrap();
assert_eq!(m.value_of("arg2"), Some("sub1")); assert_eq!(m.value_of("arg2"), Some("sub1"));
@ -589,20 +588,23 @@ fn args_negate_subcommands_two_levels() {
.global_setting(AppSettings::SubcommandsNegateReqs) .global_setting(AppSettings::SubcommandsNegateReqs)
.arg_from_usage("<arg1> 'some arg'") .arg_from_usage("<arg1> 'some arg'")
.arg_from_usage("<arg2> 'some arg'") .arg_from_usage("<arg2> 'some arg'")
.subcommand(SubCommand::with_name("sub1") .subcommand(
.arg_from_usage("<arg> 'some'") SubCommand::with_name("sub1")
.arg_from_usage("<arg2> 'some'") .arg_from_usage("<arg> 'some'")
.subcommand(SubCommand::with_name("sub2") .arg_from_usage("<arg2> 'some'")
.subcommand(SubCommand::with_name("sub3")) .subcommand(
) SubCommand::with_name("sub2").subcommand(SubCommand::with_name("sub3")),
),
) )
.get_matches_from_safe(vec!["", "sub1", "arg", "sub2"]); .get_matches_from_safe(vec!["", "sub1", "arg", "sub2"]);
assert!(res.is_ok(), "error: {:?}", res.unwrap_err().kind); assert!(res.is_ok(), "error: {:?}", res.unwrap_err().kind);
let m = res.unwrap(); let m = res.unwrap();
assert_eq!(m.subcommand_matches("sub1").unwrap().value_of("arg2"), Some("sub2")); assert_eq!(
m.subcommand_matches("sub1").unwrap().value_of("arg2"),
Some("sub2")
);
} }
#[test] #[test]
fn propagate_vals_down() { fn propagate_vals_down() {
let m = App::new("myprog") let m = App::new("myprog")
@ -667,5 +669,10 @@ fn issue_1093_allow_ext_sc() {
let app = App::new("clap-test") let app = App::new("clap-test")
.version("v1.4.8") .version("v1.4.8")
.setting(AppSettings::AllowExternalSubcommands); .setting(AppSettings::AllowExternalSubcommands);
assert!(test::compare_output(app, "clap-test --help", ALLOW_EXT_SC, false)); assert!(test::compare_output(
app,
"clap-test --help",
ALLOW_EXT_SC,
false
));
} }

View file

@ -36,14 +36,14 @@ OPTIONS:
#[test] #[test]
fn single_alias_of_option() { fn single_alias_of_option() {
let a = App::new("single_alias") let a = App::new("single_alias")
.arg(Arg::with_name("alias") .arg(
.long("alias") Arg::with_name("alias")
.takes_value(true) .long("alias")
.help("single alias") .takes_value(true)
.alias("new-opt")) .help("single alias")
.get_matches_from_safe(vec![ .alias("new-opt"),
"", "--new-opt", "cool" )
]); .get_matches_from_safe(vec!["", "--new-opt", "cool"]);
assert!(a.is_ok()); assert!(a.is_ok());
let a = a.unwrap(); let a = a.unwrap();
assert!(a.is_present("alias")); assert!(a.is_present("alias"));
@ -52,37 +52,30 @@ fn single_alias_of_option() {
#[test] #[test]
fn multiple_aliases_of_option() { fn multiple_aliases_of_option() {
let a = App::new("multiple_aliases") let a = App::new("multiple_aliases").arg(
.arg(Arg::with_name("aliases") Arg::with_name("aliases")
.long("aliases") .long("aliases")
.takes_value(true) .takes_value(true)
.help("multiple aliases") .help("multiple aliases")
.aliases(&vec![ .aliases(&vec!["alias1", "alias2", "alias3"]),
"alias1", );
"alias2", let long = a.clone()
"alias3" .get_matches_from_safe(vec!["", "--aliases", "value"]);
]));
let long = a.clone().get_matches_from_safe(vec![
"", "--aliases", "value"
]);
assert!(long.is_ok()); assert!(long.is_ok());
let long = long.unwrap(); let long = long.unwrap();
let als1 = a.clone().get_matches_from_safe(vec![ let als1 = a.clone()
"", "--alias1", "value" .get_matches_from_safe(vec!["", "--alias1", "value"]);
]);
assert!(als1.is_ok()); assert!(als1.is_ok());
let als1 = als1.unwrap(); let als1 = als1.unwrap();
let als2 = a.clone().get_matches_from_safe(vec![ let als2 = a.clone()
"", "--alias2", "value" .get_matches_from_safe(vec!["", "--alias2", "value"]);
]);
assert!(als2.is_ok()); assert!(als2.is_ok());
let als2 = als2.unwrap(); let als2 = als2.unwrap();
let als3 = a.clone().get_matches_from_safe(vec![ let als3 = a.clone()
"", "--alias3", "value" .get_matches_from_safe(vec!["", "--alias3", "value"]);
]);
assert!(als3.is_ok()); assert!(als3.is_ok());
let als3 = als3.unwrap(); let als3 = als3.unwrap();
@ -99,10 +92,8 @@ fn multiple_aliases_of_option() {
#[test] #[test]
fn single_alias_of_flag() { fn single_alias_of_flag() {
let a = App::new("test") let a = App::new("test")
.arg(Arg::with_name("flag") .arg(Arg::with_name("flag").long("flag").alias("alias"))
.long("flag") .get_matches_from_safe(vec!["", "--alias"]);
.alias("alias"))
.get_matches_from_safe(vec!["", "--alias"]);
assert!(a.is_ok()); assert!(a.is_ok());
let a = a.unwrap(); let a = a.unwrap();
assert!(a.is_present("flag")); assert!(a.is_present("flag"));
@ -110,12 +101,13 @@ fn single_alias_of_flag() {
#[test] #[test]
fn multiple_aliases_of_flag() { fn multiple_aliases_of_flag() {
let a = App::new("test") let a = App::new("test").arg(Arg::with_name("flag").long("flag").aliases(&[
.arg(Arg::with_name("flag") "invisible",
.long("flag") "set",
.aliases(&["invisible", "of",
"set", "of", "cool",
"cool", "aliases"])); "aliases",
]));
let flag = a.clone().get_matches_from_safe(vec!["", "--flag"]); let flag = a.clone().get_matches_from_safe(vec!["", "--flag"]);
assert!(flag.is_ok()); assert!(flag.is_ok());
@ -142,19 +134,22 @@ fn multiple_aliases_of_flag() {
#[test] #[test]
fn alias_on_a_subcommand_option() { fn alias_on_a_subcommand_option() {
let m = App::new("test") let m = App::new("test")
.subcommand(SubCommand::with_name("some") .subcommand(
.arg(Arg::with_name("test") SubCommand::with_name("some").arg(
.short("t") Arg::with_name("test")
.long("test") .short("t")
.takes_value(true) .long("test")
.alias("opt") .takes_value(true)
.help("testing testing"))) .alias("opt")
.arg(Arg::with_name("other") .help("testing testing"),
.long("other") ),
.aliases(&vec!["o1", "o2", "o3"])) )
.get_matches_from(vec![ .arg(
"test", "some", "--opt", "awesome" Arg::with_name("other")
]); .long("other")
.aliases(&vec!["o1", "o2", "o3"]),
)
.get_matches_from(vec!["test", "some", "--opt", "awesome"]);
assert!(m.subcommand_matches("some").is_some()); assert!(m.subcommand_matches("some").is_some());
let sub_m = m.subcommand_matches("some").unwrap(); let sub_m = m.subcommand_matches("some").unwrap();
@ -164,37 +159,52 @@ fn alias_on_a_subcommand_option() {
#[test] #[test]
fn invisible_arg_aliases_help_output() { fn invisible_arg_aliases_help_output() {
let app = App::new("ct") let app = App::new("ct").author("Salim Afiune").subcommand(
.author("Salim Afiune") SubCommand::with_name("test")
.subcommand(SubCommand::with_name("test")
.about("Some help") .about("Some help")
.version("1.2") .version("1.2")
.arg(Arg::with_name("opt") .arg(
.long("opt") Arg::with_name("opt")
.short("o") .long("opt")
.takes_value(true) .short("o")
.aliases(&["invisible", "als1", "more"])) .takes_value(true)
.arg(Arg::from_usage("-f, --flag") .aliases(&["invisible", "als1", "more"]),
.aliases(&["invisible", "flg1", "anyway"]))); )
assert!(test::compare_output(app, "ct test --help", SC_INVISIBLE_ALIAS_HELP, false)); .arg(Arg::from_usage("-f, --flag").aliases(&["invisible", "flg1", "anyway"])),
);
assert!(test::compare_output(
app,
"ct test --help",
SC_INVISIBLE_ALIAS_HELP,
false
));
} }
#[test] #[test]
fn visible_arg_aliases_help_output() { fn visible_arg_aliases_help_output() {
let app = App::new("ct") let app = App::new("ct").author("Salim Afiune").subcommand(
.author("Salim Afiune") SubCommand::with_name("test")
.subcommand(SubCommand::with_name("test")
.about("Some help") .about("Some help")
.version("1.2") .version("1.2")
.arg(Arg::with_name("opt") .arg(
.long("opt") Arg::with_name("opt")
.short("o") .long("opt")
.takes_value(true) .short("o")
.alias("invisible") .takes_value(true)
.visible_alias("visible")) .alias("invisible")
.arg(Arg::with_name("flg") .visible_alias("visible"),
.long("flag") )
.short("f") .arg(
.visible_aliases(&["v_flg", "flag2", "flg3"]))); Arg::with_name("flg")
assert!(test::compare_output(app, "ct test --help", SC_VISIBLE_ALIAS_HELP, false)); .long("flag")
.short("f")
.visible_aliases(&["v_flg", "flag2", "flg3"]),
),
);
assert!(test::compare_output(
app,
"ct test --help",
SC_VISIBLE_ALIAS_HELP,
false
));
} }

View file

@ -7,8 +7,14 @@ include!("../clap-test.rs");
#[test] #[test]
fn borrowed_args() { fn borrowed_args() {
let arg = Arg::with_name("some").short("s").long("some").help("other help"); let arg = Arg::with_name("some")
let arg2 = Arg::with_name("some2").short("S").long("some-thing").help("other help"); .short("s")
.long("some")
.help("other help");
let arg2 = Arg::with_name("some2")
.short("S")
.long("some-thing")
.help("other help");
let result = App::new("sub_command_negate") let result = App::new("sub_command_negate")
.arg(Arg::with_name("test").index(1)) .arg(Arg::with_name("test").index(1))
.arg(&arg) .arg(&arg)

View file

@ -1,7 +1,7 @@
extern crate regex;
extern crate clap; extern crate clap;
extern crate regex;
use clap::{App, Arg, SubCommand, Shell}; use clap::{App, Arg, Shell, SubCommand};
use regex::Regex; use regex::Regex;
static BASH: &'static str = r#"_myapp() { static BASH: &'static str = r#"_myapp() {
@ -63,7 +63,7 @@ static BASH: &'static str = r#"_myapp() {
return 0 return 0
;; ;;
myapp__test) myapp__test)
opts=" -h -V --help --version --case " opts=" -h -V --case --help --version "
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0 return 0
@ -189,7 +189,8 @@ complete -c myapp -n "__fish_using_command myapp help" -s h -l help -d 'Prints h
complete -c myapp -n "__fish_using_command myapp help" -s V -l version -d 'Prints version information' complete -c myapp -n "__fish_using_command myapp help" -s V -l version -d 'Prints version information'
"#; "#;
#[cfg(not(target_os="windows"))] #[cfg_attr(not(target_os = "windows"), allow(dead_code))]
#[cfg(not(target_os = "windows"))]
static POWERSHELL: &'static str = r#" static POWERSHELL: &'static str = r#"
@('myapp', './myapp') | %{ @('myapp', './myapp') | %{
Register-ArgumentCompleter -Native -CommandName $_ -ScriptBlock { Register-ArgumentCompleter -Native -CommandName $_ -ScriptBlock {
@ -240,7 +241,8 @@ static POWERSHELL: &'static str = r#"
} }
"#; "#;
#[cfg(target_os="windows")] #[cfg_attr(target_os = "windows", allow(dead_code))]
#[cfg(target_os = "windows")]
static POWERSHELL: &'static str = r#" static POWERSHELL: &'static str = r#"
@('myapp', './myapp', 'myapp.exe', '.\myapp', '.\myapp.exe', './myapp.exe') | %{ @('myapp', './myapp', 'myapp.exe', '.\myapp', '.\myapp.exe', './myapp.exe') | %{
Register-ArgumentCompleter -Native -CommandName $_ -ScriptBlock { Register-ArgumentCompleter -Native -CommandName $_ -ScriptBlock {
@ -280,7 +282,8 @@ static POWERSHELL: &'static str = r#"
} }
"#; "#;
#[cfg(not(target_os="windows"))] #[cfg_attr(not(target_os = "windows"), allow(dead_code))]
#[cfg(not(target_os = "windows"))]
static POWERSHELL_SPECIAL_CMDS: &'static str = r#" static POWERSHELL_SPECIAL_CMDS: &'static str = r#"
@('my_app', './my_app') | %{ @('my_app', './my_app') | %{
Register-ArgumentCompleter -Native -CommandName $_ -ScriptBlock { Register-ArgumentCompleter -Native -CommandName $_ -ScriptBlock {
@ -340,7 +343,8 @@ static POWERSHELL_SPECIAL_CMDS: &'static str = r#"
} }
"#; "#;
#[cfg(target_os="windows")] #[cfg_attr(target_os = "windows", allow(dead_code))]
#[cfg(target_os = "windows")]
static POWERSHELL_SPECIAL_CMDS: &'static str = r#" static POWERSHELL_SPECIAL_CMDS: &'static str = r#"
@('my_app', './my_app', 'my_app.exe', '.\my_app', '.\my_app.exe', './my_app.exe') | %{ @('my_app', './my_app', 'my_app.exe', '.\my_app', '.\my_app.exe', './my_app.exe') | %{
Register-ArgumentCompleter -Native -CommandName $_ -ScriptBlock { Register-ArgumentCompleter -Native -CommandName $_ -ScriptBlock {
@ -609,7 +613,7 @@ static BASH_SPECIAL_CMDS: &'static str = r#"_my_app() {
return 0 return 0
;; ;;
my_app__some_cmd) my_app__some_cmd)
opts=" -h -V --help --version --config " opts=" -h -V --config --help --version "
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0 return 0
@ -628,7 +632,7 @@ static BASH_SPECIAL_CMDS: &'static str = r#"_my_app() {
return 0 return 0
;; ;;
my_app__test) my_app__test)
opts=" -h -V --help --version --case " opts=" -h -V --case --help --version "
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0 return 0
@ -738,45 +742,63 @@ fn build_app_with_name(s: &'static str) -> App<'static, 'static> {
App::new(s) App::new(s)
.about("Tests completions") .about("Tests completions")
.arg(Arg::with_name("file").help("some input file")) .arg(Arg::with_name("file").help("some input file"))
.subcommand(SubCommand::with_name("test") .subcommand(
.about("tests things") SubCommand::with_name("test").about("tests things").arg(
.arg(Arg::with_name("case") Arg::with_name("case")
.long("case") .long("case")
.takes_value(true) .takes_value(true)
.help("the case to test"))) .help("the case to test"),
),
)
} }
fn build_app_special_commands() -> App<'static, 'static> { fn build_app_special_commands() -> App<'static, 'static> {
build_app_with_name("my_app") build_app_with_name("my_app")
.subcommand(SubCommand::with_name("some_cmd") .subcommand(
.about("tests other things") SubCommand::with_name("some_cmd")
.arg(Arg::with_name("config") .about("tests other things")
.long("--config") .arg(
.takes_value(true) Arg::with_name("config")
.help("the other case to test"))) .long("--config")
.takes_value(true)
.help("the other case to test"),
),
)
.subcommand(SubCommand::with_name("some-cmd-with-hypens")) .subcommand(SubCommand::with_name("some-cmd-with-hypens"))
} }
fn build_app_special_help() -> App<'static, 'static> { fn build_app_special_help() -> App<'static, 'static> {
App::new("my_app") App::new("my_app")
.arg(Arg::with_name("single-quotes") .arg(
.long("single-quotes") Arg::with_name("single-quotes")
.help("Can be 'always', 'auto', or 'never'")) .long("single-quotes")
.arg(Arg::with_name("double-quotes") .help("Can be 'always', 'auto', or 'never'"),
.long("double-quotes") )
.help("Can be \"always\", \"auto\", or \"never\"")) .arg(
.arg(Arg::with_name("backticks") Arg::with_name("double-quotes")
.long("backticks") .long("double-quotes")
.help("For more information see `echo test`")) .help("Can be \"always\", \"auto\", or \"never\""),
.arg(Arg::with_name("backslash") )
.long("backslash") .arg(
.help("Avoid '\\n'")) Arg::with_name("backticks")
.arg(Arg::with_name("brackets") .long("backticks")
.long("brackets") .help("For more information see `echo test`"),
.help("List packages [filter]")) )
.arg(Arg::with_name("expansions") .arg(
.long("expansions") Arg::with_name("backslash")
.help("Execute the shell command with $SHELL")) .long("backslash")
.help("Avoid '\\n'"),
)
.arg(
Arg::with_name("brackets")
.long("brackets")
.help("List packages [filter]"),
)
.arg(
Arg::with_name("expansions")
.long("expansions")
.help("Execute the shell command with $SHELL"),
)
} }
#[test] #[test]

View file

@ -3,7 +3,7 @@ extern crate regex;
include!("../clap-test.rs"); include!("../clap-test.rs");
use clap::{App, Arg, ErrorKind, ArgGroup}; use clap::{App, Arg, ArgGroup, ErrorKind};
static CONFLICT_ERR: &'static str = "error: The argument '-F' cannot be used with '--flag' static CONFLICT_ERR: &'static str = "error: The argument '-F' cannot be used with '--flag'
@ -22,8 +22,7 @@ For more information try --help";
#[test] #[test]
fn flag_conflict() { fn flag_conflict() {
let result = App::new("flag_conflict") let result = App::new("flag_conflict")
.arg(Arg::from_usage("-f, --flag 'some flag'") .arg(Arg::from_usage("-f, --flag 'some flag'").conflicts_with("other"))
.conflicts_with("other"))
.arg(Arg::from_usage("-o, --other 'some flag'")) .arg(Arg::from_usage("-o, --other 'some flag'"))
.get_matches_from_safe(vec!["myprog", "-f", "-o"]); .get_matches_from_safe(vec!["myprog", "-f", "-o"]);
assert!(result.is_err()); assert!(result.is_err());
@ -34,8 +33,7 @@ fn flag_conflict() {
#[test] #[test]
fn flag_conflict_2() { fn flag_conflict_2() {
let result = App::new("flag_conflict") let result = App::new("flag_conflict")
.arg(Arg::from_usage("-f, --flag 'some flag'") .arg(Arg::from_usage("-f, --flag 'some flag'").conflicts_with("other"))
.conflicts_with("other"))
.arg(Arg::from_usage("-o, --other 'some flag'")) .arg(Arg::from_usage("-o, --other 'some flag'"))
.get_matches_from_safe(vec!["myprog", "-o", "-f"]); .get_matches_from_safe(vec!["myprog", "-o", "-f"]);
assert!(result.is_err()); assert!(result.is_err());
@ -46,12 +44,13 @@ fn flag_conflict_2() {
#[test] #[test]
fn group_conflict() { fn group_conflict() {
let result = App::new("group_conflict") let result = App::new("group_conflict")
.arg(Arg::from_usage("-f, --flag 'some flag'") .arg(Arg::from_usage("-f, --flag 'some flag'").conflicts_with("gr"))
.conflicts_with("gr")) .group(
.group(ArgGroup::with_name("gr") ArgGroup::with_name("gr")
.required(true) .required(true)
.arg("some") .arg("some")
.arg("other")) .arg("other"),
)
.arg(Arg::from_usage("--some 'some arg'")) .arg(Arg::from_usage("--some 'some arg'"))
.arg(Arg::from_usage("--other 'other arg'")) .arg(Arg::from_usage("--other 'other arg'"))
.get_matches_from_safe(vec!["myprog", "--other", "-f"]); .get_matches_from_safe(vec!["myprog", "--other", "-f"]);
@ -63,12 +62,13 @@ fn group_conflict() {
#[test] #[test]
fn group_conflict_2() { fn group_conflict_2() {
let result = App::new("group_conflict") let result = App::new("group_conflict")
.arg(Arg::from_usage("-f, --flag 'some flag'") .arg(Arg::from_usage("-f, --flag 'some flag'").conflicts_with("gr"))
.conflicts_with("gr")) .group(
.group(ArgGroup::with_name("gr") ArgGroup::with_name("gr")
.required(true) .required(true)
.arg("some") .arg("some")
.arg("other")) .arg("other"),
)
.arg(Arg::from_usage("--some 'some arg'")) .arg(Arg::from_usage("--some 'some arg'"))
.arg(Arg::from_usage("--other 'other arg'")) .arg(Arg::from_usage("--other 'other arg'"))
.get_matches_from_safe(vec!["myprog", "-f", "--some"]); .get_matches_from_safe(vec!["myprog", "-f", "--some"]);
@ -79,21 +79,29 @@ fn group_conflict_2() {
#[test] #[test]
fn conflict_output() { fn conflict_output() {
test::compare_output(test::complex_app(), "clap-test val1 --flag --long-option-2 val2 -F", CONFLICT_ERR, true); test::compare_output(
test::complex_app(),
"clap-test val1 --flag --long-option-2 val2 -F",
CONFLICT_ERR,
true,
);
} }
#[test] #[test]
fn conflict_output_rev() { fn conflict_output_rev() {
test::compare_output(test::complex_app(), "clap-test val1 -F --long-option-2 val2 --flag", CONFLICT_ERR_REV, true); test::compare_output(
test::complex_app(),
"clap-test val1 -F --long-option-2 val2 --flag",
CONFLICT_ERR_REV,
true,
);
} }
#[test] #[test]
fn conflict_with_unused_default_value() { fn conflict_with_unused_default_value() {
let result = App::new("conflict") let result = App::new("conflict")
.arg(Arg::from_usage("-o, --opt=[opt] 'some opt'") .arg(Arg::from_usage("-o, --opt=[opt] 'some opt'").default_value("default"))
.default_value("default")) .arg(Arg::from_usage("-f, --flag 'some flag'").conflicts_with("opt"))
.arg(Arg::from_usage("-f, --flag 'some flag'")
.conflicts_with("opt"))
.get_matches_from_safe(vec!["myprog", "-f"]); .get_matches_from_safe(vec!["myprog", "-f"]);
assert!(result.is_ok()); assert!(result.is_ok());
let m = result.unwrap(); let m = result.unwrap();

View file

@ -8,9 +8,7 @@ use clap::{App, Arg, ErrorKind};
#[test] #[test]
fn opts() { fn opts() {
let r = App::new("df") let r = App::new("df")
.arg( .arg(Arg::from_usage("-o [opt] 'some opt'").default_value("default"))
Arg::from_usage("-o [opt] 'some opt'").default_value("default"),
)
.get_matches_from_safe(vec![""]); .get_matches_from_safe(vec![""]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -21,9 +19,7 @@ fn opts() {
#[test] #[test]
fn opt_user_override() { fn opt_user_override() {
let r = App::new("df") let r = App::new("df")
.arg( .arg(Arg::from_usage("--opt [FILE] 'some arg'").default_value("default"))
Arg::from_usage("--opt [FILE] 'some arg'").default_value("default"),
)
.get_matches_from_safe(vec!["", "--opt", "value"]); .get_matches_from_safe(vec!["", "--opt", "value"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -61,9 +57,7 @@ fn osstr_opts() {
let expected = OsStr::new("default"); let expected = OsStr::new("default");
let r = App::new("df") let r = App::new("df")
.arg( .arg(Arg::from_usage("-o [opt] 'some opt'").default_value_os(expected))
Arg::from_usage("-o [opt] 'some opt'").default_value_os(expected),
)
.get_matches_from_safe(vec![""]); .get_matches_from_safe(vec![""]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -77,9 +71,7 @@ fn osstr_opt_user_override() {
let default = OsStr::new("default"); let default = OsStr::new("default");
let r = App::new("df") let r = App::new("df")
.arg( .arg(Arg::from_usage("--opt [FILE] 'some arg'").default_value_os(default))
Arg::from_usage("--opt [FILE] 'some arg'").default_value_os(default),
)
.get_matches_from_safe(vec!["", "--opt", "value"]); .get_matches_from_safe(vec!["", "--opt", "value"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -93,9 +85,7 @@ fn osstr_positionals() {
let expected = OsStr::new("default"); let expected = OsStr::new("default");
let r = App::new("df") let r = App::new("df")
.arg( .arg(Arg::from_usage("[arg] 'some opt'").default_value_os(expected))
Arg::from_usage("[arg] 'some opt'").default_value_os(expected),
)
.get_matches_from_safe(vec![""]); .get_matches_from_safe(vec![""]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -109,9 +99,7 @@ fn osstr_positional_user_override() {
let default = OsStr::new("default"); let default = OsStr::new("default");
let r = App::new("df") let r = App::new("df")
.arg( .arg(Arg::from_usage("[arg] 'some arg'").default_value_os(default))
Arg::from_usage("[arg] 'some arg'").default_value_os(default),
)
.get_matches_from_safe(vec!["", "value"]); .get_matches_from_safe(vec!["", "value"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -125,11 +113,7 @@ fn osstr_positional_user_override() {
fn default_if_arg_present_no_default() { fn default_if_arg_present_no_default() {
let r = App::new("df") let r = App::new("df")
.arg(Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg(Arg::from_usage("[arg] 'some arg'").default_value_if( .arg(Arg::from_usage("[arg] 'some arg'").default_value_if("opt", None, "default"))
"opt",
None,
"default",
))
.get_matches_from_safe(vec!["", "--opt", "some"]); .get_matches_from_safe(vec!["", "--opt", "some"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -141,11 +125,7 @@ fn default_if_arg_present_no_default() {
fn default_if_arg_present_no_default_user_override() { fn default_if_arg_present_no_default_user_override() {
let r = App::new("df") let r = App::new("df")
.arg(Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg(Arg::from_usage("[arg] 'some arg'").default_value_if( .arg(Arg::from_usage("[arg] 'some arg'").default_value_if("opt", None, "default"))
"opt",
None,
"default",
))
.get_matches_from_safe(vec!["", "--opt", "some", "other"]); .get_matches_from_safe(vec!["", "--opt", "some", "other"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -223,11 +203,7 @@ fn default_if_arg_present_no_arg_with_default_user_override() {
fn default_if_arg_present_with_value_no_default() { fn default_if_arg_present_with_value_no_default() {
let r = App::new("df") let r = App::new("df")
.arg(Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg(Arg::from_usage("[arg] 'some arg'").default_value_if( .arg(Arg::from_usage("[arg] 'some arg'").default_value_if("opt", Some("value"), "default"))
"opt",
Some("value"),
"default",
))
.get_matches_from_safe(vec!["", "--opt", "value"]); .get_matches_from_safe(vec!["", "--opt", "value"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -239,11 +215,7 @@ fn default_if_arg_present_with_value_no_default() {
fn default_if_arg_present_with_value_no_default_fail() { fn default_if_arg_present_with_value_no_default_fail() {
let r = App::new("df") let r = App::new("df")
.arg(Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg(Arg::from_usage("[arg] 'some arg'").default_value_if( .arg(Arg::from_usage("[arg] 'some arg'").default_value_if("opt", Some("value"), "default"))
"opt",
Some("value"),
"default",
))
.get_matches_from_safe(vec!["", "--opt", "other"]); .get_matches_from_safe(vec!["", "--opt", "other"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -255,11 +227,7 @@ fn default_if_arg_present_with_value_no_default_fail() {
fn default_if_arg_present_with_value_no_default_user_override() { fn default_if_arg_present_with_value_no_default_user_override() {
let r = App::new("df") let r = App::new("df")
.arg(Arg::from_usage("--opt [FILE] 'some arg'")) .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
.arg(Arg::from_usage("[arg] 'some arg'").default_value_if( .arg(Arg::from_usage("[arg] 'some arg'").default_value_if("opt", Some("some"), "default"))
"opt",
Some("some"),
"default",
))
.get_matches_from_safe(vec!["", "--opt", "some", "other"]); .get_matches_from_safe(vec!["", "--opt", "some", "other"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();

View file

@ -5,13 +5,8 @@ use clap::{App, Arg};
#[test] #[test]
fn opt_default_no_delim() { fn opt_default_no_delim() {
let m = App::new("no_delim") let m = App::new("no_delim")
.arg(Arg::with_name("option") .arg(Arg::with_name("option").long("option").takes_value(true))
.long("option") .get_matches_from_safe(vec!["", "--option", "val1,val2,val3"]);
.takes_value(true))
.get_matches_from_safe(vec![
"",
"--option", "val1,val2,val3",
]);
assert!(m.is_ok()); assert!(m.is_ok());
let m = m.unwrap(); let m = m.unwrap();
@ -24,13 +19,8 @@ fn opt_default_no_delim() {
#[test] #[test]
fn opt_eq_no_delim() { fn opt_eq_no_delim() {
let m = App::new("no_delim") let m = App::new("no_delim")
.arg(Arg::with_name("option") .arg(Arg::with_name("option").long("option").takes_value(true))
.long("option") .get_matches_from_safe(vec!["", "--option=val1,val2,val3"]);
.takes_value(true))
.get_matches_from_safe(vec![
"",
"--option=val1,val2,val3",
]);
assert!(m.is_ok()); assert!(m.is_ok());
let m = m.unwrap(); let m = m.unwrap();
@ -43,13 +33,8 @@ fn opt_eq_no_delim() {
#[test] #[test]
fn opt_s_eq_no_delim() { fn opt_s_eq_no_delim() {
let m = App::new("no_delim") let m = App::new("no_delim")
.arg(Arg::with_name("option") .arg(Arg::with_name("option").short("o").takes_value(true))
.short("o") .get_matches_from_safe(vec!["", "-o=val1,val2,val3"]);
.takes_value(true))
.get_matches_from_safe(vec![
"",
"-o=val1,val2,val3",
]);
assert!(m.is_ok(), "{:?}", m.unwrap_err()); assert!(m.is_ok(), "{:?}", m.unwrap_err());
let m = m.unwrap(); let m = m.unwrap();
@ -62,13 +47,8 @@ fn opt_s_eq_no_delim() {
#[test] #[test]
fn opt_s_default_no_delim() { fn opt_s_default_no_delim() {
let m = App::new("no_delim") let m = App::new("no_delim")
.arg(Arg::with_name("option") .arg(Arg::with_name("option").short("o").takes_value(true))
.short("o") .get_matches_from_safe(vec!["", "-o", "val1,val2,val3"]);
.takes_value(true))
.get_matches_from_safe(vec![
"",
"-o", "val1,val2,val3",
]);
assert!(m.is_ok(), "{:?}", m.unwrap_err()); assert!(m.is_ok(), "{:?}", m.unwrap_err());
let m = m.unwrap(); let m = m.unwrap();
@ -81,13 +61,8 @@ fn opt_s_default_no_delim() {
#[test] #[test]
fn opt_s_no_space_no_delim() { fn opt_s_no_space_no_delim() {
let m = App::new("no_delim") let m = App::new("no_delim")
.arg(Arg::with_name("option") .arg(Arg::with_name("option").short("o").takes_value(true))
.short("o") .get_matches_from_safe(vec!["", "-o", "val1,val2,val3"]);
.takes_value(true))
.get_matches_from_safe(vec![
"",
"-o", "val1,val2,val3",
]);
assert!(m.is_ok()); assert!(m.is_ok());
let m = m.unwrap(); let m = m.unwrap();
@ -100,14 +75,13 @@ fn opt_s_no_space_no_delim() {
#[test] #[test]
fn opt_s_no_space_mult_no_delim() { fn opt_s_no_space_mult_no_delim() {
let m = App::new("no_delim") let m = App::new("no_delim")
.arg(Arg::with_name("option") .arg(
.short("o") Arg::with_name("option")
.multiple(true) .short("o")
.takes_value(true)) .multiple(true)
.get_matches_from_safe(vec![ .takes_value(true),
"", )
"-o", "val1,val2,val3", .get_matches_from_safe(vec!["", "-o", "val1,val2,val3"]);
]);
assert!(m.is_ok()); assert!(m.is_ok());
let m = m.unwrap(); let m = m.unwrap();
@ -120,20 +94,22 @@ fn opt_s_no_space_mult_no_delim() {
#[test] #[test]
fn opt_eq_mult_def_delim() { fn opt_eq_mult_def_delim() {
let m = App::new("no_delim") let m = App::new("no_delim")
.arg(Arg::with_name("option") .arg(
.long("opt") Arg::with_name("option")
.multiple(true) .long("opt")
.use_delimiter(true) .multiple(true)
.takes_value(true)) .use_delimiter(true)
.get_matches_from_safe(vec![ .takes_value(true),
"", )
"--opt=val1,val2,val3", .get_matches_from_safe(vec!["", "--opt=val1,val2,val3"]);
]);
assert!(m.is_ok()); assert!(m.is_ok());
let m = m.unwrap(); let m = m.unwrap();
assert!(m.is_present("option")); assert!(m.is_present("option"));
assert_eq!(m.occurrences_of("option"), 1); assert_eq!(m.occurrences_of("option"), 1);
assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), &["val1", "val2", "val3"]); assert_eq!(
m.values_of("option").unwrap().collect::<Vec<_>>(),
&["val1", "val2", "val3"]
);
} }

View file

@ -3,7 +3,7 @@ extern crate regex;
use std::str; use std::str;
use clap::{App, Arg, SubCommand, AppSettings}; use clap::{App, AppSettings, Arg, SubCommand};
include!("../clap-test.rs"); include!("../clap-test.rs");
@ -119,16 +119,25 @@ OPTIONS:
#[test] #[test]
fn no_derive_order() { fn no_derive_order() {
let app = App::new("test") let app = App::new("test").version("1.2").args(&[
.version("1.2") Arg::with_name("flag_b").long("flag_b").help("first flag"),
.args(&[ Arg::with_name("option_b")
Arg::with_name("flag_b").long("flag_b").help("first flag"), .long("option_b")
Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"), .takes_value(true)
Arg::with_name("flag_a").long("flag_a").help("second flag"), .help("first option"),
Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"), Arg::with_name("flag_a").long("flag_a").help("second flag"),
]); Arg::with_name("option_a")
.long("option_a")
.takes_value(true)
.help("second option"),
]);
assert!(test::compare_output(app, "test --help", NO_DERIVE_ORDER, false)); assert!(test::compare_output(
app,
"test --help",
NO_DERIVE_ORDER,
false
));
} }
#[test] #[test]
@ -138,12 +147,23 @@ fn derive_order() {
.version("1.2") .version("1.2")
.args(&[ .args(&[
Arg::with_name("flag_b").long("flag_b").help("first flag"), Arg::with_name("flag_b").long("flag_b").help("first flag"),
Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"), Arg::with_name("option_b")
.long("option_b")
.takes_value(true)
.help("first option"),
Arg::with_name("flag_a").long("flag_a").help("second flag"), Arg::with_name("flag_a").long("flag_a").help("second flag"),
Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"), Arg::with_name("option_a")
.long("option_a")
.takes_value(true)
.help("second option"),
]); ]);
assert!(test::compare_output(app, "test --help", DERIVE_ORDER, false)); assert!(test::compare_output(
app,
"test --help",
DERIVE_ORDER,
false
));
} }
#[test] #[test]
@ -153,12 +173,23 @@ fn unified_help() {
.version("1.2") .version("1.2")
.args(&[ .args(&[
Arg::with_name("flag_b").long("flag_b").help("first flag"), Arg::with_name("flag_b").long("flag_b").help("first flag"),
Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"), Arg::with_name("option_b")
.long("option_b")
.takes_value(true)
.help("first option"),
Arg::with_name("flag_a").long("flag_a").help("second flag"), Arg::with_name("flag_a").long("flag_a").help("second flag"),
Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"), Arg::with_name("option_a")
.long("option_a")
.takes_value(true)
.help("second option"),
]); ]);
assert!(test::compare_output(app, "test --help", UNIFIED_HELP, false)); assert!(test::compare_output(
app,
"test --help",
UNIFIED_HELP,
false
));
} }
#[test] #[test]
@ -169,12 +200,23 @@ fn unified_help_and_derive_order() {
.version("1.2") .version("1.2")
.args(&[ .args(&[
Arg::with_name("flag_b").long("flag_b").help("first flag"), Arg::with_name("flag_b").long("flag_b").help("first flag"),
Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"), Arg::with_name("option_b")
.long("option_b")
.takes_value(true)
.help("first option"),
Arg::with_name("flag_a").long("flag_a").help("second flag"), Arg::with_name("flag_a").long("flag_a").help("second flag"),
Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"), Arg::with_name("option_a")
.long("option_a")
.takes_value(true)
.help("second option"),
]); ]);
assert!(test::compare_output(app, "test --help", UNIFIED_HELP_AND_DERIVE, false)); assert!(test::compare_output(
app,
"test --help",
UNIFIED_HELP_AND_DERIVE,
false
));
} }
#[test] #[test]
@ -182,32 +224,54 @@ fn derive_order_subcommand_propagate() {
let app = App::new("test") let app = App::new("test")
.global_setting(AppSettings::DeriveDisplayOrder) .global_setting(AppSettings::DeriveDisplayOrder)
.version("1.2") .version("1.2")
.subcommand(SubCommand::with_name("sub") .subcommand(
.version("1.2") SubCommand::with_name("sub").version("1.2").args(&[
.args(&[
Arg::with_name("flag_b").long("flag_b").help("first flag"), Arg::with_name("flag_b").long("flag_b").help("first flag"),
Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"), Arg::with_name("option_b")
.long("option_b")
.takes_value(true)
.help("first option"),
Arg::with_name("flag_a").long("flag_a").help("second flag"), Arg::with_name("flag_a").long("flag_a").help("second flag"),
Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"), Arg::with_name("option_a")
])); .long("option_a")
.takes_value(true)
.help("second option"),
]),
);
assert!(test::compare_output(app, "test sub --help", DERIVE_ORDER_SC_PROP, false)); assert!(test::compare_output(
app,
"test sub --help",
DERIVE_ORDER_SC_PROP,
false
));
} }
#[test] #[test]
fn unified_help_subcommand_propagate() { fn unified_help_subcommand_propagate() {
let app = App::new("test") let app = App::new("test")
.global_setting(AppSettings::UnifiedHelpMessage) .global_setting(AppSettings::UnifiedHelpMessage)
.subcommand(SubCommand::with_name("sub") .subcommand(
.version("1.2") SubCommand::with_name("sub").version("1.2").args(&[
.args(&[
Arg::with_name("flag_b").long("flag_b").help("first flag"), Arg::with_name("flag_b").long("flag_b").help("first flag"),
Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"), Arg::with_name("option_b")
.long("option_b")
.takes_value(true)
.help("first option"),
Arg::with_name("flag_a").long("flag_a").help("second flag"), Arg::with_name("flag_a").long("flag_a").help("second flag"),
Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"), Arg::with_name("option_a")
])); .long("option_a")
.takes_value(true)
.help("second option"),
]),
);
assert!(test::compare_output(app, "test sub --help", UNIFIED_SC_PROP, false)); assert!(test::compare_output(
app,
"test sub --help",
UNIFIED_SC_PROP,
false
));
} }
#[test] #[test]
@ -215,16 +279,27 @@ fn unified_help_and_derive_order_subcommand_propagate() {
let app = App::new("test") let app = App::new("test")
.global_setting(AppSettings::DeriveDisplayOrder) .global_setting(AppSettings::DeriveDisplayOrder)
.global_setting(AppSettings::UnifiedHelpMessage) .global_setting(AppSettings::UnifiedHelpMessage)
.subcommand(SubCommand::with_name("sub") .subcommand(
.version("1.2") SubCommand::with_name("sub").version("1.2").args(&[
.args(&[
Arg::with_name("flag_b").long("flag_b").help("first flag"), Arg::with_name("flag_b").long("flag_b").help("first flag"),
Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"), Arg::with_name("option_b")
.long("option_b")
.takes_value(true)
.help("first option"),
Arg::with_name("flag_a").long("flag_a").help("second flag"), Arg::with_name("flag_a").long("flag_a").help("second flag"),
Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"), Arg::with_name("option_a")
])); .long("option_a")
.takes_value(true)
.help("second option"),
]),
);
assert!(test::compare_output(app, "test sub --help", UNIFIED_DERIVE_SC_PROP, false)); assert!(test::compare_output(
app,
"test sub --help",
UNIFIED_DERIVE_SC_PROP,
false
));
} }
#[test] #[test]
@ -232,14 +307,28 @@ fn unified_help_and_derive_order_subcommand_propagate_with_explicit_display_orde
let app = App::new("test") let app = App::new("test")
.global_setting(AppSettings::DeriveDisplayOrder) .global_setting(AppSettings::DeriveDisplayOrder)
.global_setting(AppSettings::UnifiedHelpMessage) .global_setting(AppSettings::UnifiedHelpMessage)
.subcommand(SubCommand::with_name("sub") .subcommand(
.version("1.2") SubCommand::with_name("sub").version("1.2").args(&[
.args(&[
Arg::with_name("flag_b").long("flag_b").help("first flag"), Arg::with_name("flag_b").long("flag_b").help("first flag"),
Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"), Arg::with_name("option_b")
Arg::with_name("flag_a").long("flag_a").help("second flag").display_order(0), .long("option_b")
Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"), .takes_value(true)
])); .help("first option"),
Arg::with_name("flag_a")
.long("flag_a")
.help("second flag")
.display_order(0),
Arg::with_name("option_a")
.long("option_a")
.takes_value(true)
.help("second option"),
]),
);
assert!(test::compare_output(app, "test sub --help", UNIFIED_DERIVE_SC_PROP_EXPLICIT_ORDER, false)); assert!(test::compare_output(
app,
"test sub --help",
UNIFIED_DERIVE_SC_PROP_EXPLICIT_ORDER,
false
));
} }

View file

@ -25,9 +25,7 @@ fn env_os() {
env::set_var("CLP_TEST_ENV", "env"); env::set_var("CLP_TEST_ENV", "env");
let r = App::new("df") let r = App::new("df")
.arg( .arg(Arg::from_usage("[arg] 'some opt'").env_os(OsStr::new("CLP_TEST_ENV")))
Arg::from_usage("[arg] 'some opt'").env_os(OsStr::new("CLP_TEST_ENV")),
)
.get_matches_from_safe(vec![""]); .get_matches_from_safe(vec![""]);
assert!(r.is_ok()); assert!(r.is_ok());
@ -78,9 +76,7 @@ fn opt_user_override() {
env::set_var("CLP_TEST_ENV", "env"); env::set_var("CLP_TEST_ENV", "env");
let r = App::new("df") let r = App::new("df")
.arg( .arg(Arg::from_usage("--arg [FILE] 'some arg'").env("CLP_TEST_ENV"))
Arg::from_usage("--arg [FILE] 'some arg'").env("CLP_TEST_ENV"),
)
.get_matches_from_safe(vec!["", "--arg", "opt"]); .get_matches_from_safe(vec!["", "--arg", "opt"]);
assert!(r.is_ok()); assert!(r.is_ok());
@ -204,7 +200,6 @@ fn possible_value() {
assert_eq!(m.value_of("arg").unwrap(), "env"); assert_eq!(m.value_of("arg").unwrap(), "env");
} }
#[test] #[test]
fn not_possible_value() { fn not_possible_value() {
env::set_var("CLP_TEST_ENV", "env"); env::set_var("CLP_TEST_ENV", "env");
@ -228,10 +223,12 @@ fn validator() {
.arg( .arg(
Arg::from_usage("[arg] 'some opt'") Arg::from_usage("[arg] 'some opt'")
.env("CLP_TEST_ENV") .env("CLP_TEST_ENV")
.validator(|s| if s == "env" { .validator(|s| {
Ok(()) if s == "env" {
} else { Ok(())
Err("not equal".to_string()) } else {
Err("not equal".to_string())
}
}), }),
) )
.get_matches_from_safe(vec![""]); .get_matches_from_safe(vec![""]);
@ -251,10 +248,12 @@ fn validator_invalid() {
.arg( .arg(
Arg::from_usage("[arg] 'some opt'") Arg::from_usage("[arg] 'some opt'")
.env("CLP_TEST_ENV") .env("CLP_TEST_ENV")
.validator(|s| if s != "env" { .validator(|s| {
Ok(()) if s != "env" {
} else { Ok(())
Err("is equal".to_string()) } else {
Err("is equal".to_string())
}
}), }),
) )
.get_matches_from_safe(vec![""]); .get_matches_from_safe(vec![""]);

View file

@ -7,8 +7,8 @@ fn flag_using_short() {
let m = App::new("flag") let m = App::new("flag")
.args(&[ .args(&[
Arg::from_usage("-f, --flag 'some flag'"), Arg::from_usage("-f, --flag 'some flag'"),
Arg::from_usage("-c, --color 'some other flag'") Arg::from_usage("-c, --color 'some other flag'"),
]) ])
.get_matches_from(vec!["", "-f", "-c"]); .get_matches_from(vec!["", "-f", "-c"]);
assert!(m.is_present("flag")); assert!(m.is_present("flag"));
assert!(m.is_present("color")); assert!(m.is_present("color"));
@ -17,38 +17,31 @@ fn flag_using_short() {
#[test] #[test]
fn lots_o_flags_sep() { fn lots_o_flags_sep() {
let r = App::new("opts") let r = App::new("opts")
.arg( .arg(Arg::from_usage("-o... 'some flag'"))
Arg::from_usage("-o... 'some flag'"), .get_matches_from_safe(vec![
) "", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
.get_matches_from_safe(vec!["", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", ]);
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
assert!(m.is_present("o")); assert!(m.is_present("o"));
@ -58,16 +51,15 @@ fn lots_o_flags_sep() {
#[test] #[test]
fn lots_o_flags_combined() { fn lots_o_flags_combined() {
let r = App::new("opts") let r = App::new("opts")
.arg( .arg(Arg::from_usage("-o... 'some flag'"))
Arg::from_usage("-o... 'some flag'"), .get_matches_from_safe(vec![
) "",
.get_matches_from_safe(vec!["",
"-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", "-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo",
"-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", "-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo",
"-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", "-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo",
"-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", "-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo",
"-ooooooooooooooooooooooooooooooooooooooooo", "-ooooooooooooooooooooooooooooooooooooooooo",
]); ]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
assert!(m.is_present("o")); assert!(m.is_present("o"));
@ -79,8 +71,8 @@ fn flag_using_long() {
let m = App::new("flag") let m = App::new("flag")
.args(&[ .args(&[
Arg::from_usage("--flag 'some flag'"), Arg::from_usage("--flag 'some flag'"),
Arg::from_usage("--color 'some other flag'") Arg::from_usage("--color 'some other flag'"),
]) ])
.get_matches_from(vec!["", "--flag", "--color"]); .get_matches_from(vec!["", "--flag", "--color"]);
assert!(m.is_present("flag")); assert!(m.is_present("flag"));
assert!(m.is_present("color")); assert!(m.is_present("color"));
@ -91,8 +83,8 @@ fn flag_using_mixed() {
let m = App::new("flag") let m = App::new("flag")
.args(&[ .args(&[
Arg::from_usage("-f, --flag 'some flag'"), Arg::from_usage("-f, --flag 'some flag'"),
Arg::from_usage("-c, --color 'some other flag'") Arg::from_usage("-c, --color 'some other flag'"),
]) ])
.get_matches_from(vec!["", "-f", "--color"]); .get_matches_from(vec!["", "-f", "--color"]);
assert!(m.is_present("flag")); assert!(m.is_present("flag"));
assert!(m.is_present("color")); assert!(m.is_present("color"));
@ -100,8 +92,8 @@ fn flag_using_mixed() {
let m = App::new("flag") let m = App::new("flag")
.args(&[ .args(&[
Arg::from_usage("-f, --flag 'some flag'"), Arg::from_usage("-f, --flag 'some flag'"),
Arg::from_usage("-c, --color 'some other flag'") Arg::from_usage("-c, --color 'some other flag'"),
]) ])
.get_matches_from(vec!["", "--flag", "-c"]); .get_matches_from(vec!["", "--flag", "-c"]);
assert!(m.is_present("flag")); assert!(m.is_present("flag"));
assert!(m.is_present("color")); assert!(m.is_present("color"));
@ -113,8 +105,8 @@ fn multiple_flags_in_single() {
.args(&[ .args(&[
Arg::from_usage("-f, --flag 'some flag'"), Arg::from_usage("-f, --flag 'some flag'"),
Arg::from_usage("-c, --color 'some other flag'"), Arg::from_usage("-c, --color 'some other flag'"),
Arg::from_usage("-d, --debug 'another other flag'") Arg::from_usage("-d, --debug 'another other flag'"),
]) ])
.get_matches_from(vec!["", "-fcd"]); .get_matches_from(vec!["", "-fcd"]);
assert!(m.is_present("flag")); assert!(m.is_present("flag"));
assert!(m.is_present("color")); assert!(m.is_present("color"));
@ -124,24 +116,23 @@ fn multiple_flags_in_single() {
#[test] #[test]
fn short_flag_misspel() { fn short_flag_misspel() {
let a = Arg::from_usage("-f1, --flag 'some flag'"); let a = Arg::from_usage("-f1, --flag 'some flag'");
assert_eq!(a.b.name, "flag"); assert_eq!(a.name, "flag");
assert_eq!(a.s.short.unwrap(), 'f'); assert_eq!(a.short.unwrap(), 'f');
assert_eq!(a.s.long.unwrap(), "flag"); assert_eq!(a.long.unwrap(), "flag");
assert_eq!(a.b.help.unwrap(), "some flag"); assert_eq!(a.help.unwrap(), "some flag");
assert!(!a.is_set(ArgSettings::Multiple)); assert!(!a.is_set(ArgSettings::Multiple));
assert!(a.v.val_names.is_none()); assert!(a.val_names.is_none());
assert!(a.v.num_vals.is_none()); assert!(a.num_vals.is_none());
} }
#[test] #[test]
fn short_flag_name_missing() { fn short_flag_name_missing() {
let a = Arg::from_usage("-f 'some flag'"); let a = Arg::from_usage("-f 'some flag'");
assert_eq!(a.b.name, "f"); assert_eq!(a.name, "f");
assert_eq!(a.s.short.unwrap(), 'f'); assert_eq!(a.short.unwrap(), 'f');
assert!(a.s.long.is_none()); assert!(a.long.is_none());
assert_eq!(a.b.help.unwrap(), "some flag"); assert_eq!(a.help.unwrap(), "some flag");
assert!(!a.is_set(ArgSettings::Multiple)); assert!(!a.is_set(ArgSettings::Multiple));
assert!(a.v.val_names.is_none()); assert!(a.val_names.is_none());
assert!(a.v.num_vals.is_none()); assert!(a.num_vals.is_none());
} }

View file

@ -8,30 +8,29 @@ mod tests {
fn get_app() -> App<'static, 'static> { fn get_app() -> App<'static, 'static> {
App::new("myprog") App::new("myprog")
.arg(Arg::with_name("GLOBAL_ARG") .arg(
.long("global-arg") Arg::with_name("GLOBAL_ARG")
.help( .long("global-arg")
"Specifies something needed by the subcommands", .help("Specifies something needed by the subcommands")
) .global(true)
.global(true) .takes_value(true)
.takes_value(true) .default_value("default_value"),
.default_value("default_value")) )
.arg(Arg::with_name("GLOBAL_FLAG") .arg(
.long("global-flag") Arg::with_name("GLOBAL_FLAG")
.help( .long("global-flag")
"Specifies something needed by the subcommands", .help("Specifies something needed by the subcommands")
) .multiple(true)
.multiple(true) .global(true),
.global(true)) )
.subcommand(SubCommand::with_name("outer") .subcommand(SubCommand::with_name("outer").subcommand(SubCommand::with_name("inner")))
.subcommand(SubCommand::with_name("inner")))
} }
#[test] #[test]
fn issue_1076() { fn issue_1076() {
let mut app = get_app(); let mut app = get_app();
app.get_matches_from_safe_borrow(vec!["myprog"]); let _ = app.get_matches_from_safe_borrow(vec!["myprog"]);
app.get_matches_from_safe_borrow(vec!["myprog"]); let _ = app.get_matches_from_safe_borrow(vec!["myprog"]);
app.get_matches_from_safe_borrow(vec!["myprog"]); let _ = app.get_matches_from_safe_borrow(vec!["myprog"]);
} }
} }

View file

@ -13,14 +13,16 @@ USAGE:
For more information try --help"; For more information try --help";
static REQ_GROUP_CONFLICT_USAGE: &'static str = "error: The argument '<base>' cannot be used with '--delete' static REQ_GROUP_CONFLICT_USAGE: &'static str =
"error: The argument '<base>' cannot be used with '--delete'
USAGE: USAGE:
clap-test <base|--delete> clap-test <base|--delete>
For more information try --help"; For more information try --help";
static REQ_GROUP_CONFLICT_REV: &'static str = "error: The argument '--delete' cannot be used with 'base' static REQ_GROUP_CONFLICT_REV: &'static str =
"error: The argument '--delete' cannot be used with 'base'
USAGE: USAGE:
clap-test <base|--delete> clap-test <base|--delete>
@ -30,11 +32,15 @@ For more information try --help";
#[test] #[test]
fn required_group_missing_arg() { fn required_group_missing_arg() {
let result = App::new("group") let result = App::new("group")
.args_from_usage("-f, --flag 'some flag' .args_from_usage(
-c, --color 'some other flag'") "-f, --flag 'some flag'
.group(ArgGroup::with_name("req") -c, --color 'some other flag'",
.args(&["flag", "color"]) )
.required(true)) .group(
ArgGroup::with_name("req")
.args(&["flag", "color"])
.required(true),
)
.get_matches_from_safe(vec![""]); .get_matches_from_safe(vec![""]);
assert!(result.is_err()); assert!(result.is_err());
let err = result.err().unwrap(); let err = result.err().unwrap();
@ -45,21 +51,26 @@ fn required_group_missing_arg() {
#[should_panic] #[should_panic]
fn non_existing_arg() { fn non_existing_arg() {
let _ = App::new("group") let _ = App::new("group")
.args_from_usage("-f, --flag 'some flag' .args_from_usage(
-c, --color 'some other flag'") "-f, --flag 'some flag'
.group(ArgGroup::with_name("req") -c, --color 'some other flag'",
.args(&["flg", "color"]) )
.required(true)) .group(
ArgGroup::with_name("req")
.args(&["flg", "color"])
.required(true),
)
.get_matches_from_safe(vec![""]); .get_matches_from_safe(vec![""]);
} }
#[test] #[test]
fn group_single_value() { fn group_single_value() {
let res = App::new("group") let res = App::new("group")
.args_from_usage("-f, --flag 'some flag' .args_from_usage(
-c, --color [color] 'some option'") "-f, --flag 'some flag'
.group(ArgGroup::with_name("grp") -c, --color [color] 'some option'",
.args(&["flag", "color"])) )
.group(ArgGroup::with_name("grp").args(&["flag", "color"]))
.get_matches_from_safe(vec!["", "-c", "blue"]); .get_matches_from_safe(vec!["", "-c", "blue"]);
assert!(res.is_ok()); assert!(res.is_ok());
@ -71,10 +82,11 @@ fn group_single_value() {
#[test] #[test]
fn group_single_flag() { fn group_single_flag() {
let res = App::new("group") let res = App::new("group")
.args_from_usage("-f, --flag 'some flag' .args_from_usage(
-c, --color [color] 'some option'") "-f, --flag 'some flag'
.group(ArgGroup::with_name("grp") -c, --color [color] 'some option'",
.args(&["flag", "color"])) )
.group(ArgGroup::with_name("grp").args(&["flag", "color"]))
.get_matches_from_safe(vec!["", "-f"]); .get_matches_from_safe(vec!["", "-f"]);
assert!(res.is_ok()); assert!(res.is_ok());
@ -86,10 +98,11 @@ fn group_single_flag() {
#[test] #[test]
fn group_empty() { fn group_empty() {
let res = App::new("group") let res = App::new("group")
.args_from_usage("-f, --flag 'some flag' .args_from_usage(
-c, --color [color] 'some option'") "-f, --flag 'some flag'
.group(ArgGroup::with_name("grp") -c, --color [color] 'some option'",
.args(&["flag", "color"])) )
.group(ArgGroup::with_name("grp").args(&["flag", "color"]))
.get_matches_from_safe(vec![""]); .get_matches_from_safe(vec![""]);
assert!(res.is_ok()); assert!(res.is_ok());
@ -101,11 +114,15 @@ fn group_empty() {
#[test] #[test]
fn group_reqired_flags_empty() { fn group_reqired_flags_empty() {
let result = App::new("group") let result = App::new("group")
.args_from_usage("-f, --flag 'some flag' .args_from_usage(
-c, --color 'some option'") "-f, --flag 'some flag'
.group(ArgGroup::with_name("grp") -c, --color 'some option'",
.required(true) )
.args(&["flag", "color"])) .group(
ArgGroup::with_name("grp")
.required(true)
.args(&["flag", "color"]),
)
.get_matches_from_safe(vec![""]); .get_matches_from_safe(vec![""]);
assert!(result.is_err()); assert!(result.is_err());
let err = result.err().unwrap(); let err = result.err().unwrap();
@ -115,24 +132,27 @@ fn group_reqired_flags_empty() {
#[test] #[test]
fn group_multi_value_single_arg() { fn group_multi_value_single_arg() {
let res = App::new("group") let res = App::new("group")
.args_from_usage("-f, --flag 'some flag' .args_from_usage(
-c, --color [color]... 'some option'") "-f, --flag 'some flag'
.group(ArgGroup::with_name("grp") -c, --color [color]... 'some option'",
.args(&["flag", "color"])) )
.group(ArgGroup::with_name("grp").args(&["flag", "color"]))
.get_matches_from_safe(vec!["", "-c", "blue", "red", "green"]); .get_matches_from_safe(vec!["", "-c", "blue", "red", "green"]);
assert!(res.is_ok(), "{:?}", res.unwrap_err().kind); assert!(res.is_ok(), "{:?}", res.unwrap_err().kind);
let m = res.unwrap(); let m = res.unwrap();
assert!(m.is_present("grp")); assert!(m.is_present("grp"));
assert_eq!(&*m.values_of("grp").unwrap().collect::<Vec<_>>(), &["blue", "red", "green"]); assert_eq!(
&*m.values_of("grp").unwrap().collect::<Vec<_>>(),
&["blue", "red", "green"]
);
} }
#[test] #[test]
fn empty_group() { fn empty_group() {
let r = App::new("empty_group") let r = App::new("empty_group")
.arg(Arg::from_usage("-f, --flag 'some flag'")) .arg(Arg::from_usage("-f, --flag 'some flag'"))
.group(ArgGroup::with_name("vers") .group(ArgGroup::with_name("vers").required(true))
.required(true))
.get_matches_from_safe(vec!["empty_prog"]); .get_matches_from_safe(vec!["empty_prog"]);
assert!(r.is_err()); assert!(r.is_err());
let err = r.err().unwrap(); let err = r.err().unwrap();
@ -142,36 +162,59 @@ fn empty_group() {
#[test] #[test]
fn req_group_usage_string() { fn req_group_usage_string() {
let app = App::new("req_group") let app = App::new("req_group")
.args_from_usage("[base] 'Base commit' .args_from_usage(
-d, --delete 'Remove the base commit information'") "[base] 'Base commit'
.group(ArgGroup::with_name("base_or_delete") -d, --delete 'Remove the base commit information'",
.args(&["base", "delete"]) )
.required(true)); .group(
ArgGroup::with_name("base_or_delete")
.args(&["base", "delete"])
.required(true),
);
assert!(test::compare_output(app, "clap-test", REQ_GROUP_USAGE, true)); assert!(test::compare_output(
app,
"clap-test",
REQ_GROUP_USAGE,
true
));
} }
#[test] #[test]
fn req_group_with_conflict_usage_string() { fn req_group_with_conflict_usage_string() {
let app = App::new("req_group") let app = App::new("req_group")
.arg(Arg::from_usage("[base] 'Base commit'").conflicts_with("delete")) .arg(Arg::from_usage("[base] 'Base commit'").conflicts_with("delete"))
.arg(Arg::from_usage("-d, --delete 'Remove the base commit information'")) .arg(Arg::from_usage(
.group(ArgGroup::with_name("base_or_delete") "-d, --delete 'Remove the base commit information'",
.args(&["base", "delete"]) ))
.required(true)); .group(
ArgGroup::with_name("base_or_delete")
.args(&["base", "delete"])
.required(true),
);
assert!(test::compare_output2(app, "clap-test --delete base", REQ_GROUP_CONFLICT_REV, REQ_GROUP_CONFLICT_USAGE, true)); assert!(test::compare_output2(
app,
"clap-test --delete base",
REQ_GROUP_CONFLICT_REV,
REQ_GROUP_CONFLICT_USAGE,
true
));
} }
#[test] #[test]
fn required_group_multiple_args() { fn required_group_multiple_args() {
let result = App::new("group") let result = App::new("group")
.args_from_usage("-f, --flag 'some flag' .args_from_usage(
-c, --color 'some other flag'") "-f, --flag 'some flag'
.group(ArgGroup::with_name("req") -c, --color 'some other flag'",
.args(&["flag", "color"]) )
.required(true) .group(
.multiple(true)) ArgGroup::with_name("req")
.args(&["flag", "color"])
.required(true)
.multiple(true),
)
.get_matches_from_safe(vec!["group", "-f", "-c"]); .get_matches_from_safe(vec!["group", "-f", "-c"]);
assert!(result.is_ok()); assert!(result.is_ok());
let m = result.unwrap(); let m = result.unwrap();
@ -182,10 +225,11 @@ fn required_group_multiple_args() {
#[test] #[test]
fn group_multiple_args_error() { fn group_multiple_args_error() {
let result = App::new("group") let result = App::new("group")
.args_from_usage("-f, --flag 'some flag' .args_from_usage(
-c, --color 'some other flag'") "-f, --flag 'some flag'
.group(ArgGroup::with_name("req") -c, --color 'some other flag'",
.args(&["flag", "color"])) )
.group(ArgGroup::with_name("req").args(&["flag", "color"]))
.get_matches_from_safe(vec!["group", "-f", "-c"]); .get_matches_from_safe(vec!["group", "-f", "-c"]);
assert!(result.is_err()); assert!(result.is_err());
let err = result.unwrap_err(); let err = result.unwrap_err();

View file

@ -4,7 +4,7 @@ extern crate regex;
include!("../clap-test.rs"); include!("../clap-test.rs");
use clap::{App, AppSettings, SubCommand, ErrorKind, Arg}; use clap::{App, AppSettings, Arg, ErrorKind, SubCommand};
static REQUIRE_DELIM_HELP: &'static str = "test 1.3 static REQUIRE_DELIM_HELP: &'static str = "test 1.3
Kevin K. Kevin K.
@ -180,7 +180,6 @@ FLAGS:
-h, --help Prints help information -h, --help Prints help information
-V, --version Prints version information"; -V, --version Prints version information";
static MULTI_SC_HELP: &'static str = "ctest-subcmd-multi 0.1 static MULTI_SC_HELP: &'static str = "ctest-subcmd-multi 0.1
Kevin K. <kbknapp@gmail.com> Kevin K. <kbknapp@gmail.com>
tests subcommands tests subcommands
@ -526,8 +525,7 @@ fn setup() -> App<'static, 'static> {
#[test] #[test]
fn help_short() { fn help_short() {
let m = setup() let m = setup().get_matches_from_safe(vec!["myprog", "-h"]);
.get_matches_from_safe(vec!["myprog", "-h"]);
assert!(m.is_err()); assert!(m.is_err());
assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed); assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
@ -535,8 +533,7 @@ fn help_short() {
#[test] #[test]
fn help_long() { fn help_long() {
let m = setup() let m = setup().get_matches_from_safe(vec!["myprog", "--help"]);
.get_matches_from_safe(vec!["myprog", "--help"]);
assert!(m.is_err()); assert!(m.is_err());
assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed); assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
@ -544,8 +541,7 @@ fn help_long() {
#[test] #[test]
fn help_no_subcommand() { fn help_no_subcommand() {
let m = setup() let m = setup().get_matches_from_safe(vec!["myprog", "help"]);
.get_matches_from_safe(vec!["myprog", "help"]);
assert!(m.is_err()); assert!(m.is_err());
assert_eq!(m.unwrap_err().kind, ErrorKind::UnknownArgument); assert_eq!(m.unwrap_err().kind, ErrorKind::UnknownArgument);
@ -554,9 +550,11 @@ fn help_no_subcommand() {
#[test] #[test]
fn help_subcommand() { fn help_subcommand() {
let m = setup() let m = setup()
.subcommand(SubCommand::with_name("test") .subcommand(
.about("tests things") SubCommand::with_name("test")
.arg_from_usage("-v --verbose 'with verbosity'")) .about("tests things")
.arg_from_usage("-v --verbose 'with verbosity'"),
)
.get_matches_from_safe(vec!["myprog", "help"]); .get_matches_from_safe(vec!["myprog", "help"]);
assert!(m.is_err()); assert!(m.is_err());
@ -570,7 +568,12 @@ fn req_last_arg_usage() {
(@arg FIRST: ... * "First") (@arg FIRST: ... * "First")
(@arg SECOND: ... * +last "Second") (@arg SECOND: ... * +last "Second")
); );
assert!(test::compare_output(app, "example --help", LAST_ARG_REQ_MULT, false)); assert!(test::compare_output(
app,
"example --help",
LAST_ARG_REQ_MULT,
false
));
} }
#[test] #[test]
@ -578,38 +581,48 @@ fn args_with_last_usage() {
let app = App::new("flamegraph") let app = App::new("flamegraph")
.version("0.1") .version("0.1")
.setting(AppSettings::TrailingVarArg) .setting(AppSettings::TrailingVarArg)
.arg(Arg::with_name("verbose") .arg(
.help("Prints out more stuff.") Arg::with_name("verbose")
.short("v") .help("Prints out more stuff.")
.long("verbose") .short("v")
.multiple(true) .long("verbose")
.multiple(true),
) )
.arg(Arg::with_name("timeout") .arg(
.help("Timeout in seconds.") Arg::with_name("timeout")
.short("t") .help("Timeout in seconds.")
.long("timeout") .short("t")
.value_name("SECONDS") .long("timeout")
.takes_value(true) .value_name("SECONDS")
.takes_value(true),
) )
.arg(Arg::with_name("frequency") .arg(
.help("The sampling frequency.") Arg::with_name("frequency")
.short("f") .help("The sampling frequency.")
.long("frequency") .short("f")
.value_name("HERTZ") .long("frequency")
.takes_value(true) .value_name("HERTZ")
.takes_value(true),
) )
.arg(Arg::with_name("binary path") .arg(
.help("The path of the binary to be profiled. for a binary.") Arg::with_name("binary path")
.takes_value(true) .help("The path of the binary to be profiled. for a binary.")
.value_name("BINFILE") .takes_value(true)
.value_name("BINFILE"),
) )
.arg(Arg::with_name("pass through args") .arg(
.help("Any arguments you wish to pass to the being profiled.") Arg::with_name("pass through args")
.value_name("ARGS") .help("Any arguments you wish to pass to the being profiled.")
.last(true) .value_name("ARGS")
.multiple(true) .last(true)
.multiple(true),
); );
assert!(test::compare_output(app, "flamegraph --help", LAST_ARG_USAGE, false)); assert!(test::compare_output(
app,
"flamegraph --help",
LAST_ARG_USAGE,
false
));
} }
#[test] #[test]
@ -638,7 +651,12 @@ fn subcommand_help_rev() {
#[test] #[test]
fn complex_help_output() { fn complex_help_output() {
assert!(test::compare_output(test::complex_app(), "clap-test --help", HELP, false)); assert!(test::compare_output(
test::complex_app(),
"clap-test --help",
HELP,
false
));
} }
#[test] #[test]
@ -648,83 +666,123 @@ fn after_and_before_help_output() {
.about("tests clap library") .about("tests clap library")
.before_help("some text that comes before the help") .before_help("some text that comes before the help")
.after_help("some text that comes after the help"); .after_help("some text that comes after the help");
assert!(test::compare_output(app, "clap-test --help", AFTER_HELP, false)); assert!(test::compare_output(
app,
"clap-test --help",
AFTER_HELP,
false
));
} }
#[test] #[test]
fn multi_level_sc_help() { fn multi_level_sc_help() {
let app = App::new("ctest") let app = App::new("ctest").subcommand(
.subcommand(SubCommand::with_name("subcmd").subcommand(SubCommand::with_name("multi") SubCommand::with_name("subcmd").subcommand(
.about("tests subcommands") SubCommand::with_name("multi")
.author("Kevin K. <kbknapp@gmail.com>") .about("tests subcommands")
.version("0.1") .author("Kevin K. <kbknapp@gmail.com>")
.args_from_usage(" .version("0.1")
-f, --flag 'tests flags' .args_from_usage(
-o, --option [scoption]... 'tests options' "-f, --flag 'tests flags'
"))); -o, --option [scoption]... 'tests options'",
assert!(test::compare_output(app, "ctest help subcmd multi", MULTI_SC_HELP, false)); ),
),
);
assert!(test::compare_output(
app,
"ctest help subcmd multi",
MULTI_SC_HELP,
false
));
} }
#[test] #[test]
fn no_wrap_help() { fn no_wrap_help() {
let app = App::new("ctest") let app = App::new("ctest").set_term_width(0).help(MULTI_SC_HELP);
.set_term_width(0) assert!(test::compare_output(
.help(MULTI_SC_HELP); app,
assert!(test::compare_output(app, "ctest --help", MULTI_SC_HELP, false)); "ctest --help",
MULTI_SC_HELP,
false
));
} }
#[test] #[test]
fn no_wrap_default_help() { fn no_wrap_default_help() {
let app = App::new("ctest").version("1.0").set_term_width(0); let app = App::new("ctest").version("1.0").set_term_width(0);
assert!(test::compare_output(app, "ctest --help", DEFAULT_HELP, false)); assert!(test::compare_output(
app,
"ctest --help",
DEFAULT_HELP,
false
));
} }
#[test] #[test]
fn complex_subcommand_help_output() { fn complex_subcommand_help_output() {
let a = test::complex_app(); let a = test::complex_app();
assert!(test::compare_output(a, "clap-test subcmd --help", SC_HELP, false)); assert!(test::compare_output(
a,
"clap-test subcmd --help",
SC_HELP,
false
));
} }
#[test] #[test]
fn issue_626_unicode_cutoff() { fn issue_626_unicode_cutoff() {
let app = App::new("ctest") let app = App::new("ctest").version("0.1").set_term_width(70).arg(
.version("0.1") Arg::with_name("cafe")
.set_term_width(70)
.arg(Arg::with_name("cafe")
.short("c") .short("c")
.long("cafe") .long("cafe")
.value_name("FILE") .value_name("FILE")
.help("A coffeehouse, coffee shop, or café is an establishment \ .help(
which primarily serves hot coffee, related coffee beverages \ "A coffeehouse, coffee shop, or café is an establishment \
(e.g., café latte, cappuccino, espresso), tea, and other hot \ which primarily serves hot coffee, related coffee beverages \
beverages. Some coffeehouses also serve cold beverages such as \ (e.g., café latte, cappuccino, espresso), tea, and other hot \
iced coffee and iced tea. Many cafés also serve some type of \ beverages. Some coffeehouses also serve cold beverages such as \
food, such as light snacks, muffins, or pastries.") iced coffee and iced tea. Many cafés also serve some type of \
.takes_value(true)); food, such as light snacks, muffins, or pastries.",
assert!(test::compare_output(app, "ctest --help", ISSUE_626_CUTOFF, false)); )
.takes_value(true),
);
assert!(test::compare_output(
app,
"ctest --help",
ISSUE_626_CUTOFF,
false
));
} }
#[test] #[test]
fn hide_possible_vals() { fn hide_possible_vals() {
let app = App::new("ctest") let app = App::new("ctest")
.version("0.1") .version("0.1")
.arg(Arg::with_name("pos") .arg(
.short("p") Arg::with_name("pos")
.long("pos") .short("p")
.value_name("VAL") .long("pos")
.possible_values(&["fast", "slow"]) .value_name("VAL")
.help("Some vals") .possible_values(&["fast", "slow"])
.takes_value(true)) .help("Some vals")
.arg(Arg::with_name("cafe") .takes_value(true),
.short("c") )
.long("cafe") .arg(
.value_name("FILE") Arg::with_name("cafe")
.hide_possible_values(true) .short("c")
.possible_values(&["fast", "slow"]) .long("cafe")
.help("A coffeehouse, coffee shop, or café.") .value_name("FILE")
.takes_value(true)); .hide_possible_values(true)
assert!(test::compare_output(app, "ctest --help", HIDE_POS_VALS, false)); .possible_values(&["fast", "slow"])
.help("A coffeehouse, coffee shop, or café.")
.takes_value(true),
);
assert!(test::compare_output(
app,
"ctest --help",
HIDE_POS_VALS,
false
));
} }
#[test] #[test]
@ -740,7 +798,12 @@ fn issue_626_panic() {
d'Afrique et d'Asie, dans des plantations qui sont cultivées pour les marchés d'exportation. \ d'Afrique et d'Asie, dans des plantations qui sont cultivées pour les marchés d'exportation. \
Le café est souvent une contribution majeure aux exportations des régions productrices.") Le café est souvent une contribution majeure aux exportations des régions productrices.")
.takes_value(true)); .takes_value(true));
assert!(test::compare_output(app, "ctest --help", ISSUE_626_PANIC, false)); assert!(test::compare_output(
app,
"ctest --help",
ISSUE_626_PANIC,
false
));
} }
#[test] #[test]
@ -764,29 +827,44 @@ fn issue_626_variable_panic() {
#[test] #[test]
fn final_word_wrapping() { fn final_word_wrapping() {
let app = App::new("ctest").version("0.1").set_term_width(24); let app = App::new("ctest").version("0.1").set_term_width(24);
assert!(test::compare_output(app, "ctest --help", FINAL_WORD_WRAPPING, false)); assert!(test::compare_output(
app,
"ctest --help",
FINAL_WORD_WRAPPING,
false
));
} }
#[test] #[test]
fn wrapping_newline_chars() { fn wrapping_newline_chars() {
let app = App::new("ctest") let app = App::new("ctest").version("0.1").set_term_width(60).arg(
.version("0.1") Arg::with_name("mode").help(
.set_term_width(60) "x, max, maximum 20 characters, contains symbols.{n}\
.arg(Arg::with_name("mode") l, long Copy-friendly, 14 characters, contains symbols.{n}\
.help("x, max, maximum 20 characters, contains symbols.{n}\ m, med, medium Copy-friendly, 8 characters, contains symbols.{n}",
l, long Copy-friendly, 14 characters, contains symbols.{n}\ ),
m, med, medium Copy-friendly, 8 characters, contains symbols.{n}")); );
assert!(test::compare_output(app, "ctest --help", WRAPPING_NEWLINE_CHARS, false)); assert!(test::compare_output(
app,
"ctest --help",
WRAPPING_NEWLINE_CHARS,
false
));
} }
#[test] #[test]
fn old_newline_chars() { fn old_newline_chars() {
let app = App::new("ctest") let app = App::new("ctest").version("0.1").arg(
.version("0.1") Arg::with_name("mode")
.arg(Arg::with_name("mode")
.short("m") .short("m")
.help("Some help with some wrapping{n}(Defaults to something)")); .help("Some help with some wrapping{n}(Defaults to something)"),
assert!(test::compare_output(app, "ctest --help", OLD_NEWLINE_CHARS, false)); );
assert!(test::compare_output(
app,
"ctest --help",
OLD_NEWLINE_CHARS,
false
));
} }
#[test] #[test]
@ -834,25 +912,29 @@ fn issue_702_multiple_values() {
.author("foo") .author("foo")
.about("bar") .about("bar")
.arg(Arg::with_name("arg1").help("some option")) .arg(Arg::with_name("arg1").help("some option"))
.arg(Arg::with_name("arg2") .arg(Arg::with_name("arg2").multiple(true).help("some option"))
.multiple(true) .arg(
.help("some option")) Arg::with_name("some")
.arg(Arg::with_name("some") .help("some option")
.help("some option") .short("s")
.short("s") .long("some")
.long("some") .takes_value(true),
.takes_value(true)) )
.arg(Arg::with_name("other") .arg(
.help("some other option") Arg::with_name("other")
.short("o") .help("some other option")
.long("other") .short("o")
.takes_value(true)) .long("other")
.arg(Arg::with_name("label") .takes_value(true),
.help("a label") )
.short("l") .arg(
.long("label") Arg::with_name("label")
.multiple(true) .help("a label")
.takes_value(true)); .short("l")
.long("label")
.multiple(true)
.takes_value(true),
);
assert!(test::compare_output(app, "myapp --help", ISSUE_702, false)); assert!(test::compare_output(app, "myapp --help", ISSUE_702, false));
} }
@ -862,7 +944,9 @@ fn long_about() {
.version("1.0") .version("1.0")
.author("foo") .author("foo")
.about("bar") .about("bar")
.long_about("something really really long, with\nmultiple lines of text\nthat should be displayed") .long_about(
"something really really long, with\nmultiple lines of text\nthat should be displayed",
)
.arg(Arg::with_name("arg1").help("some option")); .arg(Arg::with_name("arg1").help("some option"));
assert!(test::compare_output(app, "myapp --help", LONG_ABOUT, false)); assert!(test::compare_output(app, "myapp --help", LONG_ABOUT, false));
} }
@ -871,29 +955,33 @@ fn long_about() {
fn issue_760() { fn issue_760() {
let app = App::new("ctest") let app = App::new("ctest")
.version("0.1") .version("0.1")
.arg(Arg::with_name("option") .arg(
.help("tests options") Arg::with_name("option")
.short("o") .help("tests options")
.long("option") .short("o")
.takes_value(true) .long("option")
.multiple(true) .takes_value(true)
.number_of_values(1)) .multiple(true)
.arg(Arg::with_name("opt") .number_of_values(1),
.help("tests options") )
.short("O") .arg(
.long("opt") Arg::with_name("opt")
.takes_value(true)); .help("tests options")
.short("O")
.long("opt")
.takes_value(true),
);
assert!(test::compare_output(app, "ctest --help", ISSUE_760, false)); assert!(test::compare_output(app, "ctest --help", ISSUE_760, false));
} }
#[test] #[test]
fn ripgrep_usage() { fn ripgrep_usage() {
let app = App::new("ripgrep") let app = App::new("ripgrep").version("0.5").usage(
.version("0.5") "rg [OPTIONS] <pattern> [<path> ...]
.usage("rg [OPTIONS] <pattern> [<path> ...]
rg [OPTIONS] [-e PATTERN | -f FILE ]... [<path> ...] rg [OPTIONS] [-e PATTERN | -f FILE ]... [<path> ...]
rg [OPTIONS] --files [<path> ...] rg [OPTIONS] --files [<path> ...]
rg [OPTIONS] --type-list"); rg [OPTIONS] --type-list",
);
assert!(test::compare_output(app, "rg --help", RIPGREP_USAGE, false)); assert!(test::compare_output(app, "rg --help", RIPGREP_USAGE, false));
} }
@ -902,18 +990,22 @@ fn ripgrep_usage() {
fn ripgrep_usage_using_templates() { fn ripgrep_usage_using_templates() {
let app = App::new("ripgrep") let app = App::new("ripgrep")
.version("0.5") .version("0.5")
.usage(" .usage(
"
rg [OPTIONS] <pattern> [<path> ...] rg [OPTIONS] <pattern> [<path> ...]
rg [OPTIONS] [-e PATTERN | -f FILE ]... [<path> ...] rg [OPTIONS] [-e PATTERN | -f FILE ]... [<path> ...]
rg [OPTIONS] --files [<path> ...] rg [OPTIONS] --files [<path> ...]
rg [OPTIONS] --type-list") rg [OPTIONS] --type-list",
.template("\ )
.template(
"\
{bin} {version} {bin} {version}
USAGE:{usage} USAGE:{usage}
FLAGS: FLAGS:
{flags}"); {flags}",
);
assert!(test::compare_output(app, "rg --help", RIPGREP_USAGE, false)); assert!(test::compare_output(app, "rg --help", RIPGREP_USAGE, false));
} }
@ -926,15 +1018,22 @@ fn sc_negates_reqs() {
.arg_from_usage("-o, --opt <FILE> 'tests options'") .arg_from_usage("-o, --opt <FILE> 'tests options'")
.arg(Arg::with_name("PATH").help("help")) .arg(Arg::with_name("PATH").help("help"))
.subcommand(SubCommand::with_name("test")); .subcommand(SubCommand::with_name("test"));
assert!(test::compare_output(app, "prog --help", SC_NEGATES_REQS, false)); assert!(test::compare_output(
app,
"prog --help",
SC_NEGATES_REQS,
false
));
} }
#[test] #[test]
fn hidden_args() { fn hidden_args() {
let app = App::new("prog") let app = App::new("prog")
.version("1.0") .version("1.0")
.args_from_usage("-f, --flag 'testing flags' .args_from_usage(
-o, --opt [FILE] 'tests options'") "-f, --flag 'testing flags'
-o, --opt [FILE] 'tests options'",
)
.arg(Arg::with_name("pos").hidden(true)); .arg(Arg::with_name("pos").hidden(true));
assert!(test::compare_output(app, "prog --help", HIDDEN_ARGS, false)); assert!(test::compare_output(app, "prog --help", HIDDEN_ARGS, false));
} }
@ -944,22 +1043,36 @@ fn args_negate_sc() {
let app = App::new("prog") let app = App::new("prog")
.version("1.0") .version("1.0")
.setting(AppSettings::ArgsNegateSubcommands) .setting(AppSettings::ArgsNegateSubcommands)
.args_from_usage("-f, --flag 'testing flags' .args_from_usage(
-o, --opt [FILE] 'tests options'") "-f, --flag 'testing flags'
-o, --opt [FILE] 'tests options'",
)
.arg(Arg::with_name("PATH").help("help")) .arg(Arg::with_name("PATH").help("help"))
.subcommand(SubCommand::with_name("test")); .subcommand(SubCommand::with_name("test"));
assert!(test::compare_output(app, "prog --help", ARGS_NEGATE_SC, false)); assert!(test::compare_output(
app,
"prog --help",
ARGS_NEGATE_SC,
false
));
} }
#[test] #[test]
fn issue_1046_hidden_scs() { fn issue_1046_hidden_scs() {
let app = App::new("prog") let app = App::new("prog")
.version("1.0") .version("1.0")
.args_from_usage("-f, --flag 'testing flags' .args_from_usage(
-o, --opt [FILE] 'tests options'") "-f, --flag 'testing flags'
-o, --opt [FILE] 'tests options'",
)
.arg(Arg::with_name("PATH").help("some")) .arg(Arg::with_name("PATH").help("some"))
.subcommand(SubCommand::with_name("test").setting(AppSettings::Hidden)); .subcommand(SubCommand::with_name("test").setting(AppSettings::Hidden));
assert!(test::compare_output(app, "prog --help", ISSUE_1046_HIDDEN_SCS, false)); assert!(test::compare_output(
app,
"prog --help",
ISSUE_1046_HIDDEN_SCS,
false
));
} }
#[test] #[test]
@ -982,74 +1095,118 @@ fn customize_version_and_help() {
.help_message("Print help information") .help_message("Print help information")
.version_short("v") .version_short("v")
.version_message("Print version information"); .version_message("Print version information");
assert!(test::compare_output(app, "customize --help", CUSTOM_VERSION_AND_HELP, false)); assert!(test::compare_output(
app,
"customize --help",
CUSTOM_VERSION_AND_HELP,
false
));
} }
#[test] #[test]
fn last_arg_mult_usage() { fn last_arg_mult_usage() {
let app = App::new("last") let app = App::new("last")
.version("0.1") .version("0.1")
.arg(Arg::with_name("TARGET").required(true).help("some")) .arg(Arg::with_name("TARGET").required(true).help("some"))
.arg(Arg::with_name("CORPUS").help("some")) .arg(Arg::with_name("CORPUS").help("some"))
.arg(Arg::with_name("ARGS").multiple(true).last(true).help("some")); .arg(
Arg::with_name("ARGS")
.multiple(true)
.last(true)
.help("some"),
);
assert!(test::compare_output(app, "last --help", LAST_ARG, false)); assert!(test::compare_output(app, "last --help", LAST_ARG, false));
} }
#[test] #[test]
fn last_arg_mult_usage_req() { fn last_arg_mult_usage_req() {
let app = App::new("last") let app = App::new("last")
.version("0.1") .version("0.1")
.arg(Arg::with_name("TARGET").required(true).help("some")) .arg(Arg::with_name("TARGET").required(true).help("some"))
.arg(Arg::with_name("CORPUS").help("some")) .arg(Arg::with_name("CORPUS").help("some"))
.arg(Arg::with_name("ARGS").multiple(true).last(true).required(true).help("some")); .arg(
assert!(test::compare_output(app, "last --help", LAST_ARG_REQ, false)); Arg::with_name("ARGS")
.multiple(true)
.last(true)
.required(true)
.help("some"),
);
assert!(test::compare_output(
app,
"last --help",
LAST_ARG_REQ,
false
));
} }
#[test] #[test]
fn last_arg_mult_usage_req_with_sc() { fn last_arg_mult_usage_req_with_sc() {
let app = App::new("last") let app = App::new("last")
.version("0.1") .version("0.1")
.setting(AppSettings::SubcommandsNegateReqs) .setting(AppSettings::SubcommandsNegateReqs)
.arg(Arg::with_name("TARGET").required(true).help("some")) .arg(Arg::with_name("TARGET").required(true).help("some"))
.arg(Arg::with_name("CORPUS").help("some")) .arg(Arg::with_name("CORPUS").help("some"))
.arg(Arg::with_name("ARGS").multiple(true).last(true).required(true).help("some")) .arg(
.subcommand(SubCommand::with_name("test").about("some")); Arg::with_name("ARGS")
assert!(test::compare_output(app, "last --help", LAST_ARG_REQ_SC, false)); .multiple(true)
.last(true)
.required(true)
.help("some"),
)
.subcommand(SubCommand::with_name("test").about("some"));
assert!(test::compare_output(
app,
"last --help",
LAST_ARG_REQ_SC,
false
));
} }
#[test] #[test]
fn last_arg_mult_usage_with_sc() { fn last_arg_mult_usage_with_sc() {
let app = App::new("last") let app = App::new("last")
.version("0.1") .version("0.1")
.setting(AppSettings::ArgsNegateSubcommands) .setting(AppSettings::ArgsNegateSubcommands)
.arg(Arg::with_name("TARGET").required(true).help("some")) .arg(Arg::with_name("TARGET").required(true).help("some"))
.arg(Arg::with_name("CORPUS").help("some")) .arg(Arg::with_name("CORPUS").help("some"))
.arg(Arg::with_name("ARGS").multiple(true).last(true).help("some")) .arg(
.subcommand(SubCommand::with_name("test").about("some")); Arg::with_name("ARGS")
.multiple(true)
.last(true)
.help("some"),
)
.subcommand(SubCommand::with_name("test").about("some"));
assert!(test::compare_output(app, "last --help", LAST_ARG_SC, false)); assert!(test::compare_output(app, "last --help", LAST_ARG_SC, false));
} }
#[test] #[test]
fn hidden_default_val() { fn hidden_default_val() {
let app1 = App::new("default") let app1 = App::new("default").version("0.1").set_term_width(120).arg(
.version("0.1") Arg::with_name("argument")
.set_term_width(120) .help("Pass an argument to the program. [default: default-argument]")
.arg(Arg::with_name("argument") .long("arg")
.help("Pass an argument to the program. [default: default-argument]") .default_value("default-argument")
.long("arg") .hide_default_value(true),
.default_value("default-argument") );
.hide_default_value(true)); assert!(test::compare_output(
assert!(test::compare_output(app1, "default --help", HIDE_DEFAULT_VAL, false)); app1,
"default --help",
HIDE_DEFAULT_VAL,
false
));
let app2 = App::new("default") let app2 = App::new("default").version("0.1").set_term_width(120).arg(
.version("0.1") Arg::with_name("argument")
.set_term_width(120) .help("Pass an argument to the program.")
.arg(Arg::with_name("argument") .long("arg")
.help("Pass an argument to the program.") .default_value("default-argument"),
.long("arg") );
.default_value("default-argument")); assert!(test::compare_output(
assert!(test::compare_output(app2, "default --help", HIDE_DEFAULT_VAL, false)); app2,
"default --help",
HIDE_DEFAULT_VAL,
false
));
} }
fn issue_1112_setup() -> App<'static, 'static> { fn issue_1112_setup() -> App<'static, 'static> {
@ -1058,14 +1215,12 @@ fn issue_1112_setup() -> App<'static, 'static> {
.about("tests stuff") .about("tests stuff")
.version("1.3") .version("1.3")
.arg(Arg::from_usage("-h, --help 'some help'")) .arg(Arg::from_usage("-h, --help 'some help'"))
.subcommand(SubCommand::with_name("foo") .subcommand(SubCommand::with_name("foo").arg(Arg::from_usage("-h, --help 'some help'")))
.arg(Arg::from_usage("-h, --help 'some help'")))
} }
#[test] #[test]
fn issue_1112_override_help_long() { fn issue_1112_override_help_long() {
let m = issue_1112_setup() let m = issue_1112_setup().get_matches_from_safe(vec!["test", "--help"]);
.get_matches_from_safe(vec!["test", "--help"]);
assert!(m.is_ok()); assert!(m.is_ok());
assert!(m.unwrap().is_present("help")); assert!(m.unwrap().is_present("help"));
@ -1073,8 +1228,7 @@ fn issue_1112_override_help_long() {
#[test] #[test]
fn issue_1112_override_help_short() { fn issue_1112_override_help_short() {
let m = issue_1112_setup() let m = issue_1112_setup().get_matches_from_safe(vec!["test", "-h"]);
.get_matches_from_safe(vec!["test", "-h"]);
assert!(m.is_ok()); assert!(m.is_ok());
assert!(m.unwrap().is_present("help")); assert!(m.unwrap().is_present("help"));
@ -1082,20 +1236,28 @@ fn issue_1112_override_help_short() {
#[test] #[test]
fn issue_1112_override_help_subcmd_long() { fn issue_1112_override_help_subcmd_long() {
let m = issue_1112_setup() let m = issue_1112_setup().get_matches_from_safe(vec!["test", "foo", "--help"]);
.get_matches_from_safe(vec!["test", "foo", "--help"]);
assert!(m.is_ok()); assert!(m.is_ok());
assert!(m.unwrap().subcommand_matches("foo").unwrap().is_present("help")); assert!(
m.unwrap()
.subcommand_matches("foo")
.unwrap()
.is_present("help")
);
} }
#[test] #[test]
fn issue_1112_override_help_subcmd_short() { fn issue_1112_override_help_subcmd_short() {
let m = issue_1112_setup() let m = issue_1112_setup().get_matches_from_safe(vec!["test", "foo", "-h"]);
.get_matches_from_safe(vec!["test", "foo", "-h"]);
assert!(m.is_ok()); assert!(m.is_ok());
assert!(m.unwrap().subcommand_matches("foo").unwrap().is_present("help")); assert!(
m.unwrap()
.subcommand_matches("foo")
.unwrap()
.is_present("help")
);
} }
#[test] #[test]
@ -1104,9 +1266,18 @@ fn issue_1052_require_delim_help() {
.author("Kevin K.") .author("Kevin K.")
.about("tests stuff") .about("tests stuff")
.version("1.3") .version("1.3")
.arg(Arg::from_usage("-f, --fake <some> <val> 'some help'").require_delimiter(true).value_delimiter(":")); .arg(
Arg::from_usage("-f, --fake <some> <val> 'some help'")
.require_delimiter(true)
.value_delimiter(":"),
);
assert!(test::compare_output(app, "test --help", REQUIRE_DELIM_HELP, false)); assert!(test::compare_output(
app,
"test --help",
REQUIRE_DELIM_HELP,
false
));
} }
#[test] #[test]
@ -1116,22 +1287,31 @@ fn hide_env_vals() {
env::set_var("ENVVAR", "MYVAL"); env::set_var("ENVVAR", "MYVAL");
let app = App::new("ctest") let app = App::new("ctest")
.version("0.1") .version("0.1")
.arg(Arg::with_name("pos") .arg(
.short("p") Arg::with_name("pos")
.long("pos") .short("p")
.value_name("VAL") .long("pos")
.possible_values(&["fast", "slow"]) .value_name("VAL")
.help("Some vals") .possible_values(&["fast", "slow"])
.takes_value(true)) .help("Some vals")
.arg(Arg::with_name("cafe") .takes_value(true),
.short("c") )
.long("cafe") .arg(
.value_name("FILE") Arg::with_name("cafe")
.hide_env_values(true) .short("c")
.env("ENVVAR") .long("cafe")
.help("A coffeehouse, coffee shop, or café.") .value_name("FILE")
.takes_value(true)); .hide_env_values(true)
assert!(test::compare_output(app, "ctest --help", HIDE_ENV_VALS, false)); .env("ENVVAR")
.help("A coffeehouse, coffee shop, or café.")
.takes_value(true),
);
assert!(test::compare_output(
app,
"ctest --help",
HIDE_ENV_VALS,
false
));
} }
#[test] #[test]
@ -1141,20 +1321,29 @@ fn show_env_vals() {
env::set_var("ENVVAR", "MYVAL"); env::set_var("ENVVAR", "MYVAL");
let app = App::new("ctest") let app = App::new("ctest")
.version("0.1") .version("0.1")
.arg(Arg::with_name("pos") .arg(
.short("p") Arg::with_name("pos")
.long("pos") .short("p")
.value_name("VAL") .long("pos")
.possible_values(&["fast", "slow"]) .value_name("VAL")
.help("Some vals") .possible_values(&["fast", "slow"])
.takes_value(true)) .help("Some vals")
.arg(Arg::with_name("cafe") .takes_value(true),
.short("c") )
.long("cafe") .arg(
.value_name("FILE") Arg::with_name("cafe")
.hide_possible_values(true) .short("c")
.env("ENVVAR") .long("cafe")
.help("A coffeehouse, coffee shop, or café.") .value_name("FILE")
.takes_value(true)); .hide_possible_values(true)
assert!(test::compare_output(app, "ctest --help", SHOW_ENV_VALS, false)); .env("ENVVAR")
.help("A coffeehouse, coffee shop, or café.")
.takes_value(true),
);
assert!(test::compare_output(
app,
"ctest --help",
SHOW_ENV_VALS,
false
));
} }

View file

@ -26,9 +26,11 @@ fn hidden_args() {
.author("Kevin K.") .author("Kevin K.")
.about("tests stuff") .about("tests stuff")
.version("1.4") .version("1.4")
.args(&[Arg::from_usage("-f, --flag 'some flag'").hidden(true), .args(&[
Arg::from_usage("-F, --flag2 'some other flag'"), Arg::from_usage("-f, --flag 'some flag'").hidden(true),
Arg::from_usage("--option [opt] 'some option'"), Arg::from_usage("-F, --flag2 'some other flag'"),
Arg::with_name("DUMMY").required(false).hidden(true)]); Arg::from_usage("--option [opt] 'some option'"),
Arg::with_name("DUMMY").required(false).hidden(true),
]);
assert!(test::compare_output(app, "test --help", HIDDEN_ARGS, false)); assert!(test::compare_output(app, "test --help", HIDDEN_ARGS, false));
} }

View file

@ -36,7 +36,7 @@ fn basic() {
#[test] #[test]
fn quoted_app_name() { fn quoted_app_name() {
let app = clap_app!(("app name with spaces-and-hyphens") => let mut app = clap_app!(("app name with spaces-and-hyphens") =>
(version: "0.1") (version: "0.1")
(about: "tests clap library") (about: "tests clap library")
(author: "Kevin K. <kbknapp@gmail.com>") (author: "Kevin K. <kbknapp@gmail.com>")
@ -66,10 +66,11 @@ fn quoted_app_name() {
(@arg scpositional: index(1) "tests positionals")) (@arg scpositional: index(1) "tests positionals"))
); );
assert_eq!(app.p.meta.name, "app name with spaces-and-hyphens"); assert_eq!(app.name, "app name with spaces-and-hyphens");
let mut help_text = vec![]; let mut help_text = vec![];
app.write_help(&mut help_text).expect("Could not write help text."); app.write_help(&mut help_text)
.expect("Could not write help text.");
let help_text = String::from_utf8(help_text).expect("Help text is not valid utf-8"); let help_text = String::from_utf8(help_text).expect("Help text is not valid utf-8");
assert!(help_text.starts_with("app name with spaces-and-hyphens 0.1\n")); assert!(help_text.starts_with("app name with spaces-and-hyphens 0.1\n"));
} }
@ -106,8 +107,9 @@ fn quoted_arg_long_name() {
(@arg scpositional: index(1) "tests positionals")) (@arg scpositional: index(1) "tests positionals"))
); );
let matches = app.get_matches_from_safe(vec!["bin_name", "value1", "value2", "--long-option-2"]) let matches =
.expect("Expected to successfully match the given args."); app.get_matches_from_safe(vec!["bin_name", "value1", "value2", "--long-option-2"])
.expect("Expected to successfully match the given args.");
assert!(matches.is_present("option2")); assert!(matches.is_present("option2"));
} }
@ -143,8 +145,9 @@ fn quoted_arg_name() {
(@arg scpositional: index(1) "tests positionals")) (@arg scpositional: index(1) "tests positionals"))
); );
let matches = app.get_matches_from_safe(vec!["bin_name", "value1", "value2", "--long-option-2"]) let matches =
.expect("Expected to successfully match the given args."); app.get_matches_from_safe(vec!["bin_name", "value1", "value2", "--long-option-2"])
.expect("Expected to successfully match the given args.");
assert!(matches.is_present("option2")); assert!(matches.is_present("option2"));
} }

View file

@ -5,15 +5,9 @@ use clap::{App, Arg};
#[test] #[test]
fn multiple_occurrences_of_flags_long() { fn multiple_occurrences_of_flags_long() {
let m = App::new("mo_flags_long") let m = App::new("mo_flags_long")
.arg(Arg::from_usage("--multflag 'allowed multiple flag'") .arg(Arg::from_usage("--multflag 'allowed multiple flag'").multiple(true))
.multiple(true)) .arg(Arg::from_usage("--flag 'disallowed multiple flag'"))
.arg(Arg::from_usage("--flag 'disallowed multiple flag'")) .get_matches_from(vec!["", "--multflag", "--flag", "--multflag"]);
.get_matches_from(vec![
"",
"--multflag",
"--flag",
"--multflag"
]);
assert!(m.is_present("multflag")); assert!(m.is_present("multflag"));
assert_eq!(m.occurrences_of("multflag"), 2); assert_eq!(m.occurrences_of("multflag"), 2);
assert!(m.is_present("flag")); assert!(m.is_present("flag"));
@ -23,15 +17,9 @@ fn multiple_occurrences_of_flags_long() {
#[test] #[test]
fn multiple_occurrences_of_flags_short() { fn multiple_occurrences_of_flags_short() {
let m = App::new("mo_flags_short") let m = App::new("mo_flags_short")
.arg(Arg::from_usage("-m --multflag 'allowed multiple flag'") .arg(Arg::from_usage("-m --multflag 'allowed multiple flag'").multiple(true))
.multiple(true)) .arg(Arg::from_usage("-f --flag 'disallowed multiple flag'"))
.arg(Arg::from_usage("-f --flag 'disallowed multiple flag'")) .get_matches_from(vec!["", "-m", "-f", "-m"]);
.get_matches_from(vec![
"",
"-m",
"-f",
"-m"
]);
assert!(m.is_present("multflag")); assert!(m.is_present("multflag"));
assert_eq!(m.occurrences_of("multflag"), 2); assert_eq!(m.occurrences_of("multflag"), 2);
assert!(m.is_present("flag")); assert!(m.is_present("flag"));
@ -41,20 +29,18 @@ fn multiple_occurrences_of_flags_short() {
#[test] #[test]
fn multiple_occurrences_of_flags_mixed() { fn multiple_occurrences_of_flags_mixed() {
let m = App::new("mo_flags_mixed") let m = App::new("mo_flags_mixed")
.arg(Arg::from_usage("-m, --multflag1 'allowed multiple flag'") .arg(Arg::from_usage("-m, --multflag1 'allowed multiple flag'").multiple(true))
.multiple(true)) .arg(Arg::from_usage("-n, --multflag2 'another allowed multiple flag'").multiple(true))
.arg(Arg::from_usage("-n, --multflag2 'another allowed multiple flag'") .arg(Arg::from_usage("-f, --flag 'disallowed multiple flag'"))
.multiple(true)) .get_matches_from(vec![
.arg(Arg::from_usage("-f, --flag 'disallowed multiple flag'")) "",
.get_matches_from(vec![ "-m",
"", "-f",
"-m", "-n",
"-f", "--multflag1",
"-n", "-m",
"--multflag1", "--multflag2",
"-m", ]);
"--multflag2"
]);
assert!(m.is_present("multflag1")); assert!(m.is_present("multflag1"));
assert_eq!(m.occurrences_of("multflag1"), 3); assert_eq!(m.occurrences_of("multflag1"), 3);
assert!(m.is_present("multflag2")); assert!(m.is_present("multflag2"));
@ -65,11 +51,13 @@ fn multiple_occurrences_of_flags_mixed() {
#[test] #[test]
fn multiple_occurrences_of_flags_large_quantity() { fn multiple_occurrences_of_flags_large_quantity() {
let args : Vec<&str> = vec![""].into_iter().chain(vec!["-m"; 1024].into_iter()).collect(); let args: Vec<&str> = vec![""]
.into_iter()
.chain(vec!["-m"; 1024].into_iter())
.collect();
let m = App::new("mo_flags_larg_qty") let m = App::new("mo_flags_larg_qty")
.arg(Arg::from_usage("-m --multflag 'allowed multiple flag'") .arg(Arg::from_usage("-m --multflag 'allowed multiple flag'").multiple(true))
.multiple(true)) .get_matches_from(args);
.get_matches_from(args);
assert!(m.is_present("multflag")); assert!(m.is_present("multflag"));
assert_eq!(m.occurrences_of("multflag"), 1024); assert_eq!(m.occurrences_of("multflag"), 1024);
} }

File diff suppressed because it is too large Load diff

View file

@ -3,10 +3,11 @@ extern crate regex;
include!("../clap-test.rs"); include!("../clap-test.rs");
use clap::{App, ArgMatches, Arg, ErrorKind}; use clap::{App, Arg, ArgMatches, ErrorKind};
#[cfg(feature = "suggestions")] #[cfg(feature = "suggestions")]
static DYM: &'static str = "error: Found argument '--optio' which wasn't expected, or isn't valid in this context static DYM: &'static str =
"error: Found argument '--optio' which wasn't expected, or isn't valid in this context
\tDid you mean --option? \tDid you mean --option?
USAGE: USAGE:
@ -17,13 +18,13 @@ For more information try --help";
#[test] #[test]
fn require_equals_fail() { fn require_equals_fail() {
let res = App::new("prog") let res = App::new("prog")
.arg(Arg::with_name("cfg") .arg(
.require_equals(true) Arg::with_name("cfg")
.takes_value(true) .require_equals(true)
.long("config")) .takes_value(true)
.get_matches_from_safe(vec![ .long("config"),
"prog", "--config", "file.conf" )
]); .get_matches_from_safe(vec!["prog", "--config", "file.conf"]);
assert!(res.is_err()); assert!(res.is_err());
assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue); assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue);
} }
@ -31,15 +32,15 @@ fn require_equals_fail() {
#[test] #[test]
fn require_equals_min_values_zero() { fn require_equals_min_values_zero() {
let res = App::new("prog") let res = App::new("prog")
.arg(Arg::with_name("cfg") .arg(
.require_equals(true) Arg::with_name("cfg")
.takes_value(true) .require_equals(true)
.min_values(0) .takes_value(true)
.long("config")) .min_values(0)
.long("config"),
)
.arg(Arg::with_name("cmd")) .arg(Arg::with_name("cmd"))
.get_matches_from_safe(vec![ .get_matches_from_safe(vec!["prog", "--config", "cmd"]);
"prog", "--config", "cmd"
]);
assert!(res.is_ok()); assert!(res.is_ok());
let m = res.unwrap(); let m = res.unwrap();
assert!(m.is_present("cfg")); assert!(m.is_present("cfg"));
@ -49,13 +50,13 @@ fn require_equals_min_values_zero() {
#[test] #[test]
fn double_hyphen_as_value() { fn double_hyphen_as_value() {
let res = App::new("prog") let res = App::new("prog")
.arg(Arg::with_name("cfg") .arg(
.takes_value(true) Arg::with_name("cfg")
.allow_hyphen_values(true) .takes_value(true)
.long("config")) .allow_hyphen_values(true)
.get_matches_from_safe(vec![ .long("config"),
"prog", "--config", "--" )
]); .get_matches_from_safe(vec!["prog", "--config", "--"]);
assert!(res.is_ok(), "{:?}", res); assert!(res.is_ok(), "{:?}", res);
assert_eq!(res.unwrap().value_of("cfg"), Some("--")); assert_eq!(res.unwrap().value_of("cfg"), Some("--"));
} }
@ -63,14 +64,14 @@ fn double_hyphen_as_value() {
#[test] #[test]
fn require_equals_no_empty_values_fail() { fn require_equals_no_empty_values_fail() {
let res = App::new("prog") let res = App::new("prog")
.arg(Arg::with_name("cfg") .arg(
.require_equals(true) Arg::with_name("cfg")
.takes_value(true) .require_equals(true)
.long("config")) .takes_value(true)
.long("config"),
)
.arg(Arg::with_name("some")) .arg(Arg::with_name("some"))
.get_matches_from_safe(vec![ .get_matches_from_safe(vec!["prog", "--config=", "file.conf"]);
"prog", "--config=", "file.conf"
]);
assert!(res.is_err()); assert!(res.is_err());
assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue); assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue);
} }
@ -78,27 +79,27 @@ fn require_equals_no_empty_values_fail() {
#[test] #[test]
fn require_equals_empty_vals_pass() { fn require_equals_empty_vals_pass() {
let res = App::new("prog") let res = App::new("prog")
.arg(Arg::with_name("cfg") .arg(
.require_equals(true) Arg::with_name("cfg")
.takes_value(true) .require_equals(true)
.empty_values(true) .takes_value(true)
.long("config")) .empty_values(true)
.get_matches_from_safe(vec![ .long("config"),
"prog", "--config=" )
]); .get_matches_from_safe(vec!["prog", "--config="]);
assert!(res.is_ok()); assert!(res.is_ok());
} }
#[test] #[test]
fn require_equals_pass() { fn require_equals_pass() {
let res = App::new("prog") let res = App::new("prog")
.arg(Arg::with_name("cfg") .arg(
.require_equals(true) Arg::with_name("cfg")
.takes_value(true) .require_equals(true)
.long("config")) .takes_value(true)
.get_matches_from_safe(vec![ .long("config"),
"prog", "--config=file.conf" )
]); .get_matches_from_safe(vec!["prog", "--config=file.conf"]);
assert!(res.is_ok()); assert!(res.is_ok());
} }
@ -116,8 +117,10 @@ fn stdin_char() {
#[test] #[test]
fn opts_using_short() { fn opts_using_short() {
let r = App::new("opts") let r = App::new("opts")
.args(&[Arg::from_usage("-f [flag] 'some flag'"), .args(&[
Arg::from_usage("-c [color] 'some other flag'")]) Arg::from_usage("-f [flag] 'some flag'"),
Arg::from_usage("-c [color] 'some other flag'"),
])
.get_matches_from_safe(vec!["", "-f", "some", "-c", "other"]); .get_matches_from_safe(vec!["", "-f", "some", "-c", "other"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -131,49 +134,36 @@ fn opts_using_short() {
fn lots_o_vals() { fn lots_o_vals() {
let r = App::new("opts") let r = App::new("opts")
.arg(Arg::from_usage("-o [opt]... 'some opt'")) .arg(Arg::from_usage("-o [opt]... 'some opt'"))
.get_matches_from_safe(vec!["", "-o", "some", "some", "some", "some", "some", "some", .get_matches_from_safe(vec![
"some", "some", "some", "some", "some", "some", "some", "", "-o", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", ]);
"some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
assert!(m.is_present("o")); assert!(m.is_present("o"));
@ -183,8 +173,10 @@ fn lots_o_vals() {
#[test] #[test]
fn opts_using_long_space() { fn opts_using_long_space() {
let r = App::new("opts") let r = App::new("opts")
.args(&[Arg::from_usage("--flag [flag] 'some flag'"), .args(&[
Arg::from_usage("--color [color] 'some other flag'")]) Arg::from_usage("--flag [flag] 'some flag'"),
Arg::from_usage("--color [color] 'some other flag'"),
])
.get_matches_from_safe(vec!["", "--flag", "some", "--color", "other"]); .get_matches_from_safe(vec!["", "--flag", "some", "--color", "other"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -197,8 +189,10 @@ fn opts_using_long_space() {
#[test] #[test]
fn opts_using_long_equals() { fn opts_using_long_equals() {
let r = App::new("opts") let r = App::new("opts")
.args(&[Arg::from_usage("--flag [flag] 'some flag'"), .args(&[
Arg::from_usage("--color [color] 'some other flag'")]) Arg::from_usage("--flag [flag] 'some flag'"),
Arg::from_usage("--color [color] 'some other flag'"),
])
.get_matches_from_safe(vec!["", "--flag=some", "--color=other"]); .get_matches_from_safe(vec!["", "--flag=some", "--color=other"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -211,8 +205,10 @@ fn opts_using_long_equals() {
#[test] #[test]
fn opts_using_mixed() { fn opts_using_mixed() {
let r = App::new("opts") let r = App::new("opts")
.args(&[Arg::from_usage("-f, --flag [flag] 'some flag'"), .args(&[
Arg::from_usage("-c, --color [color] 'some other flag'")]) Arg::from_usage("-f, --flag [flag] 'some flag'"),
Arg::from_usage("-c, --color [color] 'some other flag'"),
])
.get_matches_from_safe(vec!["", "-f", "some", "--color", "other"]); .get_matches_from_safe(vec!["", "-f", "some", "--color", "other"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -225,8 +221,10 @@ fn opts_using_mixed() {
#[test] #[test]
fn opts_using_mixed2() { fn opts_using_mixed2() {
let r = App::new("opts") let r = App::new("opts")
.args(&[Arg::from_usage("-f, --flag [flag] 'some flag'"), .args(&[
Arg::from_usage("-c, --color [color] 'some other flag'")]) Arg::from_usage("-f, --flag [flag] 'some flag'"),
Arg::from_usage("-c, --color [color] 'some other flag'"),
])
.get_matches_from_safe(vec!["", "--flag=some", "-c", "other"]); .get_matches_from_safe(vec!["", "--flag=some", "-c", "other"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -350,7 +348,11 @@ fn leading_hyphen_with_flag_before() {
#[test] #[test]
fn leading_hyphen_with_only_pos_follows() { fn leading_hyphen_with_only_pos_follows() {
let r = App::new("mvae") let r = App::new("mvae")
.arg(Arg::from_usage("-o [opt]... 'some opt'").number_of_values(1).allow_hyphen_values(true)) .arg(
Arg::from_usage("-o [opt]... 'some opt'")
.number_of_values(1)
.allow_hyphen_values(true),
)
.arg_from_usage("[arg] 'some arg'") .arg_from_usage("[arg] 'some arg'")
.get_matches_from_safe(vec!["", "-o", "-2", "--", "val"]); .get_matches_from_safe(vec!["", "-o", "-2", "--", "val"]);
assert!(r.is_ok(), "{:?}", r); assert!(r.is_ok(), "{:?}", r);
@ -361,12 +363,14 @@ fn leading_hyphen_with_only_pos_follows() {
} }
#[test] #[test]
#[cfg(feature="suggestions")] #[cfg(feature = "suggestions")]
fn did_you_mean() { fn did_you_mean() {
assert!(test::compare_output(test::complex_app(), assert!(test::compare_output(
"clap-test --optio=foo", test::complex_app(),
DYM, "clap-test --optio=foo",
true)); DYM,
true
));
} }
#[test] #[test]
@ -408,7 +412,7 @@ fn issue_1105_setup(argv: Vec<&'static str>) -> Result<ArgMatches<'static>, clap
#[test] #[test]
fn issue_1105_empty_value_long_fail() { fn issue_1105_empty_value_long_fail() {
let r = issue_1105_setup(vec!["app", "--option", "--flag"]); let r = issue_1105_setup(vec!["app", "--option", "--flag"]);
assert!(r.is_err()); assert!(r.is_err());
assert_eq!(r.unwrap_err().kind, ErrorKind::EmptyValue); assert_eq!(r.unwrap_err().kind, ErrorKind::EmptyValue);
} }
@ -423,7 +427,7 @@ fn issue_1105_empty_value_long_explicit() {
#[test] #[test]
fn issue_1105_empty_value_long_equals() { fn issue_1105_empty_value_long_equals() {
let r = issue_1105_setup(vec!["app", "--option="]); let r = issue_1105_setup(vec!["app", "--option="]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
assert_eq!(m.value_of("option"), Some("")); assert_eq!(m.value_of("option"), Some(""));

View file

@ -5,8 +5,10 @@ use clap::{App, Arg, ErrorKind};
#[test] #[test]
fn only_pos_follow() { fn only_pos_follow() {
let r = App::new("onlypos") let r = App::new("onlypos")
.args(&[Arg::from_usage("-f [flag] 'some opt'"), .args(&[
Arg::from_usage("[arg] 'some arg'")]) Arg::from_usage("-f [flag] 'some opt'"),
Arg::from_usage("[arg] 'some arg'"),
])
.get_matches_from_safe(vec!["", "--", "-f"]); .get_matches_from_safe(vec!["", "--", "-f"]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
@ -20,11 +22,13 @@ fn issue_946() {
let r = App::new("compiletest") let r = App::new("compiletest")
.setting(clap::AppSettings::AllowLeadingHyphen) .setting(clap::AppSettings::AllowLeadingHyphen)
.args_from_usage("--exact 'filters match exactly'") .args_from_usage("--exact 'filters match exactly'")
.arg(clap::Arg::with_name("filter") .arg(
.index(1) clap::Arg::with_name("filter")
.takes_value(true) .index(1)
.help("filters to apply to output")) .takes_value(true)
.get_matches_from_safe(vec!["compiletest", "--exact"]); .help("filters to apply to output"),
)
.get_matches_from_safe(vec!["compiletest", "--exact"]);
assert!(r.is_ok(), "{:#?}", r); assert!(r.is_ok(), "{:#?}", r);
let matches = r.unwrap(); let matches = r.unwrap();
@ -37,9 +41,8 @@ fn positional() {
let r = App::new("positional") let r = App::new("positional")
.args(&[ .args(&[
Arg::from_usage("-f, --flag 'some flag'"), Arg::from_usage("-f, --flag 'some flag'"),
Arg::with_name("positional") Arg::with_name("positional").index(1),
.index(1) ])
])
.get_matches_from_safe(vec!["", "-f", "test"]); .get_matches_from_safe(vec!["", "-f", "test"]);
assert!(r.is_ok(), "{:#?}", r); assert!(r.is_ok(), "{:#?}", r);
let m = r.unwrap(); let m = r.unwrap();
@ -50,9 +53,8 @@ fn positional() {
let m = App::new("positional") let m = App::new("positional")
.args(&[ .args(&[
Arg::from_usage("-f, --flag 'some flag'"), Arg::from_usage("-f, --flag 'some flag'"),
Arg::with_name("positional") Arg::with_name("positional").index(1),
.index(1) ])
])
.get_matches_from(vec!["", "test", "--flag"]); .get_matches_from(vec!["", "test", "--flag"]);
assert!(m.is_present("positional")); assert!(m.is_present("positional"));
assert!(m.is_present("flag")); assert!(m.is_present("flag"));
@ -62,10 +64,9 @@ fn positional() {
#[test] #[test]
fn lots_o_vals() { fn lots_o_vals() {
let r = App::new("opts") let r = App::new("opts")
.arg( .arg(Arg::from_usage("[opt]... 'some pos'"))
Arg::from_usage("[opt]... 'some pos'"), .get_matches_from_safe(vec![
) "", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
.get_matches_from_safe(vec!["",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
@ -92,8 +93,8 @@ fn lots_o_vals() {
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
]); ]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
assert!(m.is_present("opt")); assert!(m.is_present("opt"));
@ -105,16 +106,17 @@ fn positional_multiple() {
let r = App::new("positional_multiple") let r = App::new("positional_multiple")
.args(&[ .args(&[
Arg::from_usage("-f, --flag 'some flag'"), Arg::from_usage("-f, --flag 'some flag'"),
Arg::with_name("positional") Arg::with_name("positional").index(1).multiple(true),
.index(1) ])
.multiple(true)
])
.get_matches_from_safe(vec!["", "-f", "test1", "test2", "test3"]); .get_matches_from_safe(vec!["", "-f", "test1", "test2", "test3"]);
assert!(r.is_ok(), "{:#?}", r); assert!(r.is_ok(), "{:#?}", r);
let m = r.unwrap(); let m = r.unwrap();
assert!(m.is_present("positional")); assert!(m.is_present("positional"));
assert!(m.is_present("flag")); assert!(m.is_present("flag"));
assert_eq!(&*m.values_of("positional").unwrap().collect::<Vec<_>>(), &["test1", "test2", "test3"]); assert_eq!(
&*m.values_of("positional").unwrap().collect::<Vec<_>>(),
&["test1", "test2", "test3"]
);
} }
#[test] #[test]
@ -122,16 +124,17 @@ fn positional_multiple_3() {
let r = App::new("positional_multiple") let r = App::new("positional_multiple")
.args(&[ .args(&[
Arg::from_usage("-f, --flag 'some flag'"), Arg::from_usage("-f, --flag 'some flag'"),
Arg::with_name("positional") Arg::with_name("positional").index(1).multiple(true),
.index(1) ])
.multiple(true)
])
.get_matches_from_safe(vec!["", "test1", "test2", "test3", "--flag"]); .get_matches_from_safe(vec!["", "test1", "test2", "test3", "--flag"]);
assert!(r.is_ok(), "{:#?}", r); assert!(r.is_ok(), "{:#?}", r);
let m = r.unwrap(); let m = r.unwrap();
assert!(m.is_present("positional")); assert!(m.is_present("positional"));
assert!(m.is_present("flag")); assert!(m.is_present("flag"));
assert_eq!(&*m.values_of("positional").unwrap().collect::<Vec<_>>(), &["test1", "test2", "test3"]); assert_eq!(
&*m.values_of("positional").unwrap().collect::<Vec<_>>(),
&["test1", "test2", "test3"]
);
} }
#[test] #[test]
@ -139,9 +142,8 @@ fn positional_multiple_2() {
let result = App::new("positional_multiple") let result = App::new("positional_multiple")
.args(&[ .args(&[
Arg::from_usage("-f, --flag 'some flag'"), Arg::from_usage("-f, --flag 'some flag'"),
Arg::with_name("positional") Arg::with_name("positional").index(1),
.index(1) ])
])
.get_matches_from_safe(vec!["", "-f", "test1", "test2", "test3"]); .get_matches_from_safe(vec!["", "-f", "test1", "test2", "test3"]);
assert!(result.is_err()); assert!(result.is_err());
let err = result.err().unwrap(); let err = result.err().unwrap();
@ -155,23 +157,24 @@ fn positional_possible_values() {
Arg::from_usage("-f, --flag 'some flag'"), Arg::from_usage("-f, --flag 'some flag'"),
Arg::with_name("positional") Arg::with_name("positional")
.index(1) .index(1)
.possible_value("test123") .possible_value("test123"),
]) ])
.get_matches_from_safe(vec!["", "-f", "test123"]); .get_matches_from_safe(vec!["", "-f", "test123"]);
assert!(r.is_ok(), "{:#?}", r); assert!(r.is_ok(), "{:#?}", r);
let m = r.unwrap(); let m = r.unwrap();
assert!(m.is_present("positional")); assert!(m.is_present("positional"));
assert!(m.is_present("flag")); assert!(m.is_present("flag"));
assert_eq!(&*m.values_of("positional").unwrap().collect::<Vec<_>>(), &["test123"]); assert_eq!(
&*m.values_of("positional").unwrap().collect::<Vec<_>>(),
&["test123"]
);
} }
#[test] #[test]
fn create_positional() { fn create_positional() {
let _ = App::new("test") let _ = App::new("test")
.arg(Arg::with_name("test") .arg(Arg::with_name("test").index(1).help("testing testing"))
.index(1) .get_matches_from(vec![""]);
.help("testing testing"))
.get_matches_from(vec![""]);
} }
#[test] #[test]
@ -183,13 +186,17 @@ fn positional_hyphen_does_not_panic() {
#[test] #[test]
fn single_positional_usage_string() { fn single_positional_usage_string() {
let m = App::new("test").arg_from_usage("[FILE] 'some file'").get_matches_from(vec!["test"]); let m = App::new("test")
.arg_from_usage("[FILE] 'some file'")
.get_matches_from(vec!["test"]);
assert_eq!(m.usage(), "USAGE:\n test [FILE]"); assert_eq!(m.usage(), "USAGE:\n test [FILE]");
} }
#[test] #[test]
fn single_positional_multiple_usage_string() { fn single_positional_multiple_usage_string() {
let m = App::new("test").arg_from_usage("[FILE]... 'some file'").get_matches_from(vec!["test"]); let m = App::new("test")
.arg_from_usage("[FILE]... 'some file'")
.get_matches_from(vec!["test"]);
assert_eq!(m.usage(), "USAGE:\n test [FILE]..."); assert_eq!(m.usage(), "USAGE:\n test [FILE]...");
} }

View file

@ -5,16 +5,19 @@ use clap::{App, Arg, ErrorKind};
#[test] #[test]
fn posix_compatible_flags_long() { fn posix_compatible_flags_long() {
let m = App::new("posix") let m = App::new("posix")
.arg(Arg::from_usage("--flag 'some flag'").overrides_with("color")) .arg(Arg::from_usage("--flag 'some flag'").overrides_with("color"))
.arg(Arg::from_usage("--color 'some other flag'")) .arg(Arg::from_usage("--color 'some other flag'"))
.get_matches_from(vec!["", "--flag", "--color"]); .get_matches_from(vec!["", "--flag", "--color"]);
assert!(m.is_present("color")); assert!(m.is_present("color"));
assert!(!m.is_present("flag")); assert!(!m.is_present("flag"));
}
#[test]
fn posix_compatible_flags_long_rev() {
let m = App::new("posix") let m = App::new("posix")
.arg(Arg::from_usage("--flag 'some flag'").overrides_with("color")) .arg(Arg::from_usage("--flag 'some flag'").overrides_with("color"))
.arg(Arg::from_usage("--color 'some other flag'")) .arg(Arg::from_usage("--color 'some other flag'"))
.get_matches_from(vec!["", "--color", "--flag"]); .get_matches_from(vec!["", "--color", "--flag"]);
assert!(!m.is_present("color")); assert!(!m.is_present("color"));
assert!(m.is_present("flag")); assert!(m.is_present("flag"));
} }
@ -22,16 +25,19 @@ fn posix_compatible_flags_long() {
#[test] #[test]
fn posix_compatible_flags_short() { fn posix_compatible_flags_short() {
let m = App::new("posix") let m = App::new("posix")
.arg(Arg::from_usage("-f, --flag 'some flag'").overrides_with("color")) .arg(Arg::from_usage("-f, --flag 'some flag'").overrides_with("color"))
.arg(Arg::from_usage("-c, --color 'some other flag'")) .arg(Arg::from_usage("-c, --color 'some other flag'"))
.get_matches_from(vec!["", "-f", "-c"]); .get_matches_from(vec!["", "-f", "-c"]);
assert!(m.is_present("color")); assert!(m.is_present("color"));
assert!(!m.is_present("flag")); assert!(!m.is_present("flag"));
}
#[test]
fn posix_compatible_flags_short_rev() {
let m = App::new("posix") let m = App::new("posix")
.arg(Arg::from_usage("-f, --flag 'some flag'").overrides_with("color")) .arg(Arg::from_usage("-f, --flag 'some flag'").overrides_with("color"))
.arg(Arg::from_usage("-c, --color 'some other flag'")) .arg(Arg::from_usage("-c, --color 'some other flag'"))
.get_matches_from(vec!["", "-c", "-f"]); .get_matches_from(vec!["", "-c", "-f"]);
assert!(!m.is_present("color")); assert!(!m.is_present("color"));
assert!(m.is_present("flag")); assert!(m.is_present("flag"));
} }
@ -39,17 +45,20 @@ fn posix_compatible_flags_short() {
#[test] #[test]
fn posix_compatible_opts_long() { fn posix_compatible_opts_long() {
let m = App::new("posix") let m = App::new("posix")
.arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color")) .arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color"))
.arg(Arg::from_usage("--color [color] 'some other flag'")) .arg(Arg::from_usage("--color [color] 'some other flag'"))
.get_matches_from(vec!["", "--flag", "some" ,"--color", "other"]); .get_matches_from(vec!["", "--flag", "some", "--color", "other"]);
assert!(m.is_present("color")); assert!(m.is_present("color"));
assert_eq!(m.value_of("color").unwrap(), "other"); assert_eq!(m.value_of("color").unwrap(), "other");
assert!(!m.is_present("flag")); assert!(!m.is_present("flag"));
}
#[test]
fn posix_compatible_opts_long_rev() {
let m = App::new("posix") let m = App::new("posix")
.arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color")) .arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color"))
.arg(Arg::from_usage("--color [color] 'some other flag'")) .arg(Arg::from_usage("--color [color] 'some other flag'"))
.get_matches_from(vec!["", "--color", "some" ,"--flag", "other"]); .get_matches_from(vec!["", "--color", "some", "--flag", "other"]);
assert!(!m.is_present("color")); assert!(!m.is_present("color"));
assert!(m.is_present("flag")); assert!(m.is_present("flag"));
assert_eq!(m.value_of("flag").unwrap(), "other"); assert_eq!(m.value_of("flag").unwrap(), "other");
@ -58,17 +67,20 @@ fn posix_compatible_opts_long() {
#[test] #[test]
fn posix_compatible_opts_long_equals() { fn posix_compatible_opts_long_equals() {
let m = App::new("posix") let m = App::new("posix")
.arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color")) .arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color"))
.arg(Arg::from_usage("--color [color] 'some other flag'")) .arg(Arg::from_usage("--color [color] 'some other flag'"))
.get_matches_from(vec!["", "--flag=some" ,"--color=other"]); .get_matches_from(vec!["", "--flag=some", "--color=other"]);
assert!(m.is_present("color")); assert!(m.is_present("color"));
assert_eq!(m.value_of("color").unwrap(), "other"); assert_eq!(m.value_of("color").unwrap(), "other");
assert!(!m.is_present("flag")); assert!(!m.is_present("flag"));
}
#[test]
fn posix_compatible_opts_long_equals_rev() {
let m = App::new("posix") let m = App::new("posix")
.arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color")) .arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color"))
.arg(Arg::from_usage("--color [color] 'some other flag'")) .arg(Arg::from_usage("--color [color] 'some other flag'"))
.get_matches_from(vec!["", "--color=some" ,"--flag=other"]); .get_matches_from(vec!["", "--color=some", "--flag=other"]);
assert!(!m.is_present("color")); assert!(!m.is_present("color"));
assert!(m.is_present("flag")); assert!(m.is_present("flag"));
assert_eq!(m.value_of("flag").unwrap(), "other"); assert_eq!(m.value_of("flag").unwrap(), "other");
@ -77,17 +89,20 @@ fn posix_compatible_opts_long_equals() {
#[test] #[test]
fn posix_compatible_opts_short() { fn posix_compatible_opts_short() {
let m = App::new("posix") let m = App::new("posix")
.arg(Arg::from_usage("-f [flag] 'some flag'").overrides_with("c")) .arg(Arg::from_usage("-f [flag] 'some flag'").overrides_with("c"))
.arg(Arg::from_usage("-c [color] 'some other flag'")) .arg(Arg::from_usage("-c [color] 'some other flag'"))
.get_matches_from(vec!["", "-f", "some", "-c", "other"]); .get_matches_from(vec!["", "-f", "some", "-c", "other"]);
assert!(m.is_present("c")); assert!(m.is_present("c"));
assert_eq!(m.value_of("c").unwrap(), "other"); assert_eq!(m.value_of("c").unwrap(), "other");
assert!(!m.is_present("f")); assert!(!m.is_present("f"));
}
#[test]
fn posix_compatible_opts_short_rev() {
let m = App::new("posix") let m = App::new("posix")
.arg(Arg::from_usage("-f [flag] 'some flag'").overrides_with("c")) .arg(Arg::from_usage("-f [flag] 'some flag'").overrides_with("c"))
.arg(Arg::from_usage("-c [color] 'some other flag'")) .arg(Arg::from_usage("-c [color] 'some other flag'"))
.get_matches_from(vec!["", "-c", "some", "-f", "other"]); .get_matches_from(vec!["", "-c", "some", "-f", "other"]);
assert!(!m.is_present("c")); assert!(!m.is_present("c"));
assert!(m.is_present("f")); assert!(m.is_present("f"));
assert_eq!(m.value_of("f").unwrap(), "other"); assert_eq!(m.value_of("f").unwrap(), "other");
@ -96,11 +111,9 @@ fn posix_compatible_opts_short() {
#[test] #[test]
fn conflict_overriden() { fn conflict_overriden() {
let m = App::new("conflict_overriden") let m = App::new("conflict_overriden")
.arg(Arg::from_usage("-f, --flag 'some flag'") .arg(Arg::from_usage("-f, --flag 'some flag'").conflicts_with("debug"))
.conflicts_with("debug"))
.arg(Arg::from_usage("-d, --debug 'other flag'")) .arg(Arg::from_usage("-d, --debug 'other flag'"))
.arg(Arg::from_usage("-c, --color 'third flag'") .arg(Arg::from_usage("-c, --color 'third flag'").overrides_with("flag"))
.overrides_with("flag"))
.get_matches_from(vec!["", "-f", "-c", "-d"]); .get_matches_from(vec!["", "-f", "-c", "-d"]);
assert!(m.is_present("color")); assert!(m.is_present("color"));
assert!(!m.is_present("flag")); assert!(!m.is_present("flag"));
@ -110,11 +123,9 @@ fn conflict_overriden() {
#[test] #[test]
fn conflict_overriden_2() { fn conflict_overriden_2() {
let result = App::new("conflict_overriden") let result = App::new("conflict_overriden")
.arg(Arg::from_usage("-f, --flag 'some flag'") .arg(Arg::from_usage("-f, --flag 'some flag'").conflicts_with("debug"))
.conflicts_with("debug"))
.arg(Arg::from_usage("-d, --debug 'other flag'")) .arg(Arg::from_usage("-d, --debug 'other flag'"))
.arg(Arg::from_usage("-c, --color 'third flag'") .arg(Arg::from_usage("-c, --color 'third flag'").overrides_with("flag"))
.overrides_with("flag"))
.get_matches_from_safe(vec!["", "-f", "-d", "-c"]); .get_matches_from_safe(vec!["", "-f", "-d", "-c"]);
assert!(result.is_ok()); assert!(result.is_ok());
let m = result.unwrap(); let m = result.unwrap();
@ -126,11 +137,9 @@ fn conflict_overriden_2() {
#[test] #[test]
fn conflict_overriden_3() { fn conflict_overriden_3() {
let result = App::new("conflict_overriden") let result = App::new("conflict_overriden")
.arg(Arg::from_usage("-f, --flag 'some flag'") .arg(Arg::from_usage("-f, --flag 'some flag'").conflicts_with("debug"))
.conflicts_with("debug"))
.arg(Arg::from_usage("-d, --debug 'other flag'")) .arg(Arg::from_usage("-d, --debug 'other flag'"))
.arg(Arg::from_usage("-c, --color 'third flag'") .arg(Arg::from_usage("-c, --color 'third flag'").overrides_with("flag"))
.overrides_with("flag"))
.get_matches_from_safe(vec!["", "-d", "-c", "-f"]); .get_matches_from_safe(vec!["", "-d", "-c", "-f"]);
assert!(result.is_err()); assert!(result.is_err());
let err = result.err().unwrap(); let err = result.err().unwrap();
@ -140,11 +149,9 @@ fn conflict_overriden_3() {
#[test] #[test]
fn conflict_overriden_4() { fn conflict_overriden_4() {
let m = App::new("conflict_overriden") let m = App::new("conflict_overriden")
.arg(Arg::from_usage("-f, --flag 'some flag'") .arg(Arg::from_usage("-f, --flag 'some flag'").conflicts_with("debug"))
.conflicts_with("debug"))
.arg(Arg::from_usage("-d, --debug 'other flag'")) .arg(Arg::from_usage("-d, --debug 'other flag'"))
.arg(Arg::from_usage("-c, --color 'third flag'") .arg(Arg::from_usage("-c, --color 'third flag'").overrides_with("flag"))
.overrides_with("flag"))
.get_matches_from(vec!["", "-d", "-f", "-c"]); .get_matches_from(vec!["", "-d", "-f", "-c"]);
assert!(m.is_present("color")); assert!(m.is_present("color"));
assert!(!m.is_present("flag")); assert!(!m.is_present("flag"));
@ -154,11 +161,8 @@ fn conflict_overriden_4() {
#[test] #[test]
fn pos_required_overridden_by_flag() { fn pos_required_overridden_by_flag() {
let result = App::new("require_overriden") let result = App::new("require_overriden")
.arg(Arg::with_name("pos") .arg(Arg::with_name("pos").index(1).required(true))
.index(1) .arg(Arg::from_usage("-c, --color 'some flag'").overrides_with("pos"))
.required(true))
.arg(Arg::from_usage("-c, --color 'some flag'")
.overrides_with("pos"))
.get_matches_from_safe(vec!["", "test", "-c"]); .get_matches_from_safe(vec!["", "test", "-c"]);
assert!(result.is_ok(), "{:?}", result.unwrap_err()); assert!(result.is_ok(), "{:?}", result.unwrap_err());
} }
@ -166,10 +170,8 @@ fn pos_required_overridden_by_flag() {
#[test] #[test]
fn require_overriden_2() { fn require_overriden_2() {
let m = App::new("require_overriden") let m = App::new("require_overriden")
.arg(Arg::with_name("req_pos") .arg(Arg::with_name("req_pos").required(true))
.required(true)) .arg(Arg::from_usage("-c, --color 'other flag'").overrides_with("req_pos"))
.arg(Arg::from_usage("-c, --color 'other flag'")
.overrides_with("req_pos"))
.get_matches_from(vec!["", "-c", "req_pos"]); .get_matches_from(vec!["", "-c", "req_pos"]);
assert!(!m.is_present("color")); assert!(!m.is_present("color"));
assert!(m.is_present("req_pos")); assert!(m.is_present("req_pos"));
@ -178,11 +180,9 @@ fn require_overriden_2() {
#[test] #[test]
fn require_overriden_3() { fn require_overriden_3() {
let m = App::new("require_overriden") let m = App::new("require_overriden")
.arg(Arg::from_usage("-f, --flag 'some flag'") .arg(Arg::from_usage("-f, --flag 'some flag'").requires("debug"))
.requires("debug"))
.arg(Arg::from_usage("-d, --debug 'other flag'")) .arg(Arg::from_usage("-d, --debug 'other flag'"))
.arg(Arg::from_usage("-c, --color 'third flag'") .arg(Arg::from_usage("-c, --color 'third flag'").overrides_with("flag"))
.overrides_with("flag"))
.get_matches_from(vec!["", "-f", "-c"]); .get_matches_from(vec!["", "-f", "-c"]);
assert!(m.is_present("color")); assert!(m.is_present("color"));
assert!(!m.is_present("flag")); assert!(!m.is_present("flag"));
@ -192,11 +192,9 @@ fn require_overriden_3() {
#[test] #[test]
fn require_overriden_4() { fn require_overriden_4() {
let result = App::new("require_overriden") let result = App::new("require_overriden")
.arg(Arg::from_usage("-f, --flag 'some flag'") .arg(Arg::from_usage("-f, --flag 'some flag'").requires("debug"))
.requires("debug"))
.arg(Arg::from_usage("-d, --debug 'other flag'")) .arg(Arg::from_usage("-d, --debug 'other flag'"))
.arg(Arg::from_usage("-c, --color 'third flag'") .arg(Arg::from_usage("-c, --color 'third flag'").overrides_with("flag"))
.overrides_with("flag"))
.get_matches_from_safe(vec!["", "-c", "-f"]); .get_matches_from_safe(vec!["", "-c", "-f"]);
assert!(result.is_err()); assert!(result.is_err());
let err = result.err().unwrap(); let err = result.err().unwrap();

View file

@ -4,27 +4,26 @@ extern crate regex;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
include!("../clap-test.rs"); include!("../clap-test.rs");
use clap::{App, Arg, SubCommand, ArgMatches}; use clap::{App, Arg, ArgMatches, SubCommand};
fn get_app() -> App<'static, 'static> { fn get_app() -> App<'static, 'static> {
App::new("myprog") App::new("myprog")
.arg(Arg::with_name("GLOBAL_ARG") .arg(
.long("global-arg") Arg::with_name("GLOBAL_ARG")
.help( .long("global-arg")
"Specifies something needed by the subcommands", .help("Specifies something needed by the subcommands")
) .global(true)
.global(true) .takes_value(true)
.takes_value(true) .default_value("default_value"),
.default_value("default_value")) )
.arg(Arg::with_name("GLOBAL_FLAG") .arg(
.long("global-flag") Arg::with_name("GLOBAL_FLAG")
.help( .long("global-flag")
"Specifies something needed by the subcommands", .help("Specifies something needed by the subcommands")
) .multiple(true)
.multiple(true) .global(true),
.global(true)) )
.subcommand(SubCommand::with_name("outer") .subcommand(SubCommand::with_name("outer").subcommand(SubCommand::with_name("inner")))
.subcommand(SubCommand::with_name("inner")))
} }
fn get_matches(app: App<'static, 'static>, argv: &'static str) -> ArgMatches<'static> { fn get_matches(app: App<'static, 'static>, argv: &'static str) -> ArgMatches<'static> {
@ -32,22 +31,31 @@ mod tests {
} }
fn get_outer_matches<'a>(m: &'a ArgMatches<'static>) -> &'a ArgMatches<'static> { fn get_outer_matches<'a>(m: &'a ArgMatches<'static>) -> &'a ArgMatches<'static> {
m.subcommand_matches("outer").expect("could not access outer subcommand") m.subcommand_matches("outer")
.expect("could not access outer subcommand")
} }
fn get_inner_matches<'a>(m: &'a ArgMatches<'static>) -> &'a ArgMatches<'static> { fn get_inner_matches<'a>(m: &'a ArgMatches<'static>) -> &'a ArgMatches<'static> {
get_outer_matches(m).subcommand_matches("inner").expect("could not access inner subcommand") get_outer_matches(m)
.subcommand_matches("inner")
.expect("could not access inner subcommand")
} }
fn top_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches<'static>, val: T) -> bool { fn top_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches<'static>, val: T) -> bool {
m.value_of("GLOBAL_ARG") == val.into() m.value_of("GLOBAL_ARG") == val.into()
} }
fn inner_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches<'static>, val: T) -> bool { fn inner_can_access_arg<T: Into<Option<&'static str>>>(
m: &ArgMatches<'static>,
val: T,
) -> bool {
get_inner_matches(m).value_of("GLOBAL_ARG") == val.into() get_inner_matches(m).value_of("GLOBAL_ARG") == val.into()
} }
fn outer_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches<'static>, val: T) -> bool { fn outer_can_access_arg<T: Into<Option<&'static str>>>(
m: &ArgMatches<'static>,
val: T,
) -> bool {
get_outer_matches(m).value_of("GLOBAL_ARG") == val.into() get_outer_matches(m).value_of("GLOBAL_ARG") == val.into()
} }

View file

@ -3,7 +3,7 @@ extern crate regex;
include!("../clap-test.rs"); include!("../clap-test.rs");
use clap::{App, Arg, ErrorKind, ArgGroup}; use clap::{App, Arg, ArgGroup, ErrorKind};
static REQUIRE_EQUALS: &'static str = "error: The following required arguments were not provided: static REQUIRE_EQUALS: &'static str = "error: The following required arguments were not provided:
--opt=<FILE> --opt=<FILE>
@ -22,7 +22,8 @@ USAGE:
For more information try --help"; For more information try --help";
static COND_REQ_IN_USAGE: &'static str = "error: The following required arguments were not provided: static COND_REQ_IN_USAGE: &'static str =
"error: The following required arguments were not provided:
--output <output> --output <output>
USAGE: USAGE:
@ -77,9 +78,7 @@ fn option_required_2() {
#[test] #[test]
fn positional_required() { fn positional_required() {
let result = App::new("positional_required") let result = App::new("positional_required")
.arg(Arg::with_name("flag") .arg(Arg::with_name("flag").index(1).required(true))
.index(1)
.required(true))
.get_matches_from_safe(vec![""]); .get_matches_from_safe(vec![""]);
assert!(result.is_err()); assert!(result.is_err());
let err = result.err().unwrap(); let err = result.err().unwrap();
@ -89,9 +88,7 @@ fn positional_required() {
#[test] #[test]
fn positional_required_2() { fn positional_required_2() {
let m = App::new("positional_required") let m = App::new("positional_required")
.arg(Arg::with_name("flag") .arg(Arg::with_name("flag").index(1).required(true))
.index(1)
.required(true))
.get_matches_from(vec!["", "someval"]); .get_matches_from(vec!["", "someval"]);
assert!(m.is_present("flag")); assert!(m.is_present("flag"));
assert_eq!(m.value_of("flag").unwrap(), "someval"); assert_eq!(m.value_of("flag").unwrap(), "someval");
@ -101,10 +98,12 @@ fn positional_required_2() {
fn group_required() { fn group_required() {
let result = App::new("group_required") let result = App::new("group_required")
.arg(Arg::from_usage("-f, --flag 'some flag'")) .arg(Arg::from_usage("-f, --flag 'some flag'"))
.group(ArgGroup::with_name("gr") .group(
.required(true) ArgGroup::with_name("gr")
.arg("some") .required(true)
.arg("other")) .arg("some")
.arg("other"),
)
.arg(Arg::from_usage("--some 'some arg'")) .arg(Arg::from_usage("--some 'some arg'"))
.arg(Arg::from_usage("--other 'other arg'")) .arg(Arg::from_usage("--other 'other arg'"))
.get_matches_from_safe(vec!["", "-f"]); .get_matches_from_safe(vec!["", "-f"]);
@ -117,10 +116,12 @@ fn group_required() {
fn group_required_2() { fn group_required_2() {
let m = App::new("group_required") let m = App::new("group_required")
.arg(Arg::from_usage("-f, --flag 'some flag'")) .arg(Arg::from_usage("-f, --flag 'some flag'"))
.group(ArgGroup::with_name("gr") .group(
.required(true) ArgGroup::with_name("gr")
.arg("some") .required(true)
.arg("other")) .arg("some")
.arg("other"),
)
.arg(Arg::from_usage("--some 'some arg'")) .arg(Arg::from_usage("--some 'some arg'"))
.arg(Arg::from_usage("--other 'other arg'")) .arg(Arg::from_usage("--other 'other arg'"))
.get_matches_from(vec!["", "-f", "--some"]); .get_matches_from(vec!["", "-f", "--some"]);
@ -133,10 +134,12 @@ fn group_required_2() {
fn group_required_3() { fn group_required_3() {
let m = App::new("group_required") let m = App::new("group_required")
.arg(Arg::from_usage("-f, --flag 'some flag'")) .arg(Arg::from_usage("-f, --flag 'some flag'"))
.group(ArgGroup::with_name("gr") .group(
.required(true) ArgGroup::with_name("gr")
.arg("some") .required(true)
.arg("other")) .arg("some")
.arg("other"),
)
.arg(Arg::from_usage("--some 'some arg'")) .arg(Arg::from_usage("--some 'some arg'"))
.arg(Arg::from_usage("--other 'other arg'")) .arg(Arg::from_usage("--other 'other arg'"))
.get_matches_from(vec!["", "-f", "--other"]); .get_matches_from(vec!["", "-f", "--other"]);
@ -149,9 +152,7 @@ fn group_required_3() {
fn arg_require_group() { fn arg_require_group() {
let result = App::new("arg_require_group") let result = App::new("arg_require_group")
.arg(Arg::from_usage("-f, --flag 'some flag'").requires("gr")) .arg(Arg::from_usage("-f, --flag 'some flag'").requires("gr"))
.group(ArgGroup::with_name("gr") .group(ArgGroup::with_name("gr").arg("some").arg("other"))
.arg("some")
.arg("other"))
.arg(Arg::from_usage("--some 'some arg'")) .arg(Arg::from_usage("--some 'some arg'"))
.arg(Arg::from_usage("--other 'other arg'")) .arg(Arg::from_usage("--other 'other arg'"))
.get_matches_from_safe(vec!["", "-f"]); .get_matches_from_safe(vec!["", "-f"]);
@ -164,9 +165,7 @@ fn arg_require_group() {
fn arg_require_group_2() { fn arg_require_group_2() {
let m = App::new("arg_require_group") let m = App::new("arg_require_group")
.arg(Arg::from_usage("-f, --flag 'some flag'").requires("gr")) .arg(Arg::from_usage("-f, --flag 'some flag'").requires("gr"))
.group(ArgGroup::with_name("gr") .group(ArgGroup::with_name("gr").arg("some").arg("other"))
.arg("some")
.arg("other"))
.arg(Arg::from_usage("--some 'some arg'")) .arg(Arg::from_usage("--some 'some arg'"))
.arg(Arg::from_usage("--other 'other arg'")) .arg(Arg::from_usage("--other 'other arg'"))
.get_matches_from(vec!["", "-f", "--some"]); .get_matches_from(vec!["", "-f", "--some"]);
@ -179,9 +178,7 @@ fn arg_require_group_2() {
fn arg_require_group_3() { fn arg_require_group_3() {
let m = App::new("arg_require_group") let m = App::new("arg_require_group")
.arg(Arg::from_usage("-f, --flag 'some flag'").requires("gr")) .arg(Arg::from_usage("-f, --flag 'some flag'").requires("gr"))
.group(ArgGroup::with_name("gr") .group(ArgGroup::with_name("gr").arg("some").arg("other"))
.arg("some")
.arg("other"))
.arg(Arg::from_usage("--some 'some arg'")) .arg(Arg::from_usage("--some 'some arg'"))
.arg(Arg::from_usage("--other 'other arg'")) .arg(Arg::from_usage("--other 'other arg'"))
.get_matches_from(vec!["", "-f", "--other"]); .get_matches_from(vec!["", "-f", "--other"]);
@ -195,16 +192,24 @@ fn arg_require_group_3() {
#[test] #[test]
fn issue_753() { fn issue_753() {
let m = App::new("test") let m = App::new("test")
.arg(Arg::from_usage("-l, --list 'List available interfaces (and stop there)'")) .arg(Arg::from_usage(
.arg(Arg::from_usage("-i, --iface=[INTERFACE] 'Ethernet interface for fetching NTP packets'") "-l, --list 'List available interfaces (and stop there)'",
.required_unless("list")) ))
.arg(Arg::from_usage("-f, --file=[TESTFILE] 'Fetch NTP packets from pcap file'") .arg(
.conflicts_with("iface") Arg::from_usage(
.required_unless("list")) "-i, --iface=[INTERFACE] 'Ethernet interface for fetching NTP packets'",
.arg(Arg::from_usage("-s, --server=[SERVER_IP] 'NTP server IP address'") ).required_unless("list"),
.required_unless("list")) )
.arg(Arg::from_usage("-p, --port=[SERVER_PORT] 'NTP server port'") .arg(
.default_value("123")) Arg::from_usage("-f, --file=[TESTFILE] 'Fetch NTP packets from pcap file'")
.conflicts_with("iface")
.required_unless("list"),
)
.arg(
Arg::from_usage("-s, --server=[SERVER_IP] 'NTP server IP address'")
.required_unless("list"),
)
.arg(Arg::from_usage("-p, --port=[SERVER_PORT] 'NTP server port'").default_value("123"))
.get_matches_from_safe(vec!["test", "--list"]); .get_matches_from_safe(vec!["test", "--list"]);
assert!(m.is_ok()); assert!(m.is_ok());
} }
@ -212,10 +217,12 @@ fn issue_753() {
#[test] #[test]
fn required_unless() { fn required_unless() {
let res = App::new("unlesstest") let res = App::new("unlesstest")
.arg(Arg::with_name("cfg") .arg(
.required_unless("dbg") Arg::with_name("cfg")
.takes_value(true) .required_unless("dbg")
.long("config")) .takes_value(true)
.long("config"),
)
.arg(Arg::with_name("dbg").long("debug")) .arg(Arg::with_name("dbg").long("debug"))
.get_matches_from_safe(vec!["unlesstest", "--debug"]); .get_matches_from_safe(vec!["unlesstest", "--debug"]);
@ -228,10 +235,12 @@ fn required_unless() {
#[test] #[test]
fn required_unless_err() { fn required_unless_err() {
let res = App::new("unlesstest") let res = App::new("unlesstest")
.arg(Arg::with_name("cfg") .arg(
.required_unless("dbg") Arg::with_name("cfg")
.takes_value(true) .required_unless("dbg")
.long("config")) .takes_value(true)
.long("config"),
)
.arg(Arg::with_name("dbg").long("debug")) .arg(Arg::with_name("dbg").long("debug"))
.get_matches_from_safe(vec!["unlesstest"]); .get_matches_from_safe(vec!["unlesstest"]);
@ -244,14 +253,14 @@ fn required_unless_err() {
#[test] #[test]
fn required_unless_all() { fn required_unless_all() {
let res = App::new("unlessall") let res = App::new("unlessall")
.arg(Arg::with_name("cfg") .arg(
.required_unless_all(&["dbg", "infile"]) Arg::with_name("cfg")
.takes_value(true) .required_unless_all(&["dbg", "infile"])
.long("config")) .takes_value(true)
.long("config"),
)
.arg(Arg::with_name("dbg").long("debug")) .arg(Arg::with_name("dbg").long("debug"))
.arg(Arg::with_name("infile") .arg(Arg::with_name("infile").short("i").takes_value(true))
.short("i")
.takes_value(true))
.get_matches_from_safe(vec!["unlessall", "--debug", "-i", "file"]); .get_matches_from_safe(vec!["unlessall", "--debug", "-i", "file"]);
assert!(res.is_ok()); assert!(res.is_ok());
@ -264,14 +273,14 @@ fn required_unless_all() {
#[test] #[test]
fn required_unless_all_err() { fn required_unless_all_err() {
let res = App::new("unlessall") let res = App::new("unlessall")
.arg(Arg::with_name("cfg") .arg(
.required_unless_all(&["dbg", "infile"]) Arg::with_name("cfg")
.takes_value(true) .required_unless_all(&["dbg", "infile"])
.long("config")) .takes_value(true)
.long("config"),
)
.arg(Arg::with_name("dbg").long("debug")) .arg(Arg::with_name("dbg").long("debug"))
.arg(Arg::with_name("infile") .arg(Arg::with_name("infile").short("i").takes_value(true))
.short("i")
.takes_value(true))
.get_matches_from_safe(vec!["unlessall", "--debug"]); .get_matches_from_safe(vec!["unlessall", "--debug"]);
assert!(res.is_err()); assert!(res.is_err());
@ -283,14 +292,14 @@ fn required_unless_all_err() {
#[test] #[test]
fn required_unless_one() { fn required_unless_one() {
let res = App::new("unlessone") let res = App::new("unlessone")
.arg(Arg::with_name("cfg") .arg(
.required_unless_one(&["dbg", "infile"]) Arg::with_name("cfg")
.takes_value(true) .required_unless_one(&["dbg", "infile"])
.long("config")) .takes_value(true)
.long("config"),
)
.arg(Arg::with_name("dbg").long("debug")) .arg(Arg::with_name("dbg").long("debug"))
.arg(Arg::with_name("infile") .arg(Arg::with_name("infile").short("i").takes_value(true))
.short("i")
.takes_value(true))
.get_matches_from_safe(vec!["unlessone", "--debug"]); .get_matches_from_safe(vec!["unlessone", "--debug"]);
assert!(res.is_ok()); assert!(res.is_ok());
@ -304,14 +313,14 @@ fn required_unless_one_2() {
// This tests that the required_unless_one works when the second arg in the array is used // This tests that the required_unless_one works when the second arg in the array is used
// instead of the first. // instead of the first.
let res = App::new("unlessone") let res = App::new("unlessone")
.arg(Arg::with_name("cfg") .arg(
.required_unless_one(&["dbg", "infile"]) Arg::with_name("cfg")
.takes_value(true) .required_unless_one(&["dbg", "infile"])
.long("config")) .takes_value(true)
.long("config"),
)
.arg(Arg::with_name("dbg").long("debug")) .arg(Arg::with_name("dbg").long("debug"))
.arg(Arg::with_name("infile") .arg(Arg::with_name("infile").short("i").takes_value(true))
.short("i")
.takes_value(true))
.get_matches_from_safe(vec!["unlessone", "-i", "file"]); .get_matches_from_safe(vec!["unlessone", "-i", "file"]);
assert!(res.is_ok()); assert!(res.is_ok());
@ -329,8 +338,9 @@ fn required_unless_one_works_with_short() {
.arg( .arg(
Arg::with_name("x") Arg::with_name("x")
.short("x") .short("x")
.required_unless_one(&["a", "b"]) .required_unless_one(&["a", "b"]),
).get_matches_from_safe(vec!["unlessone", "-a"]); )
.get_matches_from_safe(vec!["unlessone", "-a"]);
assert!(res.is_ok()); assert!(res.is_ok());
} }
@ -343,8 +353,9 @@ fn required_unless_one_works_with_short_err() {
.arg( .arg(
Arg::with_name("x") Arg::with_name("x")
.short("x") .short("x")
.required_unless_one(&["a", "b"]) .required_unless_one(&["a", "b"]),
).get_matches_from_safe(vec!["unlessone"]); )
.get_matches_from_safe(vec!["unlessone"]);
assert!(!res.is_ok()); assert!(!res.is_ok());
} }
@ -354,10 +365,8 @@ fn required_unless_one_works_without() {
let res = App::new("unlessone") let res = App::new("unlessone")
.arg(Arg::with_name("a").conflicts_with("b").short("a")) .arg(Arg::with_name("a").conflicts_with("b").short("a"))
.arg(Arg::with_name("b").short("b")) .arg(Arg::with_name("b").short("b"))
.arg( .arg(Arg::with_name("x").required_unless_one(&["a", "b"]))
Arg::with_name("x") .get_matches_from_safe(vec!["unlessone", "-a"]);
.required_unless_one(&["a", "b"])
).get_matches_from_safe(vec!["unlessone", "-a"]);
assert!(res.is_ok()); assert!(res.is_ok());
} }
@ -370,8 +379,9 @@ fn required_unless_one_works_with_long() {
.arg( .arg(
Arg::with_name("x") Arg::with_name("x")
.long("x_is_the_option") .long("x_is_the_option")
.required_unless_one(&["a", "b"]) .required_unless_one(&["a", "b"]),
).get_matches_from_safe(vec!["unlessone", "-a"]); )
.get_matches_from_safe(vec!["unlessone", "-a"]);
assert!(res.is_ok()); assert!(res.is_ok());
} }
@ -379,14 +389,14 @@ fn required_unless_one_works_with_long() {
#[test] #[test]
fn required_unless_one_1() { fn required_unless_one_1() {
let res = App::new("unlessone") let res = App::new("unlessone")
.arg(Arg::with_name("cfg") .arg(
.required_unless_one(&["dbg", "infile"]) Arg::with_name("cfg")
.takes_value(true) .required_unless_one(&["dbg", "infile"])
.long("config")) .takes_value(true)
.long("config"),
)
.arg(Arg::with_name("dbg").long("debug")) .arg(Arg::with_name("dbg").long("debug"))
.arg(Arg::with_name("infile") .arg(Arg::with_name("infile").short("i").takes_value(true))
.short("i")
.takes_value(true))
.get_matches_from_safe(vec!["unlessone", "--debug"]); .get_matches_from_safe(vec!["unlessone", "--debug"]);
assert!(res.is_ok()); assert!(res.is_ok());
@ -399,14 +409,14 @@ fn required_unless_one_1() {
#[test] #[test]
fn required_unless_one_err() { fn required_unless_one_err() {
let res = App::new("unlessone") let res = App::new("unlessone")
.arg(Arg::with_name("cfg") .arg(
.required_unless_one(&["dbg", "infile"]) Arg::with_name("cfg")
.takes_value(true) .required_unless_one(&["dbg", "infile"])
.long("config")) .takes_value(true)
.long("config"),
)
.arg(Arg::with_name("dbg").long("debug")) .arg(Arg::with_name("dbg").long("debug"))
.arg(Arg::with_name("infile") .arg(Arg::with_name("infile").short("i").takes_value(true))
.short("i")
.takes_value(true))
.get_matches_from_safe(vec!["unlessone"]); .get_matches_from_safe(vec!["unlessone"]);
assert!(res.is_err()); assert!(res.is_err());
@ -415,7 +425,12 @@ fn required_unless_one_err() {
#[test] #[test]
fn missing_required_output() { fn missing_required_output() {
assert!(test::compare_output(test::complex_app(), "clap-test -F", MISSING_REQ, true)); assert!(test::compare_output(
test::complex_app(),
"clap-test -F",
MISSING_REQ,
true
));
} }
// Conditional external requirements // Conditional external requirements
@ -423,10 +438,12 @@ fn missing_required_output() {
#[test] #[test]
fn requires_if_present_val() { fn requires_if_present_val() {
let res = App::new("unlessone") let res = App::new("unlessone")
.arg(Arg::with_name("cfg") .arg(
.requires_if("my.cfg", "extra") Arg::with_name("cfg")
.takes_value(true) .requires_if("my.cfg", "extra")
.long("config")) .takes_value(true)
.long("config"),
)
.arg(Arg::with_name("extra").long("extra")) .arg(Arg::with_name("extra").long("extra"))
.get_matches_from_safe(vec!["unlessone", "--config=my.cfg"]); .get_matches_from_safe(vec!["unlessone", "--config=my.cfg"]);
@ -437,10 +454,12 @@ fn requires_if_present_val() {
#[test] #[test]
fn requires_if_present_mult() { fn requires_if_present_mult() {
let res = App::new("unlessone") let res = App::new("unlessone")
.arg(Arg::with_name("cfg") .arg(
.requires_ifs(&[("my.cfg", "extra"), ("other.cfg", "other")]) Arg::with_name("cfg")
.takes_value(true) .requires_ifs(&[("my.cfg", "extra"), ("other.cfg", "other")])
.long("config")) .takes_value(true)
.long("config"),
)
.arg(Arg::with_name("extra").long("extra")) .arg(Arg::with_name("extra").long("extra"))
.arg(Arg::with_name("other").long("other")) .arg(Arg::with_name("other").long("other"))
.get_matches_from_safe(vec!["unlessone", "--config=other.cfg"]); .get_matches_from_safe(vec!["unlessone", "--config=other.cfg"]);
@ -452,10 +471,12 @@ fn requires_if_present_mult() {
#[test] #[test]
fn requires_if_present_mult_pass() { fn requires_if_present_mult_pass() {
let res = App::new("unlessone") let res = App::new("unlessone")
.arg(Arg::with_name("cfg") .arg(
.requires_ifs(&[("my.cfg", "extra"), ("other.cfg", "other")]) Arg::with_name("cfg")
.takes_value(true) .requires_ifs(&[("my.cfg", "extra"), ("other.cfg", "other")])
.long("config")) .takes_value(true)
.long("config"),
)
.arg(Arg::with_name("extra").long("extra")) .arg(Arg::with_name("extra").long("extra"))
.arg(Arg::with_name("other").long("other")) .arg(Arg::with_name("other").long("other"))
.get_matches_from_safe(vec!["unlessone", "--config=some.cfg"]); .get_matches_from_safe(vec!["unlessone", "--config=some.cfg"]);
@ -467,10 +488,12 @@ fn requires_if_present_mult_pass() {
#[test] #[test]
fn requires_if_present_val_no_present_pass() { fn requires_if_present_val_no_present_pass() {
let res = App::new("unlessone") let res = App::new("unlessone")
.arg(Arg::with_name("cfg") .arg(
.requires_if("my.cfg", "extra") Arg::with_name("cfg")
.takes_value(true) .requires_if("my.cfg", "extra")
.long("config")) .takes_value(true)
.long("config"),
)
.arg(Arg::with_name("extra").long("extra")) .arg(Arg::with_name("extra").long("extra"))
.get_matches_from_safe(vec!["unlessone"]); .get_matches_from_safe(vec!["unlessone"]);
@ -482,13 +505,13 @@ fn requires_if_present_val_no_present_pass() {
#[test] #[test]
fn required_if_val_present_pass() { fn required_if_val_present_pass() {
let res = App::new("ri") let res = App::new("ri")
.arg(Arg::with_name("cfg") .arg(
.required_if("extra", "val") Arg::with_name("cfg")
.takes_value(true) .required_if("extra", "val")
.long("config")) .takes_value(true)
.arg(Arg::with_name("extra") .long("config"),
.takes_value(true) )
.long("extra")) .arg(Arg::with_name("extra").takes_value(true).long("extra"))
.get_matches_from_safe(vec!["ri", "--extra", "val", "--config", "my.cfg"]); .get_matches_from_safe(vec!["ri", "--extra", "val", "--config", "my.cfg"]);
assert!(res.is_ok()); assert!(res.is_ok());
@ -497,13 +520,13 @@ fn required_if_val_present_pass() {
#[test] #[test]
fn required_if_val_present_fail() { fn required_if_val_present_fail() {
let res = App::new("ri") let res = App::new("ri")
.arg(Arg::with_name("cfg") .arg(
.required_if("extra", "val") Arg::with_name("cfg")
.takes_value(true) .required_if("extra", "val")
.long("config")) .takes_value(true)
.arg(Arg::with_name("extra") .long("config"),
.takes_value(true) )
.long("extra")) .arg(Arg::with_name("extra").takes_value(true).long("extra"))
.get_matches_from_safe(vec!["ri", "--extra", "val"]); .get_matches_from_safe(vec!["ri", "--extra", "val"]);
assert!(res.is_err()); assert!(res.is_err());
@ -516,36 +539,44 @@ fn required_if_val_present_fail_error_output() {
.version("1.0") .version("1.0")
.author("F0x06") .author("F0x06")
.about("Arg test") .about("Arg test")
.arg(Arg::with_name("target") .arg(
.takes_value(true) Arg::with_name("target")
.required(true) .takes_value(true)
.possible_values(&["file", "stdout"]) .required(true)
.long("target")) .possible_values(&["file", "stdout"])
.arg(Arg::with_name("input") .long("target"),
.takes_value(true) )
.required(true) .arg(
.long("input")) Arg::with_name("input")
.arg(Arg::with_name("output") .takes_value(true)
.takes_value(true) .required(true)
.required_if("target", "file") .long("input"),
.long("output")); )
.arg(
Arg::with_name("output")
.takes_value(true)
.required_if("target", "file")
.long("output"),
);
assert!(test::compare_output(app, assert!(test::compare_output(
"test --input somepath --target file", app,
COND_REQ_IN_USAGE, "test --input somepath --target file",
true)); COND_REQ_IN_USAGE,
true
));
} }
#[test] #[test]
fn required_if_wrong_val() { fn required_if_wrong_val() {
let res = App::new("ri") let res = App::new("ri")
.arg(Arg::with_name("cfg") .arg(
.required_if("extra", "val") Arg::with_name("cfg")
.takes_value(true) .required_if("extra", "val")
.long("config")) .takes_value(true)
.arg(Arg::with_name("extra") .long("config"),
.takes_value(true) )
.long("extra")) .arg(Arg::with_name("extra").takes_value(true).long("extra"))
.get_matches_from_safe(vec!["ri", "--extra", "other"]); .get_matches_from_safe(vec!["ri", "--extra", "other"]);
assert!(res.is_ok()); assert!(res.is_ok());
@ -554,16 +585,14 @@ fn required_if_wrong_val() {
#[test] #[test]
fn required_ifs_val_present_pass() { fn required_ifs_val_present_pass() {
let res = App::new("ri") let res = App::new("ri")
.arg(Arg::with_name("cfg") .arg(
.required_ifs(&[("extra", "val"), ("option", "spec")]) Arg::with_name("cfg")
.takes_value(true) .required_ifs(&[("extra", "val"), ("option", "spec")])
.long("config")) .takes_value(true)
.arg(Arg::with_name("option") .long("config"),
.takes_value(true) )
.long("option")) .arg(Arg::with_name("option").takes_value(true).long("option"))
.arg(Arg::with_name("extra") .arg(Arg::with_name("extra").takes_value(true).long("extra"))
.takes_value(true)
.long("extra"))
.get_matches_from_safe(vec!["ri", "--option", "spec", "--config", "my.cfg"]); .get_matches_from_safe(vec!["ri", "--option", "spec", "--config", "my.cfg"]);
assert!(res.is_ok()); assert!(res.is_ok());
@ -573,16 +602,14 @@ fn required_ifs_val_present_pass() {
#[test] #[test]
fn required_ifs_val_present_fail() { fn required_ifs_val_present_fail() {
let res = App::new("ri") let res = App::new("ri")
.arg(Arg::with_name("cfg") .arg(
.required_ifs(&[("extra", "val"), ("option", "spec")]) Arg::with_name("cfg")
.takes_value(true) .required_ifs(&[("extra", "val"), ("option", "spec")])
.long("config")) .takes_value(true)
.arg(Arg::with_name("extra") .long("config"),
.takes_value(true) )
.long("extra")) .arg(Arg::with_name("extra").takes_value(true).long("extra"))
.arg(Arg::with_name("option") .arg(Arg::with_name("option").takes_value(true).long("option"))
.takes_value(true)
.long("option"))
.get_matches_from_safe(vec!["ri", "--option", "spec"]); .get_matches_from_safe(vec!["ri", "--option", "spec"]);
assert!(res.is_err()); assert!(res.is_err());
@ -592,16 +619,14 @@ fn required_ifs_val_present_fail() {
#[test] #[test]
fn required_ifs_wrong_val() { fn required_ifs_wrong_val() {
let res = App::new("ri") let res = App::new("ri")
.arg(Arg::with_name("cfg") .arg(
.required_ifs(&[("extra", "val"), ("option", "spec")]) Arg::with_name("cfg")
.takes_value(true) .required_ifs(&[("extra", "val"), ("option", "spec")])
.long("config")) .takes_value(true)
.arg(Arg::with_name("extra") .long("config"),
.takes_value(true) )
.long("extra")) .arg(Arg::with_name("extra").takes_value(true).long("extra"))
.arg(Arg::with_name("option") .arg(Arg::with_name("option").takes_value(true).long("option"))
.takes_value(true)
.long("option"))
.get_matches_from_safe(vec!["ri", "--option", "other"]); .get_matches_from_safe(vec!["ri", "--option", "other"]);
assert!(res.is_ok()); assert!(res.is_ok());
@ -610,16 +635,14 @@ fn required_ifs_wrong_val() {
#[test] #[test]
fn required_ifs_wrong_val_mult_fail() { fn required_ifs_wrong_val_mult_fail() {
let res = App::new("ri") let res = App::new("ri")
.arg(Arg::with_name("cfg") .arg(
.required_ifs(&[("extra", "val"), ("option", "spec")]) Arg::with_name("cfg")
.takes_value(true) .required_ifs(&[("extra", "val"), ("option", "spec")])
.long("config")) .takes_value(true)
.arg(Arg::with_name("extra") .long("config"),
.takes_value(true) )
.long("extra")) .arg(Arg::with_name("extra").takes_value(true).long("extra"))
.arg(Arg::with_name("option") .arg(Arg::with_name("option").takes_value(true).long("option"))
.takes_value(true)
.long("option"))
.get_matches_from_safe(vec!["ri", "--extra", "other", "--option", "spec"]); .get_matches_from_safe(vec!["ri", "--extra", "other", "--option", "spec"]);
assert!(res.is_err()); assert!(res.is_err());
@ -628,16 +651,14 @@ fn required_ifs_wrong_val_mult_fail() {
#[test] #[test]
fn require_eq() { fn require_eq() {
let app = App::new("clap-test") let app = App::new("clap-test").version("v1.4.8").arg(
.version("v1.4.8") Arg::with_name("opt")
.arg(
Arg::with_name("opt")
.long("opt") .long("opt")
.short("o") .short("o")
.required(true) .required(true)
.require_equals(true) .require_equals(true)
.value_name("FILE") .value_name("FILE")
.help("some") .help("some"),
); );
assert!(test::compare_output(app, "clap-test", REQUIRE_EQUALS, true)); assert!(test::compare_output(app, "clap-test", REQUIRE_EQUALS, true));
} }

View file

@ -3,7 +3,7 @@ extern crate regex;
include!("../clap-test.rs"); include!("../clap-test.rs");
use clap::{App, Arg, SubCommand, ErrorKind}; use clap::{App, Arg, ErrorKind, SubCommand};
static VISIBLE_ALIAS_HELP: &'static str = "clap-test 2.6 static VISIBLE_ALIAS_HELP: &'static str = "clap-test 2.6
@ -43,7 +43,8 @@ USAGE:
For more information try --help"; For more information try --help";
#[cfg(feature = "suggestions")] #[cfg(feature = "suggestions")]
static DYM_ARG: &'static str = "error: Found argument '--subcm' which wasn't expected, or isn't valid in this context static DYM_ARG: &'static str =
"error: Found argument '--subcm' which wasn't expected, or isn't valid in this context
\tDid you mean to put '--subcmdarg' after the subcommand 'subcmd'? \tDid you mean to put '--subcmdarg' after the subcommand 'subcmd'?
USAGE: USAGE:
@ -54,12 +55,15 @@ For more information try --help";
#[test] #[test]
fn subcommand() { fn subcommand() {
let m = App::new("test") let m = App::new("test")
.subcommand(SubCommand::with_name("some") .subcommand(
.arg(Arg::with_name("test") SubCommand::with_name("some").arg(
.short("t") Arg::with_name("test")
.long("test") .short("t")
.takes_value(true) .long("test")
.help("testing testing"))) .takes_value(true)
.help("testing testing"),
),
)
.arg(Arg::with_name("other").long("other")) .arg(Arg::with_name("other").long("other"))
.get_matches_from(vec!["myprog", "some", "--test", "testing"]); .get_matches_from(vec!["myprog", "some", "--test", "testing"]);
@ -72,12 +76,15 @@ fn subcommand() {
#[test] #[test]
fn subcommand_none_given() { fn subcommand_none_given() {
let m = App::new("test") let m = App::new("test")
.subcommand(SubCommand::with_name("some") .subcommand(
.arg(Arg::with_name("test") SubCommand::with_name("some").arg(
.short("t") Arg::with_name("test")
.long("test") .short("t")
.takes_value(true) .long("test")
.help("testing testing"))) .takes_value(true)
.help("testing testing"),
),
)
.arg(Arg::with_name("other").long("other")) .arg(Arg::with_name("other").long("other"))
.get_matches_from(vec![""]); .get_matches_from(vec![""]);
@ -88,14 +95,14 @@ fn subcommand_none_given() {
fn subcommand_multiple() { fn subcommand_multiple() {
let m = App::new("test") let m = App::new("test")
.subcommands(vec![ .subcommands(vec![
SubCommand::with_name("some") SubCommand::with_name("some").arg(
.arg(Arg::with_name("test") Arg::with_name("test")
.short("t") .short("t")
.long("test") .long("test")
.takes_value(true) .takes_value(true)
.help("testing testing")), .help("testing testing"),
SubCommand::with_name("add") ),
.arg(Arg::with_name("roster").short("r")) SubCommand::with_name("add").arg(Arg::with_name("roster").short("r")),
]) ])
.arg(Arg::with_name("other").long("other")) .arg(Arg::with_name("other").long("other"))
.get_matches_from(vec!["myprog", "some", "--test", "testing"]); .get_matches_from(vec!["myprog", "some", "--test", "testing"]);
@ -111,68 +118,74 @@ fn subcommand_multiple() {
#[test] #[test]
fn single_alias() { fn single_alias() {
let m = App::new("myprog") let m = App::new("myprog")
.subcommand(SubCommand::with_name("test") .subcommand(SubCommand::with_name("test").alias("do-stuff"))
.alias("do-stuff")) .get_matches_from(vec!["myprog", "do-stuff"]);
.get_matches_from(vec!["myprog", "do-stuff"]);
assert_eq!(m.subcommand_name(), Some("test")); assert_eq!(m.subcommand_name(), Some("test"));
} }
#[test] #[test]
fn multiple_aliases() { fn multiple_aliases() {
let m = App::new("myprog") let m = App::new("myprog")
.subcommand(SubCommand::with_name("test") .subcommand(SubCommand::with_name("test").aliases(&["do-stuff", "test-stuff"]))
.aliases(&["do-stuff", "test-stuff"])) .get_matches_from(vec!["myprog", "test-stuff"]);
.get_matches_from(vec!["myprog", "test-stuff"]);
assert_eq!(m.subcommand_name(), Some("test")); assert_eq!(m.subcommand_name(), Some("test"));
} }
#[test] #[test]
#[cfg(feature="suggestions")] #[cfg(feature = "suggestions")]
fn subcmd_did_you_mean_output() { fn subcmd_did_you_mean_output() {
let app = App::new("dym") let app = App::new("dym").subcommand(SubCommand::with_name("subcmd"));
.subcommand(SubCommand::with_name("subcmd"));
assert!(test::compare_output(app, "dym subcm", DYM_SUBCMD, true)); assert!(test::compare_output(app, "dym subcm", DYM_SUBCMD, true));
} }
#[test] #[test]
#[cfg(feature="suggestions")] #[cfg(feature = "suggestions")]
fn subcmd_did_you_mean_output_arg() { fn subcmd_did_you_mean_output_arg() {
let app = App::new("dym") let app = App::new("dym").subcommand(
.subcommand(SubCommand::with_name("subcmd") SubCommand::with_name("subcmd").arg_from_usage("-s --subcmdarg [subcmdarg] 'tests'"),
.arg_from_usage("-s --subcmdarg [subcmdarg] 'tests'") ); );
assert!(test::compare_output(app, "dym --subcm foo", DYM_ARG, true)); assert!(test::compare_output(app, "dym --subcm foo", DYM_ARG, true));
} }
#[test] #[test]
fn alias_help() { fn alias_help() {
let m = App::new("myprog") let m = App::new("myprog")
.subcommand(SubCommand::with_name("test") .subcommand(SubCommand::with_name("test").alias("do-stuff"))
.alias("do-stuff")) .get_matches_from_safe(vec!["myprog", "help", "do-stuff"]);
.get_matches_from_safe(vec!["myprog", "help", "do-stuff"]);
assert!(m.is_err()); assert!(m.is_err());
assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed); assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
} }
#[test] #[test]
fn visible_aliases_help_output() { fn visible_aliases_help_output() {
let app = App::new("clap-test") let app = App::new("clap-test").version("2.6").subcommand(
.version("2.6") SubCommand::with_name("test")
.subcommand(SubCommand::with_name("test")
.about("Some help") .about("Some help")
.alias("invisible") .alias("invisible")
.visible_alias("dongle") .visible_alias("dongle")
.visible_alias("done")); .visible_alias("done"),
assert!(test::compare_output(app, "clap-test --help", VISIBLE_ALIAS_HELP, false)); );
assert!(test::compare_output(
app,
"clap-test --help",
VISIBLE_ALIAS_HELP,
false
));
} }
#[test] #[test]
fn invisible_aliases_help_output() { fn invisible_aliases_help_output() {
let app = App::new("clap-test") let app = App::new("clap-test").version("2.6").subcommand(
.version("2.6") SubCommand::with_name("test")
.subcommand(SubCommand::with_name("test")
.about("Some help") .about("Some help")
.alias("invisible")); .alias("invisible"),
assert!(test::compare_output(app, "clap-test --help", INVISIBLE_ALIAS_HELP, false)); );
assert!(test::compare_output(
app,
"clap-test --help",
INVISIBLE_ALIAS_HELP,
false
));
} }
#[test] #[test]

View file

@ -5,8 +5,8 @@ use clap::{App, SubCommand};
include!("../clap-test.rs"); include!("../clap-test.rs");
static EXAMPLE1_TMPL_S : &'static str = include_str!("example1_tmpl_simple.txt"); static EXAMPLE1_TMPL_S: &'static str = include_str!("example1_tmpl_simple.txt");
static EXAMPLE1_TMPS_F : &'static str = include_str!("example1_tmpl_full.txt"); static EXAMPLE1_TMPS_F: &'static str = include_str!("example1_tmpl_full.txt");
static CUSTOM_TEMPL_HELP: &'static str = "MyApp 1.0 static CUSTOM_TEMPL_HELP: &'static str = "MyApp 1.0
Kevin K. <kbknapp@gmail.com> Kevin K. <kbknapp@gmail.com>
@ -52,53 +52,78 @@ SUBCOMMANDS:
#[test] #[test]
fn with_template() { fn with_template() {
let app = app_example1().template(EXAMPLE1_TMPL_S); let app = app_example1().template(EXAMPLE1_TMPL_S);
assert!(test::compare_output(app, "MyApp --help", SIMPLE_TEMPLATE, false)); assert!(test::compare_output(
app,
"MyApp --help",
SIMPLE_TEMPLATE,
false
));
} }
#[test] #[test]
fn custom_template() { fn custom_template() {
let app = app_example1().template(EXAMPLE1_TMPS_F); let app = app_example1().template(EXAMPLE1_TMPS_F);
assert!(test::compare_output(app, "MyApp --help", CUSTOM_TEMPL_HELP, false)); assert!(test::compare_output(
app,
"MyApp --help",
CUSTOM_TEMPL_HELP,
false
));
} }
#[test] #[test]
fn template_empty() { fn template_empty() {
let app = App::new("MyApp") let app = App::new("MyApp")
.version("1.0") .version("1.0")
.author("Kevin K. <kbknapp@gmail.com>") .author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things") .about("Does awesome things")
.template(""); .template("");
assert!(test::compare_output(app, "MyApp --help", "", false)); assert!(test::compare_output(app, "MyApp --help", "", false));
} }
#[test] #[test]
fn template_notag() { fn template_notag() {
let app = App::new("MyApp") let app = App::new("MyApp")
.version("1.0") .version("1.0")
.author("Kevin K. <kbknapp@gmail.com>") .author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things") .about("Does awesome things")
.template("test no tag test"); .template("test no tag test");
assert!(test::compare_output(app, "MyApp --help", "test no tag test", false)); assert!(test::compare_output(
app,
"MyApp --help",
"test no tag test",
false
));
} }
#[test] #[test]
fn template_unknowntag() { fn template_unknowntag() {
let app = App::new("MyApp") let app = App::new("MyApp")
.version("1.0") .version("1.0")
.author("Kevin K. <kbknapp@gmail.com>") .author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things") .about("Does awesome things")
.template("test {unknown_tag} test"); .template("test {unknown_tag} test");
assert!(test::compare_output(app, "MyApp --help", "test {unknown_tag} test", false)); assert!(test::compare_output(
app,
"MyApp --help",
"test {unknown_tag} test",
false
));
} }
#[test] #[test]
fn template_author_version() { fn template_author_version() {
let app = App::new("MyApp") let app = App::new("MyApp")
.version("1.0") .version("1.0")
.author("Kevin K. <kbknapp@gmail.com>") .author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things") .about("Does awesome things")
.template("{author}\n{version}\n{about}\n{bin}"); .template("{author}\n{version}\n{about}\n{bin}");
assert!(test::compare_output(app, "MyApp --help", "Kevin K. <kbknapp@gmail.com>\n1.0\nDoes awesome things\nMyApp", false)); assert!(test::compare_output(
app,
"MyApp --help",
"Kevin K. <kbknapp@gmail.com>\n1.0\nDoes awesome things\nMyApp",
false
));
} }
// ---------- // ----------
@ -108,10 +133,14 @@ fn app_example1<'b, 'c>() -> App<'b, 'c> {
.version("1.0") .version("1.0")
.author("Kevin K. <kbknapp@gmail.com>") .author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things") .about("Does awesome things")
.args_from_usage("-c, --config=[FILE] 'Sets a custom config file' .args_from_usage(
"-c, --config=[FILE] 'Sets a custom config file'
<output> 'Sets an optional output file' <output> 'Sets an optional output file'
-d... 'Turn debugging information on'") -d... 'Turn debugging information on'",
.subcommand(SubCommand::with_name("test") )
.about("does testing things") .subcommand(
.arg_from_usage("-l, --list 'lists test values'")) SubCommand::with_name("test")
.about("does testing things")
.arg_from_usage("-l, --list 'lists test values'"),
)
} }

View file

@ -101,7 +101,12 @@ pub fn check_complex_output(args: &str, out: &str) {
if matches.is_present("option") { if matches.is_present("option") {
if let Some(v) = matches.value_of("option") { if let Some(v) = matches.value_of("option") {
writeln!(w, "option present {} times with value: {}",matches.occurrences_of("option"), v).unwrap(); writeln!(
w,
"option present {} times with value: {}",
matches.occurrences_of("option"),
v
).unwrap();
} }
if let Some(ov) = matches.values_of("option") { if let Some(ov) = matches.values_of("option") {
for o in ov { for o in ov {
@ -120,29 +125,50 @@ pub fn check_complex_output(args: &str, out: &str) {
if matches.is_present("flag2") { if matches.is_present("flag2") {
writeln!(w, "flag2 present").unwrap(); writeln!(w, "flag2 present").unwrap();
writeln!(w, "option2 present with value of: {}", matches.value_of("long-option-2").unwrap()).unwrap(); writeln!(
writeln!(w, "positional2 present with value of: {}", matches.value_of("positional2").unwrap()).unwrap(); w,
"option2 present with value of: {}",
matches.value_of("long-option-2").unwrap()
).unwrap();
writeln!(
w,
"positional2 present with value of: {}",
matches.value_of("positional2").unwrap()
).unwrap();
} else { } else {
writeln!(w, "flag2 NOT present").unwrap(); writeln!(w, "flag2 NOT present").unwrap();
writeln!(w, "option2 maybe present with value of: {}", matches.value_of("long-option-2").unwrap_or("Nothing")).unwrap(); writeln!(
writeln!(w, "positional2 maybe present with value of: {}", matches.value_of("positional2").unwrap_or("Nothing")).unwrap(); w,
"option2 maybe present with value of: {}",
matches.value_of("long-option-2").unwrap_or("Nothing")
).unwrap();
writeln!(
w,
"positional2 maybe present with value of: {}",
matches.value_of("positional2").unwrap_or("Nothing")
).unwrap();
} }
let _ = match matches.value_of("Option3").unwrap_or("") { let _ = match matches.value_of("Option3").unwrap_or("") {
"fast" => writeln!(w, "option3 present quickly"), "fast" => writeln!(w, "option3 present quickly"),
"slow" => writeln!(w, "option3 present slowly"), "slow" => writeln!(w, "option3 present slowly"),
_ => writeln!(w, "option3 NOT present") _ => writeln!(w, "option3 NOT present"),
}; };
let _ = match matches.value_of("positional3").unwrap_or("") { let _ = match matches.value_of("positional3").unwrap_or("") {
"vi" => writeln!(w, "positional3 present in vi mode"), "vi" => writeln!(w, "positional3 present in vi mode"),
"emacs" => writeln!(w, "positional3 present in emacs mode"), "emacs" => writeln!(w, "positional3 present in emacs mode"),
_ => writeln!(w, "positional3 NOT present") _ => writeln!(w, "positional3 NOT present"),
}; };
if matches.is_present("option") { if matches.is_present("option") {
if let Some(v) = matches.value_of("option") { if let Some(v) = matches.value_of("option") {
writeln!(w, "option present {} times with value: {}",matches.occurrences_of("option"), v).unwrap(); writeln!(
w,
"option present {} times with value: {}",
matches.occurrences_of("option"),
v
).unwrap();
} }
if let Some(ov) = matches.values_of("option") { if let Some(ov) = matches.values_of("option") {
for o in ov { for o in ov {
@ -268,22 +294,27 @@ fn test_enums() {
#[test] #[test]
fn create_app() { fn create_app() {
let _ = let _ = App::new("test")
App::new("test").version("1.0").author("kevin").about("does awesome things").get_matches_from(vec![""]); .version("1.0")
.author("kevin")
.about("does awesome things")
.get_matches_from(vec![""]);
} }
#[test] #[test]
fn add_multiple_arg() { fn add_multiple_arg() {
let _ = App::new("test") let _ = App::new("test")
.args(&mut [ .args(&mut [
Arg::with_name("test").short("s"), Arg::with_name("test").short("s"),
Arg::with_name("test2").short("l")]) Arg::with_name("test2").short("l"),
.get_matches_from(vec![""]); ])
.get_matches_from(vec![""]);
} }
#[test] #[test]
fn flag_x2_opt() { fn flag_x2_opt() {
check_complex_output("clap-test value -f -f -o some", check_complex_output(
"flag present 2 times "clap-test value -f -f -o some",
"flag present 2 times
option present 1 times with value: some option present 1 times with value: some
An option: some An option: some
positional present with value: value positional present with value: value
@ -296,13 +327,12 @@ option present 1 times with value: some
An option: some An option: some
positional present with value: value positional present with value: value
subcmd NOT present subcmd NOT present
"); ",
);
} }
#[test] #[test]
fn long_opt_x2_pos() { fn long_opt_x2_pos() { check_complex_output("clap-test value --option some --option other", O2P); }
check_complex_output("clap-test value --option some --option other", O2P);
}
#[test] #[test]
fn long_opt_eq_x2_pos() { fn long_opt_eq_x2_pos() {
@ -310,29 +340,19 @@ fn long_opt_eq_x2_pos() {
} }
#[test] #[test]
fn short_opt_x2_pos() { fn short_opt_x2_pos() { check_complex_output("clap-test value -o some -o other", O2P); }
check_complex_output("clap-test value -o some -o other", O2P);
}
#[test] #[test]
fn short_opt_eq_x2_pos() { fn short_opt_eq_x2_pos() { check_complex_output("clap-test value -o=some -o=other", O2P); }
check_complex_output("clap-test value -o=some -o=other", O2P);
}
#[test] #[test]
fn short_flag_x2_comb_short_opt_pos() { fn short_flag_x2_comb_short_opt_pos() { check_complex_output("clap-test value -ff -o some", F2OP); }
check_complex_output("clap-test value -ff -o some", F2OP);
}
#[test] #[test]
fn short_flag_short_opt_pos() { fn short_flag_short_opt_pos() { check_complex_output("clap-test value -f -o some", FOP); }
check_complex_output("clap-test value -f -o some", FOP);
}
#[test] #[test]
fn long_flag_long_opt_pos() { fn long_flag_long_opt_pos() { check_complex_output("clap-test value --flag --option some", FOP); }
check_complex_output("clap-test value --flag --option some", FOP);
}
#[test] #[test]
fn long_flag_long_opt_eq_pos() { fn long_flag_long_opt_eq_pos() {

View file

@ -5,18 +5,32 @@ use clap::{App, Arg};
#[test] #[test]
#[should_panic] #[should_panic]
fn unique_arg_names() { fn unique_arg_names() {
App::new("some").args(&[Arg::with_name("arg").short("a"), Arg::with_name("arg").short("b")]); let _ = App::new("some")
.args(&[
Arg::with_name("arg").short("a"),
Arg::with_name("arg").short("b"),
])
.get_matches_safe();
} }
#[test] #[test]
#[should_panic] #[should_panic]
fn unique_arg_shorts() { fn unique_arg_shorts() {
App::new("some").args(&[Arg::with_name("arg1").short("a"), Arg::with_name("arg2").short("a")]); let _ = App::new("some")
.args(&[
Arg::with_name("arg1").short("a"),
Arg::with_name("arg2").short("a"),
])
.get_matches_safe();
} }
#[test] #[test]
#[should_panic] #[should_panic]
fn unique_arg_longs() { fn unique_arg_longs() {
App::new("some") let _ = App::new("some")
.args(&[Arg::with_name("arg1").long("long"), Arg::with_name("arg2").long("long")]); .args(&[
Arg::with_name("arg1").long("long"),
Arg::with_name("arg2").long("long"),
])
.get_matches_safe();
} }

View file

@ -4,15 +4,14 @@ extern crate clap;
use std::ffi::OsString; use std::ffi::OsString;
use std::os::unix::ffi::OsStringExt; use std::os::unix::ffi::OsStringExt;
use clap::{App, Arg, AppSettings, ErrorKind}; use clap::{App, AppSettings, Arg, ErrorKind};
#[test] #[test]
fn invalid_utf8_strict_positional() { fn invalid_utf8_strict_positional() {
let m = App::new("bad_utf8") let m = App::new("bad_utf8")
.arg(Arg::from_usage("<arg> 'some arg'")) .arg(Arg::from_usage("<arg> 'some arg'"))
.setting(AppSettings::StrictUtf8) .setting(AppSettings::StrictUtf8)
.get_matches_from_safe(vec![OsString::from(""), .get_matches_from_safe(vec![OsString::from(""), OsString::from_vec(vec![0xe9])]);
OsString::from_vec(vec![0xe9])]);
assert!(m.is_err()); assert!(m.is_err());
assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8); assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8);
} }
@ -22,9 +21,11 @@ fn invalid_utf8_strict_option_short_space() {
let m = App::new("bad_utf8") let m = App::new("bad_utf8")
.arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
.setting(AppSettings::StrictUtf8) .setting(AppSettings::StrictUtf8)
.get_matches_from_safe(vec![OsString::from(""), .get_matches_from_safe(vec![
OsString::from("-a"), OsString::from(""),
OsString::from_vec(vec![0xe9])]); OsString::from("-a"),
OsString::from_vec(vec![0xe9]),
]);
assert!(m.is_err()); assert!(m.is_err());
assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8); assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8);
} }
@ -34,8 +35,10 @@ fn invalid_utf8_strict_option_short_equals() {
let m = App::new("bad_utf8") let m = App::new("bad_utf8")
.arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
.setting(AppSettings::StrictUtf8) .setting(AppSettings::StrictUtf8)
.get_matches_from_safe(vec![OsString::from(""), .get_matches_from_safe(vec![
OsString::from_vec(vec![0x2d, 0x61, 0x3d, 0xe9])]); OsString::from(""),
OsString::from_vec(vec![0x2d, 0x61, 0x3d, 0xe9]),
]);
assert!(m.is_err()); assert!(m.is_err());
assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8); assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8);
} }
@ -45,8 +48,10 @@ fn invalid_utf8_strict_option_short_no_space() {
let m = App::new("bad_utf8") let m = App::new("bad_utf8")
.arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
.setting(AppSettings::StrictUtf8) .setting(AppSettings::StrictUtf8)
.get_matches_from_safe(vec![OsString::from(""), .get_matches_from_safe(vec![
OsString::from_vec(vec![0x2d, 0x61, 0xe9])]); OsString::from(""),
OsString::from_vec(vec![0x2d, 0x61, 0xe9]),
]);
assert!(m.is_err()); assert!(m.is_err());
assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8); assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8);
} }
@ -56,9 +61,11 @@ fn invalid_utf8_strict_option_long_space() {
let m = App::new("bad_utf8") let m = App::new("bad_utf8")
.arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
.setting(AppSettings::StrictUtf8) .setting(AppSettings::StrictUtf8)
.get_matches_from_safe(vec![OsString::from(""), .get_matches_from_safe(vec![
OsString::from("--arg"), OsString::from(""),
OsString::from_vec(vec![0xe9])]); OsString::from("--arg"),
OsString::from_vec(vec![0xe9]),
]);
assert!(m.is_err()); assert!(m.is_err());
assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8); assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8);
} }
@ -68,8 +75,10 @@ fn invalid_utf8_strict_option_long_equals() {
let m = App::new("bad_utf8") let m = App::new("bad_utf8")
.arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
.setting(AppSettings::StrictUtf8) .setting(AppSettings::StrictUtf8)
.get_matches_from_safe(vec![OsString::from(""), .get_matches_from_safe(vec![
OsString::from_vec(vec![0x2d, 0x2d, 0x61, 0x72, 0x67, 0x3d, 0xe9])]); OsString::from(""),
OsString::from_vec(vec![0x2d, 0x2d, 0x61, 0x72, 0x67, 0x3d, 0xe9]),
]);
assert!(m.is_err()); assert!(m.is_err());
assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8); assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8);
} }
@ -78,8 +87,7 @@ fn invalid_utf8_strict_option_long_equals() {
fn invalid_utf8_lossy_positional() { fn invalid_utf8_lossy_positional() {
let r = App::new("bad_utf8") let r = App::new("bad_utf8")
.arg(Arg::from_usage("<arg> 'some arg'")) .arg(Arg::from_usage("<arg> 'some arg'"))
.get_matches_from_safe(vec![OsString::from(""), .get_matches_from_safe(vec![OsString::from(""), OsString::from_vec(vec![0xe9])]);
OsString::from_vec(vec![0xe9])]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
assert!(m.is_present("arg")); assert!(m.is_present("arg"));
@ -90,9 +98,11 @@ fn invalid_utf8_lossy_positional() {
fn invalid_utf8_lossy_option_short_space() { fn invalid_utf8_lossy_option_short_space() {
let r = App::new("bad_utf8") let r = App::new("bad_utf8")
.arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
.get_matches_from_safe(vec![OsString::from(""), .get_matches_from_safe(vec![
OsString::from("-a"), OsString::from(""),
OsString::from_vec(vec![0xe9])]); OsString::from("-a"),
OsString::from_vec(vec![0xe9]),
]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
assert!(m.is_present("arg")); assert!(m.is_present("arg"));
@ -103,8 +113,10 @@ fn invalid_utf8_lossy_option_short_space() {
fn invalid_utf8_lossy_option_short_equals() { fn invalid_utf8_lossy_option_short_equals() {
let r = App::new("bad_utf8") let r = App::new("bad_utf8")
.arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
.get_matches_from_safe(vec![OsString::from(""), .get_matches_from_safe(vec![
OsString::from_vec(vec![0x2d, 0x61, 0x3d, 0xe9])]); OsString::from(""),
OsString::from_vec(vec![0x2d, 0x61, 0x3d, 0xe9]),
]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
assert!(m.is_present("arg")); assert!(m.is_present("arg"));
@ -115,8 +127,10 @@ fn invalid_utf8_lossy_option_short_equals() {
fn invalid_utf8_lossy_option_short_no_space() { fn invalid_utf8_lossy_option_short_no_space() {
let r = App::new("bad_utf8") let r = App::new("bad_utf8")
.arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
.get_matches_from_safe(vec![OsString::from(""), .get_matches_from_safe(vec![
OsString::from_vec(vec![0x2d, 0x61, 0xe9])]); OsString::from(""),
OsString::from_vec(vec![0x2d, 0x61, 0xe9]),
]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
assert!(m.is_present("arg")); assert!(m.is_present("arg"));
@ -127,9 +141,11 @@ fn invalid_utf8_lossy_option_short_no_space() {
fn invalid_utf8_lossy_option_long_space() { fn invalid_utf8_lossy_option_long_space() {
let r = App::new("bad_utf8") let r = App::new("bad_utf8")
.arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
.get_matches_from_safe(vec![OsString::from(""), .get_matches_from_safe(vec![
OsString::from("--arg"), OsString::from(""),
OsString::from_vec(vec![0xe9])]); OsString::from("--arg"),
OsString::from_vec(vec![0xe9]),
]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
assert!(m.is_present("arg")); assert!(m.is_present("arg"));
@ -140,8 +156,10 @@ fn invalid_utf8_lossy_option_long_space() {
fn invalid_utf8_lossy_option_long_equals() { fn invalid_utf8_lossy_option_long_equals() {
let r = App::new("bad_utf8") let r = App::new("bad_utf8")
.arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
.get_matches_from_safe(vec![OsString::from(""), .get_matches_from_safe(vec![
OsString::from_vec(vec![0x2d, 0x2d, 0x61, 0x72, 0x67, 0x3d, 0xe9])]); OsString::from(""),
OsString::from_vec(vec![0x2d, 0x2d, 0x61, 0x72, 0x67, 0x3d, 0xe9]),
]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
assert!(m.is_present("arg")); assert!(m.is_present("arg"));
@ -152,72 +170,99 @@ fn invalid_utf8_lossy_option_long_equals() {
fn invalid_utf8_positional() { fn invalid_utf8_positional() {
let r = App::new("bad_utf8") let r = App::new("bad_utf8")
.arg(Arg::from_usage("<arg> 'some arg'")) .arg(Arg::from_usage("<arg> 'some arg'"))
.get_matches_from_safe(vec![OsString::from(""), .get_matches_from_safe(vec![OsString::from(""), OsString::from_vec(vec![0xe9])]);
OsString::from_vec(vec![0xe9])]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
assert!(m.is_present("arg")); assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_os("arg").unwrap(), &*OsString::from_vec(vec![0xe9])); assert_eq!(
&*m.value_of_os("arg").unwrap(),
&*OsString::from_vec(vec![0xe9])
);
} }
#[test] #[test]
fn invalid_utf8_option_short_space() { fn invalid_utf8_option_short_space() {
let r = App::new("bad_utf8") let r = App::new("bad_utf8")
.arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
.get_matches_from_safe(vec![OsString::from(""), .get_matches_from_safe(vec![
OsString::from("-a"), OsString::from(""),
OsString::from_vec(vec![0xe9])]); OsString::from("-a"),
OsString::from_vec(vec![0xe9]),
]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
assert!(m.is_present("arg")); assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_os("arg").unwrap(), &*OsString::from_vec(vec![0xe9])); assert_eq!(
&*m.value_of_os("arg").unwrap(),
&*OsString::from_vec(vec![0xe9])
);
} }
#[test] #[test]
fn invalid_utf8_option_short_equals() { fn invalid_utf8_option_short_equals() {
let r = App::new("bad_utf8") let r = App::new("bad_utf8")
.arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
.get_matches_from_safe(vec![OsString::from(""), .get_matches_from_safe(vec![
OsString::from_vec(vec![0x2d, 0x61, 0x3d, 0xe9])]); OsString::from(""),
OsString::from_vec(vec![0x2d, 0x61, 0x3d, 0xe9]),
]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
assert!(m.is_present("arg")); assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_os("arg").unwrap(), &*OsString::from_vec(vec![0xe9])); assert_eq!(
&*m.value_of_os("arg").unwrap(),
&*OsString::from_vec(vec![0xe9])
);
} }
#[test] #[test]
fn invalid_utf8_option_short_no_space() { fn invalid_utf8_option_short_no_space() {
let r = App::new("bad_utf8") let r = App::new("bad_utf8")
.arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
.get_matches_from_safe(vec![OsString::from(""), .get_matches_from_safe(vec![
OsString::from_vec(vec![0x2d, 0x61, 0xe9])]); OsString::from(""),
OsString::from_vec(vec![0x2d, 0x61, 0xe9]),
]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
assert!(m.is_present("arg")); assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_os("arg").unwrap(), &*OsString::from_vec(vec![0xe9])); assert_eq!(
&*m.value_of_os("arg").unwrap(),
&*OsString::from_vec(vec![0xe9])
);
} }
#[test] #[test]
fn invalid_utf8_option_long_space() { fn invalid_utf8_option_long_space() {
let r = App::new("bad_utf8") let r = App::new("bad_utf8")
.arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
.get_matches_from_safe(vec![OsString::from(""), .get_matches_from_safe(vec![
OsString::from("--arg"), OsString::from(""),
OsString::from_vec(vec![0xe9])]); OsString::from("--arg"),
OsString::from_vec(vec![0xe9]),
]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
assert!(m.is_present("arg")); assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_os("arg").unwrap(), &*OsString::from_vec(vec![0xe9])); assert_eq!(
&*m.value_of_os("arg").unwrap(),
&*OsString::from_vec(vec![0xe9])
);
} }
#[test] #[test]
fn invalid_utf8_option_long_equals() { fn invalid_utf8_option_long_equals() {
let r = App::new("bad_utf8") let r = App::new("bad_utf8")
.arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
.get_matches_from_safe(vec![OsString::from(""), .get_matches_from_safe(vec![
OsString::from_vec(vec![0x2d, 0x2d, 0x61, 0x72, 0x67, 0x3d, 0xe9])]); OsString::from(""),
OsString::from_vec(vec![0x2d, 0x2d, 0x61, 0x72, 0x67, 0x3d, 0xe9]),
]);
assert!(r.is_ok()); assert!(r.is_ok());
let m = r.unwrap(); let m = r.unwrap();
assert!(m.is_present("arg")); assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_os("arg").unwrap(), &*OsString::from_vec(vec![0xe9])); assert_eq!(
&*m.value_of_os("arg").unwrap(),
&*OsString::from_vec(vec![0xe9])
);
} }

View file

@ -38,10 +38,10 @@ fn complex_version_output() {
let mut a = App::new("clap-test").version("v1.4.8"); let mut a = App::new("clap-test").version("v1.4.8");
let _ = a.get_matches_from_safe_borrow(vec![""]); let _ = a.get_matches_from_safe_borrow(vec![""]);
// Now we check the output of print_version() // Now we check the output of print_version()
let mut ver = vec![]; let mut ver = vec![];
a.write_version(&mut ver).unwrap(); a.write_version(&mut ver).unwrap();
assert_eq!(str::from_utf8(&ver).unwrap(), VERSION); assert_eq!(str::from_utf8(&ver).unwrap(), VERSION);
} }
#[test] #[test]

View file

@ -1,4 +1,4 @@
#![cfg(feature="yaml")] #![cfg(feature = "yaml")]
#[macro_use] #[macro_use]
extern crate clap; extern crate clap;
@ -21,8 +21,9 @@ fn help_message() {
let mut help_buffer = Vec::new(); let mut help_buffer = Vec::new();
app.write_help(&mut help_buffer).unwrap(); app.write_help(&mut help_buffer).unwrap();
let help_string = String::from_utf8(help_buffer).unwrap(); let help_string = String::from_utf8(help_buffer).unwrap();
assert!(help_string.contains( assert!(
"-h, --help prints help with a nonstandard description\n")); help_string.contains("-h, --help prints help with a nonstandard description\n")
);
} }
#[test] #[test]
@ -35,6 +36,5 @@ fn author() {
let mut help_buffer = Vec::new(); let mut help_buffer = Vec::new();
app.write_help(&mut help_buffer).unwrap(); app.write_help(&mut help_buffer).unwrap();
let help_string = String::from_utf8(help_buffer).unwrap(); let help_string = String::from_utf8(help_buffer).unwrap();
assert!(help_string.contains( assert!(help_string.contains("Kevin K. <kbknapp@gmail.com>"));
"Kevin K. <kbknapp@gmail.com>"));
} }