diff --git a/src/app/parser.rs b/src/app/parser.rs index d0635a3673e..099bc30a699 100644 --- a/src/app/parser.rs +++ b/src/app/parser.rs @@ -1250,7 +1250,16 @@ impl<'a, 'b> Parser<'a, 'b> return Ok(ret); } else if let Some(flag) = self.flags .iter() - .find(|v| v.long.is_some() && &*v.long.unwrap() == arg) { + .find(|v| + (v.long.is_some() && + &*v.long.unwrap() == arg) || + (v.aliases.is_some() && + v.aliases + .as_ref() + .unwrap() + .iter() + .any(|&(n, _)| n == &*arg)) + ) { debugln!("Found valid flag '{}'", flag.to_string()); // Only flags could be help or version, and we need to check the raw long // so this is the first point to check diff --git a/src/args/arg.rs b/src/args/arg.rs index d6adef98ac5..e1a35887020 100644 --- a/src/args/arg.rs +++ b/src/args/arg.rs @@ -452,6 +452,7 @@ impl<'a, 'b> Arg<'a, 'b> { /// # use clap::{App, Arg}; /// let m = App::new("myprog") /// .arg(Arg::with_name("test") + /// .long("test") /// .aliases(&["do-stuff", "do-tests", "tests"]) /// .help("the file to add") /// .required(false)) @@ -506,6 +507,7 @@ impl<'a, 'b> Arg<'a, 'b> { /// # use clap::{App, Arg}; /// let m = App::new("myprog") /// .arg(Arg::with_name("test") + /// .long("test") /// .visible_aliases(&["something", "awesome", "cool"])) /// .get_matches_from(vec!["myprog", "--awesome"]); /// assert!(m.is_present("test")); diff --git a/src/args/arg_builder/flag.rs b/src/args/arg_builder/flag.rs index 471993e4618..5f99017b5be 100644 --- a/src/args/arg_builder/flag.rs +++ b/src/args/arg_builder/flag.rs @@ -17,6 +17,7 @@ use args::settings::{ArgFlags, ArgSettings}; pub struct FlagBuilder<'n, 'e> { pub name: &'n str, pub long: Option<&'e str>, + pub aliases: Option>, pub help: Option<&'e str>, pub blacklist: Option>, pub requires: Option>, @@ -31,6 +32,7 @@ impl<'n, 'e> Default for FlagBuilder<'n, 'e> { FlagBuilder { name: "", long: None, + aliases: None, help: None, blacklist: None, requires: None, @@ -68,6 +70,7 @@ impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for FlagBuilder<'a, 'b> { name: a.name, short: a.short, long: a.long, + aliases: a.aliases.clone(), help: a.help, blacklist: a.blacklist.clone(), overrides: a.overrides.clone(), @@ -81,10 +84,27 @@ impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for FlagBuilder<'a, 'b> { impl<'n, 'e> Display for FlagBuilder<'n, 'e> { fn fmt(&self, f: &mut Formatter) -> Result { if let Some(l) = self.long { - write!(f, "--{}", l) + try!(write!(f, "--{}", l)); } else { - write!(f, "-{}", self.short.unwrap()) + try!(write!(f, "-{}", self.short.unwrap())); } + + // Write aliases such as [aliases: alias, new-alias] + if let Some(ref vec) = self.aliases { + try!(write!(f, " [aliases: ")); + let mut it = vec.iter().peekable(); + while let Some(&(val, b)) = it.next() { + if b { + try!(write!(f, "{}", val)); + if it.peek().is_some() { + try!(write!(f, ", ")); + } + } + } + try!(write!(f, "]")); + } + + Ok(()) } } @@ -94,6 +114,7 @@ impl<'n, 'e> Clone for FlagBuilder<'n, 'e> { name: self.name, short: self.short, long: self.long, + aliases: self.aliases.clone(), help: self.help, blacklist: self.blacklist.clone(), overrides: self.overrides.clone(), @@ -169,7 +190,19 @@ impl<'n, 'e> AnyArg<'n, 'e> for FlagBuilder<'n, 'e> { self.long.is_some() } fn aliases(&self) -> Option> { - None + if let Some(ref aliases) = self.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 + } } } @@ -197,4 +230,26 @@ mod test { assert_eq!(&*format!("{}", f2), "-f"); } + + #[test] + fn flagbuilder_display_single_alias() { + let mut f = FlagBuilder::new("flg"); + f.long = Some("flag"); + f.aliases = Some(vec![("als", true)]); + + assert_eq!(&*format!("{}", f), "--flag [aliases: als]"); + } + + #[test] + fn flagbuilder_display_multiple_aliases() { + let mut f = FlagBuilder::new("flg"); + f.short = Some('f'); + f.aliases = Some(vec![ + ("alias_not_visible", false), + ("f2", true), + ("f3", true), + ("f4", true) + ]); + assert_eq!(&*format!("{}", f), "-f [aliases: f2, f3, f4]"); + } } diff --git a/src/args/arg_builder/option.rs b/src/args/arg_builder/option.rs index 438cc820336..501375f552d 100644 --- a/src/args/arg_builder/option.rs +++ b/src/args/arg_builder/option.rs @@ -344,6 +344,7 @@ mod test { assert_eq!(&*format!("{}", o), "--option [aliases: als]"); } + #[test] fn optbuilder_display_multiple_aliases() { let mut o = OptBuilder::new("opt"); o.long = Some("option"); diff --git a/tests/arg_aliases.rs b/tests/arg_aliases.rs index 2895128afcc..68620a60de5 100644 --- a/tests/arg_aliases.rs +++ b/tests/arg_aliases.rs @@ -9,22 +9,30 @@ static SC_VISIBLE_ALIAS_HELP: &'static str = "test Some help USAGE: - test [OPTIONS] + test [FLAGS] [OPTIONS] + +FLAGS: + -f, --flag + flag with aliases [aliases: v_flg, flag2, flg3] OPTIONS: - --opt [aliases: visible]"; + -o, --opt + help for option with alias [aliases: visible]"; static SC_INVISIBLE_ALIAS_HELP: &'static str = "test Some help USAGE: - test [OPTIONS] + test [FLAGS] [OPTIONS] + +FLAGS: + -f, --flag flag with aliases OPTIONS: - --opt "; + -o, --opt help for option with alias"; #[test] -fn single_alias_of_option_long() { +fn single_alias_of_option() { let a = App::new("single_alias") .arg(Arg::with_name("alias") .long("alias") @@ -41,7 +49,7 @@ fn single_alias_of_option_long() { } #[test] -fn multiple_aliases_of_option_long() { +fn multiple_aliases_of_option() { let a = App::new("multiple_aliases") .arg(Arg::with_name("aliases") .long("aliases") @@ -86,6 +94,49 @@ fn multiple_aliases_of_option_long() { assert_eq!(als3.value_of("aliases").unwrap(), "value"); } +#[test] +fn single_alias_of_flag() { + let a = App::new("test") + .arg(Arg::with_name("flag") + .long("flag") + .alias("alias")) + .get_matches_from_safe(vec!["", "--alias"]); + assert!(a.is_ok()); + let a = a.unwrap(); + assert!(a.is_present("flag")); +} + +#[test] +fn multiple_aliases_of_flag() { + let a = App::new("test") + .arg(Arg::with_name("flag") + .long("flag") + .aliases(&["invisible", + "set", "of", + "cool", "aliases"])); + + let flag = a.clone().get_matches_from_safe(vec!["", "--flag"]); + assert!(flag.is_ok()); + let flag = flag.unwrap(); + + let inv = a.clone().get_matches_from_safe(vec!["", "--invisible"]); + assert!(inv.is_ok()); + let inv = inv.unwrap(); + + let cool = a.clone().get_matches_from_safe(vec!["", "--cool"]); + assert!(cool.is_ok()); + let cool = cool.unwrap(); + + let als = a.clone().get_matches_from_safe(vec!["", "--aliases"]); + assert!(als.is_ok()); + let als = als.unwrap(); + + assert!(flag.is_present("flag")); + assert!(inv.is_present("flag")); + assert!(cool.is_present("flag")); + assert!(als.is_present("flag")); +} + #[test] fn alias_on_a_subcommand_option() { let m = App::new("test") @@ -112,36 +163,40 @@ fn alias_on_a_subcommand_option() { #[test] fn invisible_arg_aliases_help_output() { let app = App::new("clap-test") + .author("Salim Afiune") .subcommand(SubCommand::with_name("test") .about("Some help") .arg(Arg::with_name("opt") .long("opt") + .short("o") + .help("help for option with alias") .takes_value(true) - .aliases(&["invisible", "als1", "more"]))); + .aliases(&["invisible", "als1", "more"])) + .arg(Arg::with_name("flg") + .long("flag") + .short("f") + .help("flag with aliases") + .aliases(&["invisible", "flg1", "anyway"]))); test::check_subcommand_help(app, "test", SC_INVISIBLE_ALIAS_HELP); } #[test] fn visible_arg_aliases_help_output() { let app = App::new("clap-test") + .author("Salim Afiune") .subcommand(SubCommand::with_name("test") .about("Some help") .arg(Arg::with_name("opt") .long("opt") + .short("o") + .help("help for option with alias") .takes_value(true) .alias("invisible") - .visible_alias("visible"))); + .visible_alias("visible")) + .arg(Arg::with_name("flg") + .long("flag") + .short("f") + .help("flag with aliases") + .visible_aliases(&["v_flg", "flag2", "flg3"]))); test::check_subcommand_help(app, "test", SC_VISIBLE_ALIAS_HELP); } - -#[test] -fn visible_arg_flag_aliases() { - let a = App::new("test") - .arg(Arg::with_name("opt") - .long("opt") - .aliases(&["invisible", "set", "of", "aliases"])) - .get_matches_from_safe(vec!["", "--aliases"]); - assert!(a.is_ok()); - let a = a.unwrap(); - assert!(a.is_present("opt")); -}