Skip to content

Commit 40d6dac

Browse files
author
Salim Afiune
committed
feat(flag_aliases): Ability to alias flags
Added same alias funtionality for flags, now you can do: ``` Arg::with_name("flg") .long("flag") .short("f") .alias("not_visible_flag") .visible_alias("awesome_v_flag") ``` Signed-off-by: Salim Afiune <[email protected]>
1 parent e5d9760 commit 40d6dac

File tree

5 files changed

+146
-24
lines changed

5 files changed

+146
-24
lines changed

src/app/parser.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -1250,7 +1250,16 @@ impl<'a, 'b> Parser<'a, 'b>
12501250
return Ok(ret);
12511251
} else if let Some(flag) = self.flags
12521252
.iter()
1253-
.find(|v| v.long.is_some() && &*v.long.unwrap() == arg) {
1253+
.find(|v|
1254+
(v.long.is_some() &&
1255+
&*v.long.unwrap() == arg) ||
1256+
(v.aliases.is_some() &&
1257+
v.aliases
1258+
.as_ref()
1259+
.unwrap()
1260+
.iter()
1261+
.any(|&(n, _)| n == &*arg))
1262+
) {
12541263
debugln!("Found valid flag '{}'", flag.to_string());
12551264
// Only flags could be help or version, and we need to check the raw long
12561265
// so this is the first point to check

src/args/arg.rs

+2
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,7 @@ impl<'a, 'b> Arg<'a, 'b> {
452452
/// # use clap::{App, Arg};
453453
/// let m = App::new("myprog")
454454
/// .arg(Arg::with_name("test")
455+
/// .long("test")
455456
/// .aliases(&["do-stuff", "do-tests", "tests"])
456457
/// .help("the file to add")
457458
/// .required(false))
@@ -506,6 +507,7 @@ impl<'a, 'b> Arg<'a, 'b> {
506507
/// # use clap::{App, Arg};
507508
/// let m = App::new("myprog")
508509
/// .arg(Arg::with_name("test")
510+
/// .long("test")
509511
/// .visible_aliases(&["something", "awesome", "cool"]))
510512
/// .get_matches_from(vec!["myprog", "--awesome"]);
511513
/// assert!(m.is_present("test"));

src/args/arg_builder/flag.rs

+58-3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use args::settings::{ArgFlags, ArgSettings};
1717
pub struct FlagBuilder<'n, 'e> {
1818
pub name: &'n str,
1919
pub long: Option<&'e str>,
20+
pub aliases: Option<Vec<(&'e str, bool)>>,
2021
pub help: Option<&'e str>,
2122
pub blacklist: Option<Vec<&'e str>>,
2223
pub requires: Option<Vec<&'e str>>,
@@ -31,6 +32,7 @@ impl<'n, 'e> Default for FlagBuilder<'n, 'e> {
3132
FlagBuilder {
3233
name: "",
3334
long: None,
35+
aliases: None,
3436
help: None,
3537
blacklist: None,
3638
requires: None,
@@ -68,6 +70,7 @@ impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for FlagBuilder<'a, 'b> {
6870
name: a.name,
6971
short: a.short,
7072
long: a.long,
73+
aliases: a.aliases.clone(),
7174
help: a.help,
7275
blacklist: a.blacklist.clone(),
7376
overrides: a.overrides.clone(),
@@ -81,10 +84,27 @@ impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for FlagBuilder<'a, 'b> {
8184
impl<'n, 'e> Display for FlagBuilder<'n, 'e> {
8285
fn fmt(&self, f: &mut Formatter) -> Result {
8386
if let Some(l) = self.long {
84-
write!(f, "--{}", l)
87+
try!(write!(f, "--{}", l));
8588
} else {
86-
write!(f, "-{}", self.short.unwrap())
89+
try!(write!(f, "-{}", self.short.unwrap()));
8790
}
91+
92+
// Write aliases such as [aliases: alias, new-alias]
93+
if let Some(ref vec) = self.aliases {
94+
try!(write!(f, " [aliases: "));
95+
let mut it = vec.iter().peekable();
96+
while let Some(&(val, b)) = it.next() {
97+
if b {
98+
try!(write!(f, "{}", val));
99+
if it.peek().is_some() {
100+
try!(write!(f, ", "));
101+
}
102+
}
103+
}
104+
try!(write!(f, "]"));
105+
}
106+
107+
Ok(())
88108
}
89109
}
90110

@@ -94,6 +114,7 @@ impl<'n, 'e> Clone for FlagBuilder<'n, 'e> {
94114
name: self.name,
95115
short: self.short,
96116
long: self.long,
117+
aliases: self.aliases.clone(),
97118
help: self.help,
98119
blacklist: self.blacklist.clone(),
99120
overrides: self.overrides.clone(),
@@ -169,7 +190,19 @@ impl<'n, 'e> AnyArg<'n, 'e> for FlagBuilder<'n, 'e> {
169190
self.long.is_some()
170191
}
171192
fn aliases(&self) -> Option<Vec<&'e str>> {
172-
None
193+
if let Some(ref aliases) = self.aliases {
194+
let vis_aliases: Vec<_> =
195+
aliases.iter()
196+
.filter_map(|&(n, v)| if v { Some(n) } else { None })
197+
.collect();
198+
if vis_aliases.is_empty() {
199+
None
200+
} else {
201+
Some(vis_aliases)
202+
}
203+
} else {
204+
None
205+
}
173206
}
174207
}
175208

@@ -197,4 +230,26 @@ mod test {
197230

198231
assert_eq!(&*format!("{}", f2), "-f");
199232
}
233+
234+
#[test]
235+
fn flagbuilder_display_single_alias() {
236+
let mut f = FlagBuilder::new("flg");
237+
f.long = Some("flag");
238+
f.aliases = Some(vec![("als", true)]);
239+
240+
assert_eq!(&*format!("{}", f), "--flag [aliases: als]");
241+
}
242+
243+
#[test]
244+
fn flagbuilder_display_multiple_aliases() {
245+
let mut f = FlagBuilder::new("flg");
246+
f.short = Some('f');
247+
f.aliases = Some(vec![
248+
("alias_not_visible", false),
249+
("f2", true),
250+
("f3", true),
251+
("f4", true)
252+
]);
253+
assert_eq!(&*format!("{}", f), "-f [aliases: f2, f3, f4]");
254+
}
200255
}

src/args/arg_builder/option.rs

+1
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,7 @@ mod test {
344344
assert_eq!(&*format!("{}", o), "--option <opt> [aliases: als]");
345345
}
346346

347+
#[test]
347348
fn optbuilder_display_multiple_aliases() {
348349
let mut o = OptBuilder::new("opt");
349350
o.long = Some("option");

tests/arg_aliases.rs

+75-20
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,30 @@ static SC_VISIBLE_ALIAS_HELP: &'static str = "test
99
Some help
1010
1111
USAGE:
12-
test [OPTIONS]
12+
test [FLAGS] [OPTIONS]
13+
14+
FLAGS:
15+
-f, --flag
16+
flag with aliases [aliases: v_flg, flag2, flg3]
1317
1418
OPTIONS:
15-
--opt <opt> [aliases: visible]";
19+
-o, --opt <opt>
20+
help for option with alias [aliases: visible]";
1621

1722
static SC_INVISIBLE_ALIAS_HELP: &'static str = "test
1823
Some help
1924
2025
USAGE:
21-
test [OPTIONS]
26+
test [FLAGS] [OPTIONS]
27+
28+
FLAGS:
29+
-f, --flag flag with aliases
2230
2331
OPTIONS:
24-
--opt <opt> ";
32+
-o, --opt <opt> help for option with alias";
2533

2634
#[test]
27-
fn single_alias_of_option_long() {
35+
fn single_alias_of_option() {
2836
let a = App::new("single_alias")
2937
.arg(Arg::with_name("alias")
3038
.long("alias")
@@ -41,7 +49,7 @@ fn single_alias_of_option_long() {
4149
}
4250

4351
#[test]
44-
fn multiple_aliases_of_option_long() {
52+
fn multiple_aliases_of_option() {
4553
let a = App::new("multiple_aliases")
4654
.arg(Arg::with_name("aliases")
4755
.long("aliases")
@@ -86,6 +94,49 @@ fn multiple_aliases_of_option_long() {
8694
assert_eq!(als3.value_of("aliases").unwrap(), "value");
8795
}
8896

97+
#[test]
98+
fn single_alias_of_flag() {
99+
let a = App::new("test")
100+
.arg(Arg::with_name("flag")
101+
.long("flag")
102+
.alias("alias"))
103+
.get_matches_from_safe(vec!["", "--alias"]);
104+
assert!(a.is_ok());
105+
let a = a.unwrap();
106+
assert!(a.is_present("flag"));
107+
}
108+
109+
#[test]
110+
fn multiple_aliases_of_flag() {
111+
let a = App::new("test")
112+
.arg(Arg::with_name("flag")
113+
.long("flag")
114+
.aliases(&["invisible",
115+
"set", "of",
116+
"cool", "aliases"]));
117+
118+
let flag = a.clone().get_matches_from_safe(vec!["", "--flag"]);
119+
assert!(flag.is_ok());
120+
let flag = flag.unwrap();
121+
122+
let inv = a.clone().get_matches_from_safe(vec!["", "--invisible"]);
123+
assert!(inv.is_ok());
124+
let inv = inv.unwrap();
125+
126+
let cool = a.clone().get_matches_from_safe(vec!["", "--cool"]);
127+
assert!(cool.is_ok());
128+
let cool = cool.unwrap();
129+
130+
let als = a.clone().get_matches_from_safe(vec!["", "--aliases"]);
131+
assert!(als.is_ok());
132+
let als = als.unwrap();
133+
134+
assert!(flag.is_present("flag"));
135+
assert!(inv.is_present("flag"));
136+
assert!(cool.is_present("flag"));
137+
assert!(als.is_present("flag"));
138+
}
139+
89140
#[test]
90141
fn alias_on_a_subcommand_option() {
91142
let m = App::new("test")
@@ -112,36 +163,40 @@ fn alias_on_a_subcommand_option() {
112163
#[test]
113164
fn invisible_arg_aliases_help_output() {
114165
let app = App::new("clap-test")
166+
.author("Salim Afiune")
115167
.subcommand(SubCommand::with_name("test")
116168
.about("Some help")
117169
.arg(Arg::with_name("opt")
118170
.long("opt")
171+
.short("o")
172+
.help("help for option with alias")
119173
.takes_value(true)
120-
.aliases(&["invisible", "als1", "more"])));
174+
.aliases(&["invisible", "als1", "more"]))
175+
.arg(Arg::with_name("flg")
176+
.long("flag")
177+
.short("f")
178+
.help("flag with aliases")
179+
.aliases(&["invisible", "flg1", "anyway"])));
121180
test::check_subcommand_help(app, "test", SC_INVISIBLE_ALIAS_HELP);
122181
}
123182

124183
#[test]
125184
fn visible_arg_aliases_help_output() {
126185
let app = App::new("clap-test")
186+
.author("Salim Afiune")
127187
.subcommand(SubCommand::with_name("test")
128188
.about("Some help")
129189
.arg(Arg::with_name("opt")
130190
.long("opt")
191+
.short("o")
192+
.help("help for option with alias")
131193
.takes_value(true)
132194
.alias("invisible")
133-
.visible_alias("visible")));
195+
.visible_alias("visible"))
196+
.arg(Arg::with_name("flg")
197+
.long("flag")
198+
.short("f")
199+
.help("flag with aliases")
200+
.visible_aliases(&["v_flg", "flag2", "flg3"])));
134201
test::check_subcommand_help(app, "test", SC_VISIBLE_ALIAS_HELP);
135202
}
136-
137-
#[test]
138-
fn visible_arg_flag_aliases() {
139-
let a = App::new("test")
140-
.arg(Arg::with_name("opt")
141-
.long("opt")
142-
.aliases(&["invisible", "set", "of", "aliases"]))
143-
.get_matches_from_safe(vec!["", "--aliases"]);
144-
assert!(a.is_ok());
145-
let a = a.unwrap();
146-
assert!(a.is_present("opt"));
147-
}

0 commit comments

Comments
 (0)