Auto merge of #525 - kbknapp:issues-521,522, r=kbknapp

Issues 521,522
This commit is contained in:
Homu 2016-06-10 19:17:44 +09:00
commit 50ca205e3b
5 changed files with 127 additions and 10 deletions

View file

@ -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;
@ -561,7 +576,7 @@ impl<'a> Help<'a> {
} else {
first = false;
}
try!(self.write_arg(sc, longest));
try!(self.write_arg(&sc, longest));
}
}
Ok(())

View file

@ -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>,

View file

@ -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
}
@ -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
}

View file

@ -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 {
@ -530,6 +530,24 @@ impl<'a, 'b> Parser<'a, 'b>
if i == cmds.len() - 1 {
break;
}
} else if let Some(c) = sc.subcommands
.iter()
.filter(|s|
if let Some(ref als) = s.p
.meta
.aliases {
als.iter()
.any(|&(a, _)| &a == &&*cmd.to_string_lossy())
} else {
false
}
)
.next()
.map(|sc| &sc.p) {
sc = c;
if i == cmds.len() - 1 {
break;
}
} else {
return Err(
Error::unrecognized_subcommand(
@ -638,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

View file

@ -3,7 +3,20 @@ extern crate regex;
include!("../clap-test.rs");
use clap::{App, Arg, SubCommand};
use clap::{App, Arg, SubCommand, ErrorKind};
static VISIBLE_ALIAS_HELP: &'static str = "clap-test 2.6
USAGE:
clap-test [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)
vim|vi Some help";
#[test]
fn subcommand() {
@ -93,3 +106,24 @@ USAGE:
For more information try --help", true);
}
#[test]
fn alias_help() {
let m = App::new("myprog")
.subcommand(SubCommand::with_name("test")
.alias("do-stuff"))
.get_matches_from_safe(vec!["myprog", "help", "do-stuff"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}
#[test]
fn visible_aliases_help_output() {
let app = App::new("clap-test")
.version("2.6")
.subcommand(SubCommand::with_name("vim")
.about("Some help")
.alias("invisible")
.visible_alias("vi"));
test::check_help(app, VISIBLE_ALIAS_HELP);
}