Skip to content

Commit

Permalink
feat(Subcommands): adds support for visible aliases
Browse files Browse the repository at this point in the history
This commit adds support for visible aliases, which function exactly like aliases except that they
also appear in the help message, using the help string of the aliased subcommand.

i.e.

```rust
App::new("myprog")
    .subcommand(SubCommand::with_name("test")
		.about("does testy things")
		.alias("invisible")
		.visible_alias("visible"));
```

When run with `myprog --help`, the output is:

```
myprog

USAGE:
	myprog [FLAGS] [SUBCOMMAND]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    help	        Prints this message or the help of the given subcommand(s)
    test|visible    does testy things
```

Closes #522
  • Loading branch information
kbknapp committed Jun 10, 2016
1 parent 5354d14 commit 7b10e7f
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 10 deletions.
19 changes: 17 additions & 2 deletions src/app/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -548,9 +548,24 @@ impl<'a> Help<'a> {

let mut ord_m = VecMap::new();
for sc in parser.subcommands.iter().filter(|s| !s.p.is_set(AppSettings::Hidden)) {
let sc = if let Some(ref aliases) = sc.p.meta.aliases {
let mut a = App::new(format!("{}|{}", &*sc.p.meta.name, aliases.iter()
.filter(|&&(_, vis)| vis)
.map(|&(n, _)| n)
.collect::<Vec<_>>()
.join("|")));
a = if let Some(about) = sc.p.meta.about {
a.about(about)
} else {
a
};
a
} else {
sc.clone()
};
let btm = ord_m.entry(sc.p.meta.disp_ord).or_insert(BTreeMap::new());
btm.insert(sc.p.meta.name.clone(), sc);
longest = cmp::max(longest, sc.p.meta.name.len());
btm.insert(sc.p.meta.name.clone(), sc.clone());
}

let mut first = true;
Expand All @@ -561,7 +576,7 @@ impl<'a> Help<'a> {
} else {
first = false;
}
try!(self.write_arg(sc, longest));
try!(self.write_arg(&sc, longest));
}
}
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion src/app/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub struct AppMeta<'b> {
pub about: Option<&'b str>,
pub more_help: Option<&'b str>,
pub pre_help: Option<&'b str>,
pub aliases: Option<Vec<&'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>,
Expand Down
58 changes: 54 additions & 4 deletions src/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -602,9 +602,9 @@ impl<'a, 'b> App<'a, 'b> {
/// [`SubCommand`]: ./struct.SubCommand.html
pub fn alias<S: Into<&'b str>>(mut self, name: S) -> Self {
if let Some(ref mut als) = self.p.meta.aliases {
als.push(name.into());
als.push((name.into(), false));
} else {
self.p.meta.aliases = Some(vec![name.into()]);
self.p.meta.aliases = Some(vec![(name.into(), false)]);
}
self
}
Expand Down Expand Up @@ -632,10 +632,60 @@ impl<'a, 'b> App<'a, 'b> {
pub fn aliases(mut self, names: &[&'b str]) -> Self {
if let Some(ref mut als) = self.p.meta.aliases {
for n in names {
als.push(n);
als.push((n, false));
}
} else {
self.p.meta.aliases = Some(names.iter().map(|n| *n).collect::<Vec<_>>());
self.p.meta.aliases = Some(names.iter().map(|n| (*n, false)).collect::<Vec<_>>());
}
self
}

/// Allows adding a [`SubCommand`] alias that functions exactly like those defined with
/// [`App::alias`], except that they are visible inside the help message.
///
/// # Examples
///
/// ```no_run
/// # use clap::{App, Arg, SubCommand};
/// let m = App::new("myprog")
/// .subcommand(SubCommand::with_name("test")
/// .visible_alias("do-stuff"))
/// .get_matches_from(vec!["myprog", "do-stuff"]);
/// assert_eq!(m.subcommand_name(), Some("test"));
/// ```
/// [`SubCommand`]: ./struct.SubCommand.html
/// [`App::alias`]: ./struct.App.html#method.alias
pub fn visible_alias<S: Into<&'b str>>(mut self, name: S) -> Self {
if let Some(ref mut als) = self.p.meta.aliases {
als.push((name.into(), true));
} else {
self.p.meta.aliases = Some(vec![(name.into(), true)]);
}
self
}

/// Allows adding multiple [`SubCommand`] aliases that functions exactly like those defined
/// with [`App::aliases`], except that they are visible inside the help message.
///
/// # Examples
///
/// ```no_run
/// # use clap::{App, Arg, SubCommand};
/// let m = App::new("myprog")
/// .subcommand(SubCommand::with_name("test")
/// .visible_aliases(&["do-stuff", "tests"]))
/// .get_matches_from(vec!["myprog", "do-stuff"]);
/// assert_eq!(m.subcommand_name(), Some("test"));
/// ```
/// [`SubCommand`]: ./struct.SubCommand.html
/// [`App::aliases`]: ./struct.App.html#method.aliases
pub fn visible_aliases(mut self, names: &[&'b str]) -> Self {
if let Some(ref mut als) = self.p.meta.aliases {
for n in names {
als.push((n, true));
}
} else {
self.p.meta.aliases = Some(names.iter().map(|n| (*n, true)).collect::<Vec<_>>());
}
self
}
Expand Down
6 changes: 3 additions & 3 deletions src/app/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ impl<'a, 'b> Parser<'a, 'b>
.as_ref()
.unwrap()
.iter()
.any(|&a| a == &*arg_os)));
.any(|&(a, _)| a == &*arg_os)));
if (!starts_new_arg || self.is_set(AppSettings::AllowLeadingHyphen)) && !pos_sc {
// Check to see if parsing a value from an option
if let Some(nvo) = needs_val_of {
Expand Down Expand Up @@ -537,7 +537,7 @@ impl<'a, 'b> Parser<'a, 'b>
.meta
.aliases {
als.iter()
.any(|a| a == &&*cmd.to_string_lossy())
.any(|&(a, _)| &a == &&*cmd.to_string_lossy())
} else {
false
}
Expand Down Expand Up @@ -656,7 +656,7 @@ impl<'a, 'b> Parser<'a, 'b>
.as_ref()
.unwrap()
.iter()
.any(|&a| a == &*pos_sc_name) {
.any(|&(a, _)| &a == &&*pos_sc_name) {
Some(sc.p.meta.name.clone())
} else {
None
Expand Down

0 comments on commit 7b10e7f

Please sign in to comment.