feat: allows distinguishing between short and long version messages (-V/short or --version/long)

One can now use `App::long_version` to dsiplay a different (presumably
longer) message when `--version` is called. This commit also adds the
corresponding print/write long version methods of `App`
This commit is contained in:
Kevin K 2017-04-05 00:34:29 -04:00
parent d82b4be5d7
commit 59272b06cc
3 changed files with 168 additions and 119 deletions

View file

@ -6,6 +6,7 @@ pub struct AppMeta<'b> {
pub bin_name: Option<String>, pub bin_name: Option<String>,
pub author: Option<&'b str>, pub author: Option<&'b str>,
pub version: Option<&'b str>, pub version: Option<&'b str>,
pub long_version: Option<&'b str>,
pub about: Option<&'b str>, pub about: Option<&'b str>,
pub long_about: Option<&'b str>, pub long_about: Option<&'b str>,
pub more_help: Option<&'b str>, pub more_help: Option<&'b str>,

View file

@ -310,7 +310,10 @@ impl<'a, 'b> App<'a, 'b> {
} }
/// Sets a string of the version number to be displayed when displaying version or help /// Sets a string of the version number to be displayed when displaying version or help
/// information. /// information with `-V`.
///
/// **NOTE:** If only `version` is provided, and not [`App::long_version`] but the user
/// requests `--version` clap will still display the contents of `version` appropriately
/// ///
/// **Pro-tip:** Use `clap`s convenience macro [`crate_version!`] to automatically set your /// **Pro-tip:** Use `clap`s convenience macro [`crate_version!`] to automatically set your
/// application's version to the same thing as your crate at compile time. See the [`examples/`] /// application's version to the same thing as your crate at compile time. See the [`examples/`]
@ -326,11 +329,43 @@ impl<'a, 'b> App<'a, 'b> {
/// ``` /// ```
/// [`crate_version!`]: ./macro.crate_version!.html /// [`crate_version!`]: ./macro.crate_version!.html
/// [`examples/`]: https://github.com/kbknapp/clap-rs/tree/master/examples /// [`examples/`]: https://github.com/kbknapp/clap-rs/tree/master/examples
/// [`App::long_version`]: ./struct.App.html#method.long_version
pub fn version<S: Into<&'b str>>(mut self, ver: S) -> Self { pub fn version<S: Into<&'b str>>(mut self, ver: S) -> Self {
self.p.meta.version = Some(ver.into()); self.p.meta.version = Some(ver.into());
self self
} }
/// Sets a string of the version number to be displayed when displaying version or help
/// information with `--version`.
///
/// **NOTE:** If only `long_version` is provided, and not [`App::version`] but the user
/// requests `-V` clap will still display the contents of `long_version` appropriately
///
/// **Pro-tip:** Use `clap`s convenience macro [`crate_version!`] to automatically set your
/// application's version to the same thing as your crate at compile time. See the [`examples/`]
/// directory for more information
///
/// # Examples
///
/// ```no_run
/// # use clap::{App, Arg};
/// App::new("myprog")
/// .long_version(
/// "v0.1.24
/// commit: abcdef89726d
/// revision: 123
/// release: 2
/// binary: myprog")
/// # ;
/// ```
/// [`crate_version!`]: ./macro.crate_version!.html
/// [`examples/`]: https://github.com/kbknapp/clap-rs/tree/master/examples
/// [`App::version`]: ./struct.App.html#method.version
pub fn long_version<S: Into<&'b str>>(mut self, ver: S) -> Self {
self.p.meta.long_version = Some(ver.into());
self
}
/// Sets a custom usage string to override the auto-generated usage string. /// Sets a custom usage string to override the auto-generated usage string.
/// ///
/// This will be displayed to the user when errors are found in argument parsing, or when you /// This will be displayed to the user when errors are found in argument parsing, or when you
@ -1217,7 +1252,10 @@ impl<'a, 'b> App<'a, 'b> {
Help::write_app_help(w, self, true) Help::write_app_help(w, self, true)
} }
/// Writes the version message to the user to a [`io::Write`] object /// Writes the version message to the user to a [`io::Write`] object as if the user ran `-V`.
///
/// **NOTE:** clap has the ability to distinguish between "short" and "long" version messages
/// depending on if the user ran [`-V` (short)] or [`--version` (long)]
/// ///
/// # Examples /// # Examples
/// ///
@ -1229,10 +1267,32 @@ impl<'a, 'b> App<'a, 'b> {
/// app.write_version(&mut out).expect("failed to write to stdout"); /// app.write_version(&mut out).expect("failed to write to stdout");
/// ``` /// ```
/// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
/// [`-V` (short)]: ./struct.App.html#method.version
/// [`--version` (long)]: ./struct.App.html#method.long_version
pub fn write_version<W: Write>(&self, w: &mut W) -> ClapResult<()> { pub fn write_version<W: Write>(&self, w: &mut W) -> ClapResult<()> {
self.p.write_version(w).map_err(From::from) self.p.write_version(w, false).map_err(From::from)
} }
/// Writes the version message to the user to a [`io::Write`] object
///
/// **NOTE:** clap has the ability to distinguish between "short" and "long" version messages
/// depending on if the user ran [`-V` (short)] or [`--version` (long)]
///
/// # Examples
///
/// ```rust
/// # use clap::App;
/// use std::io;
/// let mut app = App::new("myprog");
/// let mut out = io::stdout();
/// app.write_long_version(&mut out).expect("failed to write to stdout");
/// ```
/// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
/// [`-V` (short)]: ./struct.App.html#method.version
/// [`--version` (long)]: ./struct.App.html#method.long_version
pub fn write_long_version<W: Write>(&self, w: &mut W) -> ClapResult<()> {
self.p.write_version(w, true).map_err(From::from)
}
/// Generate a completions file for a specified shell at compile time. /// Generate a completions file for a specified shell at compile time.
/// ///

View file

@ -63,7 +63,10 @@ impl<'a, 'b> Parser<'a, 'b>
where 'a: 'b where 'a: 'b
{ {
pub fn with_name(n: String) -> Self { pub fn with_name(n: String) -> Self {
Parser { meta: AppMeta::with_name(n), ..Default::default() } Parser {
meta: AppMeta::with_name(n),
..Default::default()
}
} }
pub fn help_short(&mut self, s: &str) { pub fn help_short(&mut self, s: &str) {
@ -98,11 +101,7 @@ impl<'a, 'b> Parser<'a, 'b>
use std::error::Error; use std::error::Error;
let out_dir = PathBuf::from(od); let out_dir = PathBuf::from(od);
let name = &*self.meta let name = &*self.meta.bin_name.as_ref().unwrap().clone();
.bin_name
.as_ref()
.unwrap()
.clone();
let file_name = match for_shell { let file_name = match for_shell {
Shell::Bash => format!("{}.bash-completion", name), Shell::Bash => format!("{}.bash-completion", name),
Shell::Fish => format!("{}.fish", name), Shell::Fish => format!("{}.fish", name),
@ -146,7 +145,9 @@ impl<'a, 'b> Parser<'a, 'b>
global and required", global and required",
a.b.name); a.b.name);
if a.b.is_set(ArgSettings::Last) { if a.b.is_set(ArgSettings::Last) {
assert!(!self.positionals.values().any(|p| p.b.is_set(ArgSettings::Last)), assert!(!self.positionals
.values()
.any(|p| p.b.is_set(ArgSettings::Last)),
"Only one positional argument may have last(true) set. Found two."); "Only one positional argument may have last(true) set. Found two.");
assert!(a.s.long.is_none(), assert!(a.s.long.is_none(),
"Flags or Options may not have last(true) set. {} has both a long and last(true) set.", "Flags or Options may not have last(true) set. {} has both a long and last(true) set.",
@ -190,7 +191,10 @@ impl<'a, 'b> Parser<'a, 'b>
if a.is_set(ArgSettings::Required) { if a.is_set(ArgSettings::Required) {
// If the arg is required, add all it's requirements to master required list // If the arg is required, add all it's requirements to master required list
if let Some(ref areqs) = a.b.requires { if let Some(ref areqs) = a.b.requires {
for name in areqs.iter().filter(|&&(val, _)| val.is_none()).map(|&(_, name)| name) { for name in areqs
.iter()
.filter(|&&(val, _)| val.is_none())
.map(|&(_, name)| name) {
self.required.push(name); self.required.push(name);
} }
} }
@ -232,7 +236,8 @@ impl<'a, 'b> Parser<'a, 'b>
} else { } else {
a.index.unwrap() as usize a.index.unwrap() as usize
}; };
self.positionals.insert(i, PosBuilder::from_arg(a, i as u64)); self.positionals
.insert(i, PosBuilder::from_arg(a, i as u64));
} else if a.is_set(ArgSettings::TakesValue) { } else if a.is_set(ArgSettings::TakesValue) {
let mut ob = OptBuilder::from(a); let mut ob = OptBuilder::from(a);
ob.s.unified_ord = self.flags.len() + self.opts.len(); ob.s.unified_ord = self.flags.len() + self.opts.len();
@ -326,11 +331,7 @@ impl<'a, 'b> Parser<'a, 'b>
if vsc { if vsc {
sc.p.set(AS::DisableVersion); sc.p.set(AS::DisableVersion);
} }
if gv && if gv && sc.p.meta.version.is_none() && self.meta.version.is_some() {
sc.p
.meta
.version
.is_none() && self.meta.version.is_some() {
sc.p.set(AS::GlobalVersion); sc.p.set(AS::GlobalVersion);
sc.p.meta.version = Some(self.meta.version.unwrap()); sc.p.meta.version = Some(self.meta.version.unwrap());
} }
@ -404,7 +405,9 @@ impl<'a, 'b> Parser<'a, 'b>
if self.flags.is_empty() { if self.flags.is_empty() {
return false; return false;
} }
self.flags.iter().any(|f| !f.is_set(ArgSettings::Hidden)) self.flags
.iter()
.any(|f| !f.is_set(ArgSettings::Hidden))
} }
#[inline] #[inline]
@ -412,7 +415,9 @@ impl<'a, 'b> Parser<'a, 'b>
if self.positionals.is_empty() { if self.positionals.is_empty() {
return false; return false;
} }
self.positionals.values().any(|p| !p.is_set(ArgSettings::Hidden)) self.positionals
.values()
.any(|p| !p.is_set(ArgSettings::Hidden))
} }
#[inline] #[inline]
@ -440,10 +445,7 @@ impl<'a, 'b> Parser<'a, 'b>
// Firt we verify that the index highest supplied index, is equal to the number of // Firt we verify that the index highest supplied index, is equal to the number of
// positional arguments to verify there are no gaps (i.e. supplying an index of 1 and 3 // positional arguments to verify there are no gaps (i.e. supplying an index of 1 and 3
// but no 2) // but no 2)
if let Some((idx, p)) = self.positionals if let Some((idx, p)) = self.positionals.iter().rev().next() {
.iter()
.rev()
.next() {
assert!(!(idx != self.positionals.len()), assert!(!(idx != self.positionals.len()),
"Found positional argument \"{}\" who's index is {} but there \ "Found positional argument \"{}\" who's index is {} but there \
are only {} positional arguments defined", are only {} positional arguments defined",
@ -453,10 +455,12 @@ impl<'a, 'b> Parser<'a, 'b>
} }
// Next we verify that only the highest index has a .multiple(true) (if any) // Next we verify that only the highest index has a .multiple(true) (if any)
if self.positionals.values().any(|a| { if self.positionals
a.b.is_set(ArgSettings::Multiple) && .values()
(a.index as usize != self.positionals.len()) .any(|a| {
}) { a.b.is_set(ArgSettings::Multiple) &&
(a.index as usize != self.positionals.len())
}) {
let mut it = self.positionals.values().rev(); let mut it = self.positionals.values().rev();
let last = it.next().unwrap(); let last = it.next().unwrap();
let second_to_last = it.next().unwrap(); let second_to_last = it.next().unwrap();
@ -542,10 +546,11 @@ impl<'a, 'b> Parser<'a, 'b>
} }
} }
} }
if self.positionals.values().any(|p| { if self.positionals
p.b.is_set(ArgSettings::Last) && .values()
p.b.is_set(ArgSettings::Required) .any(|p| {
}) && self.has_subcommands() && p.b.is_set(ArgSettings::Last) && p.b.is_set(ArgSettings::Required)
}) && self.has_subcommands() &&
!self.is_set(AS::SubcommandsNegateReqs) { !self.is_set(AS::SubcommandsNegateReqs) {
panic!("Having a required positional argument with .last(true) set *and* child \ panic!("Having a required positional argument with .last(true) set *and* child \
subcommands without setting SubcommandsNegateReqs isn't compatible."); subcommands without setting SubcommandsNegateReqs isn't compatible.");
@ -594,10 +599,7 @@ impl<'a, 'b> Parser<'a, 'b>
.iter() .iter()
.filter(|s| { .filter(|s| {
starts(&s.p.meta.name[..], &*arg_os) || starts(&s.p.meta.name[..], &*arg_os) ||
(s.p (s.p.meta.aliases.is_some() &&
.meta
.aliases
.is_some() &&
s.p s.p
.meta .meta
.aliases .aliases
@ -750,11 +752,16 @@ impl<'a, 'b> Parser<'a, 'b>
debugln!("Parser::get_matches_with;"); debugln!("Parser::get_matches_with;");
// Verify all positional assertions pass // Verify all positional assertions pass
debug_assert!(self.verify_positionals()); debug_assert!(self.verify_positionals());
if self.positionals.values().any(|a| { if self.positionals
a.b.is_set(ArgSettings::Multiple) && .values()
(a.index as usize != self.positionals.len()) .any(|a| {
}) && a.b.is_set(ArgSettings::Multiple) &&
self.positionals.values().last().map_or(false, |p| !p.is_set(ArgSettings::Last)) { (a.index as usize != self.positionals.len())
}) &&
self.positionals
.values()
.last()
.map_or(false, |p| !p.is_set(ArgSettings::Last)) {
self.settings.set(AS::LowIndexMultiplePositional); self.settings.set(AS::LowIndexMultiplePositional);
} }
let has_args = self.has_args(); let has_args = self.has_args();
@ -843,7 +850,8 @@ impl<'a, 'b> Parser<'a, 'b>
!self.is_set(AS::InferSubcommands) { !self.is_set(AS::InferSubcommands) {
if let Some(cdate) = suggestions::did_you_mean(&*arg_os.to_string_lossy(), if let Some(cdate) = suggestions::did_you_mean(&*arg_os.to_string_lossy(),
sc_names!(self)) { sc_names!(self)) {
return Err(Error::invalid_subcommand(arg_os.to_string_lossy() return Err(Error::invalid_subcommand(arg_os
.to_string_lossy()
.into_owned(), .into_owned(),
cdate, cdate,
self.meta self.meta
@ -962,7 +970,8 @@ impl<'a, 'b> Parser<'a, 'b>
None), None),
self.color())); self.color()));
} else { } else {
return Err(Error::unrecognized_subcommand(arg_os.to_string_lossy() return Err(Error::unrecognized_subcommand(arg_os
.to_string_lossy()
.into_owned(), .into_owned(),
self.meta self.meta
.bin_name .bin_name
@ -984,10 +993,7 @@ impl<'a, 'b> Parser<'a, 'b>
}; };
try!(self.parse_subcommand(&*sc_name, matcher, it)); try!(self.parse_subcommand(&*sc_name, matcher, it));
} else if self.is_set(AS::SubcommandRequired) { } else if self.is_set(AS::SubcommandRequired) {
let bn = self.meta let bn = self.meta.bin_name.as_ref().unwrap_or(&self.meta.name);
.bin_name
.as_ref()
.unwrap_or(&self.meta.name);
return Err(Error::missing_subcommand(bn, return Err(Error::missing_subcommand(bn,
&usage::create_error_usage(self, matcher, None), &usage::create_error_usage(self, matcher, None),
self.color())); self.color()));
@ -1018,10 +1024,7 @@ impl<'a, 'b> Parser<'a, 'b>
debugln!("Parser::build_bin_names;"); debugln!("Parser::build_bin_names;");
for sc in &mut self.subcommands { for sc in &mut self.subcommands {
debug!("Parser::build_bin_names:iter: bin_name set..."); debug!("Parser::build_bin_names:iter: bin_name set...");
if sc.p if sc.p.meta.bin_name.is_none() {
.meta
.bin_name
.is_none() {
sdebugln!("No"); sdebugln!("No");
let bin_name = format!("{}{}{}", let bin_name = format!("{}{}{}",
self.meta self.meta
@ -1059,10 +1062,7 @@ impl<'a, 'b> Parser<'a, 'b>
debugln!("Parser::parse_subcommand;"); debugln!("Parser::parse_subcommand;");
let mut mid_string = String::new(); let mut mid_string = String::new();
if !self.is_set(AS::SubcommandsNegateReqs) { if !self.is_set(AS::SubcommandsNegateReqs) {
let mut hs: Vec<&str> = self.required let mut hs: Vec<&str> = self.required.iter().map(|n| &**n).collect();
.iter()
.map(|n| &**n)
.collect();
for k in matcher.arg_names() { for k in matcher.arg_names() {
hs.push(k); hs.push(k);
} }
@ -1073,41 +1073,35 @@ impl<'a, 'b> Parser<'a, 'b>
} }
} }
mid_string.push_str(" "); mid_string.push_str(" ");
if let Some(ref mut sc) = self.subcommands.iter_mut().find(|s| &s.p.meta.name == &sc_name) { if let Some(ref mut sc) = self.subcommands
.iter_mut()
.find(|s| &s.p.meta.name == &sc_name) {
let mut sc_matcher = ArgMatcher::new(); let mut sc_matcher = ArgMatcher::new();
// bin_name should be parent's bin_name + [<reqs>] + the sc's name separated by // bin_name should be parent's bin_name + [<reqs>] + the sc's name separated by
// a space // a space
sc.p.meta.usage = Some(format!("{}{}{}", sc.p.meta.usage = Some(format!("{}{}{}",
self.meta self.meta.bin_name.as_ref().unwrap_or(&String::new()),
.bin_name
.as_ref()
.unwrap_or(&String::new()),
if self.meta.bin_name.is_some() { if self.meta.bin_name.is_some() {
&*mid_string &*mid_string
} else { } else {
"" ""
}, },
&*sc.p.meta.name)); &*sc.p.meta.name));
sc.p.meta.bin_name = Some(format!("{}{}{}", sc.p.meta.bin_name =
self.meta Some(format!("{}{}{}",
.bin_name self.meta.bin_name.as_ref().unwrap_or(&String::new()),
.as_ref() if self.meta.bin_name.is_some() {
.unwrap_or(&String::new()), " "
if self.meta.bin_name.is_some() { } else {
" " ""
} else { },
"" &*sc.p.meta.name));
},
&*sc.p.meta.name));
debugln!("Parser::parse_subcommand: About to parse sc={}", debugln!("Parser::parse_subcommand: About to parse sc={}",
sc.p.meta.name); sc.p.meta.name);
debugln!("Parser::parse_subcommand: sc settings={:#?}", sc.p.settings); debugln!("Parser::parse_subcommand: sc settings={:#?}", sc.p.settings);
try!(sc.p.get_matches_with(&mut sc_matcher, it)); try!(sc.p.get_matches_with(&mut sc_matcher, it));
matcher.subcommand(SubCommand { matcher.subcommand(SubCommand {
name: sc.p name: sc.p.meta.name.clone(),
.meta
.name
.clone(),
matches: sc_matcher.into(), matches: sc_matcher.into(),
}); });
} }
@ -1218,7 +1212,8 @@ impl<'a, 'b> Parser<'a, 'b>
let arg = FlagBuilder { let arg = FlagBuilder {
b: Base { b: Base {
name: "vclap_version", name: "vclap_version",
help: self.version_message.or(Some("Prints version information")), help: self.version_message
.or(Some("Prints version information")),
..Default::default() ..Default::default()
}, },
s: Switched { s: Switched {
@ -1250,7 +1245,7 @@ impl<'a, 'b> Parser<'a, 'b>
} }
if arg == "version" && self.is_set(AS::NeedsLongVersion) { if arg == "version" && self.is_set(AS::NeedsLongVersion) {
sdebugln!("Version"); sdebugln!("Version");
try!(self._version()); try!(self._version(true));
} }
sdebugln!("Neither"); sdebugln!("Neither");
@ -1270,7 +1265,7 @@ impl<'a, 'b> Parser<'a, 'b>
if let Some(v) = self.version_short { if let Some(v) = self.version_short {
if arg == v && self.is_set(AS::NeedsLongVersion) { if arg == v && self.is_set(AS::NeedsLongVersion) {
sdebugln!("Version"); sdebugln!("Version");
try!(self._version()); try!(self._version(false));
} }
} }
sdebugln!("Neither"); sdebugln!("Neither");
@ -1279,9 +1274,13 @@ impl<'a, 'b> Parser<'a, 'b>
fn use_long_help(&self) -> bool { fn use_long_help(&self) -> bool {
let ul = self.flags.iter().any(|f| f.b.long_help.is_some()) || let ul = self.flags.iter().any(|f| f.b.long_help.is_some()) ||
self.opts.iter().any(|o| o.b.long_help.is_some()) || self.opts.iter().any(|o| o.b.long_help.is_some()) ||
self.positionals.values().any(|p| p.b.long_help.is_some()) || self.positionals
self.subcommands.iter().any(|s| s.p.meta.long_about.is_some()); .values()
.any(|p| p.b.long_help.is_some()) ||
self.subcommands
.iter()
.any(|s| s.p.meta.long_about.is_some());
debugln!("Parser::use_long_help: ret={:?}", ul); debugln!("Parser::use_long_help: ret={:?}", ul);
ul ul
} }
@ -1298,11 +1297,11 @@ impl<'a, 'b> Parser<'a, 'b>
}) })
} }
fn _version(&self) -> ClapResult<()> { fn _version(&self, use_long: bool) -> ClapResult<()> {
debugln!("Parser::_version: "); debugln!("Parser::_version: ");
let out = io::stdout(); let out = io::stdout();
let mut buf_w = BufWriter::new(out.lock()); let mut buf_w = BufWriter::new(out.lock());
try!(self.print_version(&mut buf_w)); try!(self.print_version(&mut buf_w, use_long));
Err(Error { Err(Error {
message: String::new(), message: String::new(),
kind: ErrorKind::VersionDisplayed, kind: ErrorKind::VersionDisplayed,
@ -1363,7 +1362,8 @@ impl<'a, 'b> Parser<'a, 'b>
} }
debugln!("Parser::parse_long_arg: Didn't match anything"); debugln!("Parser::parse_long_arg: Didn't match anything");
self.did_you_mean_error(arg.to_str().expect(INVALID_UTF8), matcher).map(|_| None) self.did_you_mean_error(arg.to_str().expect(INVALID_UTF8), matcher)
.map(|_| None)
} }
#[cfg_attr(feature = "lints", allow(len_zero))] #[cfg_attr(feature = "lints", allow(len_zero))]
@ -1489,7 +1489,8 @@ impl<'a, 'b> Parser<'a, 'b>
matcher.inc_occurrence_of(opt.b.name); matcher.inc_occurrence_of(opt.b.name);
// Increment or create the group "args" // Increment or create the group "args"
self.groups_for_arg(opt.b.name).and_then(|vec| Some(matcher.inc_occurrences_of(&*vec))); self.groups_for_arg(opt.b.name)
.and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));
if val.is_none() || if val.is_none() ||
!has_eq && !has_eq &&
@ -1575,7 +1576,8 @@ impl<'a, 'b> Parser<'a, 'b>
matcher.inc_occurrence_of(flag.b.name); matcher.inc_occurrence_of(flag.b.name);
// Increment or create the group "args" // Increment or create the group "args"
self.groups_for_arg(flag.b.name).and_then(|vec| Some(matcher.inc_occurrences_of(&*vec))); self.groups_for_arg(flag.b.name)
.and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));
Ok(()) Ok(())
} }
@ -1608,30 +1610,30 @@ impl<'a, 'b> Parser<'a, 'b>
} }
// Prints the version to the user and exits if quit=true // Prints the version to the user and exits if quit=true
fn print_version<W: Write>(&self, w: &mut W) -> ClapResult<()> { fn print_version<W: Write>(&self, w: &mut W, use_long: bool) -> ClapResult<()> {
try!(self.write_version(w)); try!(self.write_version(w, use_long));
w.flush().map_err(Error::from) w.flush().map_err(Error::from)
} }
pub fn write_version<W: Write>(&self, w: &mut W) -> io::Result<()> { pub fn write_version<W: Write>(&self, w: &mut W, use_long: bool) -> io::Result<()> {
let ver = if use_long {
self.meta
.long_version
.unwrap_or(self.meta.version.unwrap_or("".into()))
} else {
self.meta
.version
.unwrap_or(self.meta.long_version.unwrap_or("".into()))
};
if let Some(bn) = self.meta.bin_name.as_ref() { if let Some(bn) = self.meta.bin_name.as_ref() {
if bn.contains(' ') { if bn.contains(' ') {
// Incase we're dealing with subcommands i.e. git mv is translated to git-mv // Incase we're dealing with subcommands i.e. git mv is translated to git-mv
write!(w, write!(w, "{} {}", bn.replace(" ", "-"), ver)
"{} {}",
bn.replace(" ", "-"),
self.meta.version.unwrap_or("".into()))
} else { } else {
write!(w, write!(w, "{} {}", &self.meta.name[..], ver)
"{} {}",
&self.meta.name[..],
self.meta.version.unwrap_or("".into()))
} }
} else { } else {
write!(w, write!(w, "{} {}", &self.meta.name[..], ver)
"{} {}",
&self.meta.name[..],
self.meta.version.unwrap_or("".into()))
} }
} }
@ -1753,20 +1755,10 @@ impl<'a, 'b> Parser<'a, 'b>
pub fn find_subcommand(&'b self, sc: &str) -> Option<&'b App<'a, 'b>> { pub fn find_subcommand(&'b self, sc: &str) -> Option<&'b App<'a, 'b>> {
debugln!("Parser::find_subcommand: sc={}", sc); debugln!("Parser::find_subcommand: sc={}", sc);
debugln!("Parser::find_subcommand: Currently in Parser...{}", debugln!("Parser::find_subcommand: Currently in Parser...{}",
self.meta self.meta.bin_name.as_ref().unwrap());
.bin_name
.as_ref()
.unwrap());
for s in self.subcommands.iter() { for s in self.subcommands.iter() {
if s.p if s.p.meta.bin_name.as_ref().unwrap_or(&String::new()) == sc ||
.meta (s.p.meta.aliases.is_some() &&
.bin_name
.as_ref()
.unwrap_or(&String::new()) == sc ||
(s.p
.meta
.aliases
.is_some() &&
s.p s.p
.meta .meta
.aliases .aliases
@ -1774,12 +1766,8 @@ impl<'a, 'b> Parser<'a, 'b>
.unwrap() .unwrap()
.iter() .iter()
.any(|&(s, _)| { .any(|&(s, _)| {
s == s == sc.split(' ').rev().next().expect(INTERNAL_ERROR_MSG)
sc.split(' ') })) {
.rev()
.next()
.expect(INTERNAL_ERROR_MSG)
})) {
return Some(s); return Some(s);
} }
if let Some(app) = s.p.find_subcommand(sc) { if let Some(app) = s.p.find_subcommand(sc) {