fix: long_flag_aliases instead of using alias

Previously long_flag alias checks were against normal aliases instead of
specifically designated long_flag aliases, this is more clear and explicit.
This commit is contained in:
NickHackman 2020-07-10 09:27:14 -04:00
parent f5aabfa482
commit 5118cec1b1
2 changed files with 149 additions and 12 deletions

View file

@ -84,6 +84,7 @@ pub struct App<'b> {
pub(crate) after_help: Option<&'b str>,
pub(crate) aliases: Vec<(&'b str, bool)>, // (name, visible)
pub(crate) short_flag_aliases: Vec<(char, bool)>, // (name, visible)
pub(crate) long_flag_aliases: Vec<(&'b str, bool)>, // (name, visible)
pub(crate) usage_str: Option<&'b str>,
pub(crate) usage: Option<String>,
pub(crate) help_str: Option<&'b str>,
@ -151,6 +152,15 @@ impl<'b> App<'b> {
.map(|a| a.0)
}
/// Iterate through the *visible* short aliases for this subcommand.
#[inline]
pub fn get_visible_long_flag_aliases(&self) -> impl Iterator<Item = &'b str> + '_ {
self.long_flag_aliases
.iter()
.filter(|(_, vis)| *vis)
.map(|a| a.0)
}
/// Iterate through the set of *all* the aliases for this subcommand, both visible and hidden.
#[inline]
pub fn get_all_aliases(&self) -> impl Iterator<Item = &str> {
@ -163,6 +173,12 @@ impl<'b> App<'b> {
self.short_flag_aliases.iter().map(|a| a.0)
}
/// Iterate through the set of *all* the long aliases for this subcommand, both visible and hidden.
#[inline]
pub fn get_all_long_flag_aliases(&self) -> impl Iterator<Item = &'b str> + '_ {
self.long_flag_aliases.iter().map(|a| a.0)
}
/// Get the list of subcommands
#[inline]
pub fn get_subcommands(&self) -> impl Iterator<Item = &App<'b>> {
@ -913,7 +929,7 @@ impl<'b> App<'b> {
/// let m = App::new("myprog")
/// .subcommand(App::new("test").short_flag('t')
/// .short_flag_alias('d'))
/// .get_matches_from(vec!["myprog", "d"]);
/// .get_matches_from(vec!["myprog", "-d"]);
/// assert_eq!(m.subcommand_name(), Some("test"));
/// ```
pub fn short_flag_alias(mut self, name: char) -> Self {
@ -924,6 +940,26 @@ impl<'b> App<'b> {
self
}
/// Allows adding an alias, which function as "hidden" long flag subcommands that
/// automatically dispatch as if this subcommand was used. This is more efficient, and easier
/// than creating multiple hidden subcommands as one only needs to check for the existence of
/// this command, and not all variants.
///
/// # Examples
///
/// ```no_run
/// # use clap::{App, Arg, };
/// let m = App::new("myprog")
/// .subcommand(App::new("test").long_flag('t')
/// .long_flag_alias("testing"))
/// .get_matches_from(vec!["myprog", "--testing"]);
/// assert_eq!(m.subcommand_name(), Some("test"));
/// ```
pub fn long_flag_alias(mut self, name: &'b str) -> Self {
self.long_flag_aliases.push((name, false));
self
}
/// Allows adding [``] aliases, which function as "hidden" subcommands that
/// automatically dispatch as if this subcommand was used. This is more efficient, and easier
/// than creating multiple hidden subcommands as one only needs to check for the existence of
@ -978,6 +1014,32 @@ impl<'b> App<'b> {
self
}
/// Allows adding aliases, which function as "hidden" long flag subcommands that
/// automatically dispatch as if this subcommand was used. This is more efficient, and easier
/// than creating multiple hidden subcommands as one only needs to check for the existence of
/// this command, and not all variants.
///
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg, };
/// let m = App::new("myprog")
/// .subcommand(App::new("test").long_flag("test")
/// .long_flag_aliases(&["testing", "testall", "test_all"]))
/// .arg(Arg::new("input")
/// .about("the file to add")
/// .index(1)
/// .required(false))
/// .get_matches_from(vec!["myprog", "--testing"]);
/// assert_eq!(m.subcommand_name(), Some("test"));
/// ```
pub fn long_flag_aliases(mut self, names: &[&'b str]) -> Self {
for s in names {
self.long_flag_aliases.push((s, false));
}
self
}
/// Allows adding a [``] alias that functions exactly like those defined with
/// [`App::alias`], except that they are visible inside the help message.
///
@ -1020,6 +1082,25 @@ impl<'b> App<'b> {
self
}
/// Allows adding an alias that functions exactly like those defined with
/// [`App::long_flag_alias`], except that they are visible inside the help message.
///
/// # Examples
///
/// ```no_run
/// # use clap::{App, Arg, };
/// let m = App::new("myprog")
/// .subcommand(App::new("test").long_flag("test")
/// .visible_long_flag_alias("testing"))
/// .get_matches_from(vec!["myprog", "--testing"]);
/// assert_eq!(m.subcommand_name(), Some("test"));
/// ```
/// [`App::long_flag_alias`]: ./struct.App.html#method.long_flag_alias
pub fn visible_long_flag_alias(mut self, name: &'b str) -> Self {
self.long_flag_aliases.push((name, true));
self
}
/// Allows adding multiple [``] aliases that functions exactly like those defined
/// with [`App::aliases`], except that they are visible inside the help message.
///
@ -1064,6 +1145,27 @@ impl<'b> App<'b> {
self
}
/// Allows adding multiple long flag aliases that functions exactly like those defined
/// with [`App::long_flag_aliases`], except that they are visible inside the help message.
///
/// # Examples
///
/// ```no_run
/// # use clap::{App, Arg, };
/// let m = App::new("myprog")
/// .subcommand(App::new("test").long_flag("test")
/// .visible_long_flag_aliases(&["testing", "testall", "test_all"]))
/// .get_matches_from(vec!["myprog", "--testing"]);
/// assert_eq!(m.subcommand_name(), Some("test"));
/// ```
/// [`App::short_flag_aliases`]: ./struct.App.html#method.short_flag_aliases
pub fn visible_long_flag_aliases(mut self, names: &[&'b str]) -> Self {
for s in names {
self.long_flag_aliases.push((s, true));
}
self
}
/// Replaces an argument to this application with other arguments.
///
/// Below, when the given args are `app install`, they will be changed to `app module install`.
@ -2301,6 +2403,29 @@ impl<'b> App<'b> {
*name == *self.get_name() || self.get_all_aliases().any(|alias| *name == *alias)
}
/// Check if this subcommand can be referred to as `name`. In other words,
/// check if `name` is the name of this short flag subcommand or is one of its short flag aliases.
#[inline]
pub(crate) fn short_flag_aliases_to(&self, flag: char) -> bool {
Some(flag) == self.short_flag
|| self.get_all_short_flag_aliases().any(|alias| flag == alias)
}
/// Check if this subcommand can be referred to as `name`. In other words,
/// check if `name` is the name of this long flag subcommand or is one of its long flag aliases.
#[inline]
pub(crate) fn long_flag_aliases_to<T>(&self, flag: &T) -> bool
where
T: PartialEq<str> + ?Sized,
{
match self.long_flag {
Some(long_flag) => {
flag == long_flag || self.get_all_long_flag_aliases().any(|alias| flag == alias)
}
None => self.get_all_long_flag_aliases().any(|alias| flag == alias),
}
}
#[cfg(debug_assertions)]
pub(crate) fn id_exists(&self, id: &Id) -> bool {
self.args.args.iter().any(|x| x.id == *id) || self.groups.iter().any(|x| x.id == *id)
@ -2401,22 +2526,14 @@ impl<'b> App<'b> {
/// Find a flag subcommand name by short flag or an alias
pub(crate) fn find_short_subcmd(&self, c: char) -> Option<&str> {
self.get_subcommands()
.find(|sc| {
sc.short_flag == Some(c) || sc.get_all_short_flag_aliases().any(|alias| alias == c)
})
.find(|sc| sc.short_flag_aliases_to(c))
.map(|sc| sc.get_name())
}
/// Find a flag subcommand name by long flag or an alias
pub(crate) fn find_long_subcmd(&self, long: &ArgStr<'_>) -> Option<&str> {
self.get_subcommands()
.find(|sc| {
if let Some(sc_long) = sc.long_flag {
*long == sc_long || sc.aliases_to(long)
} else {
false
}
})
.find(|sc| sc.long_flag_aliases_to(long))
.map(|sc| sc.get_name())
}
}

View file

@ -207,7 +207,27 @@ fn flag_subcommand_long_with_alias() {
.long("test")
.about("testing testing"),
)
.alias("result"),
.long_flag_alias("result"),
)
.get_matches_from(vec!["myprog", "--result", "--test"]);
assert_eq!(matches.subcommand_name().unwrap(), "some");
let sub_matches = matches.subcommand_matches("some").unwrap();
assert!(sub_matches.is_present("test"));
}
#[test]
fn flag_subcommand_long_with_aliases() {
let matches = App::new("test")
.subcommand(
App::new("some")
.long_flag("some")
.arg(
Arg::new("test")
.short('t')
.long("test")
.about("testing testing"),
)
.long_flag_aliases(&["result", "someall"]),
)
.get_matches_from(vec!["myprog", "--result", "--test"]);
assert_eq!(matches.subcommand_name().unwrap(), "some");