aboutsummaryrefslogtreecommitdiff
path: root/clap/src/app/parser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'clap/src/app/parser.rs')
-rw-r--r--clap/src/app/parser.rs2167
1 files changed, 2167 insertions, 0 deletions
diff --git a/clap/src/app/parser.rs b/clap/src/app/parser.rs
new file mode 100644
index 0000000..decfde4
--- /dev/null
+++ b/clap/src/app/parser.rs
@@ -0,0 +1,2167 @@
+// Std
+use std::ffi::{OsStr, OsString};
+use std::fmt::Display;
+use std::fs::File;
+use std::io::{self, BufWriter, Write};
+#[cfg(all(feature = "debug", not(any(target_os = "windows", target_arch = "wasm32"))))]
+use std::os::unix::ffi::OsStrExt;
+#[cfg(all(feature = "debug", any(target_os = "windows", target_arch = "wasm32")))]
+use osstringext::OsStrExt3;
+use std::path::PathBuf;
+use std::slice::Iter;
+use std::iter::Peekable;
+use std::cell::Cell;
+
+// Internal
+use INTERNAL_ERROR_MSG;
+use INVALID_UTF8;
+use SubCommand;
+use app::App;
+use app::help::Help;
+use app::meta::AppMeta;
+use app::settings::AppFlags;
+use args::{AnyArg, Arg, ArgGroup, ArgMatcher, Base, FlagBuilder, OptBuilder, PosBuilder, Switched};
+use args::settings::ArgSettings;
+use completions::ComplGen;
+use errors::{Error, ErrorKind};
+use errors::Result as ClapResult;
+use fmt::ColorWhen;
+use osstringext::OsStrExt2;
+use completions::Shell;
+use suggestions;
+use app::settings::AppSettings as AS;
+use app::validator::Validator;
+use app::usage;
+use map::{self, VecMap};
+
+#[derive(Debug, PartialEq, Copy, Clone)]
+#[doc(hidden)]
+pub enum ParseResult<'a> {
+ Flag,
+ Opt(&'a str),
+ Pos(&'a str),
+ MaybeHyphenValue,
+ MaybeNegNum,
+ NotFound,
+ ValuesDone,
+}
+
+#[allow(missing_debug_implementations)]
+#[doc(hidden)]
+#[derive(Clone, Default)]
+pub struct Parser<'a, 'b>
+where
+ 'a: 'b,
+{
+ pub meta: AppMeta<'b>,
+ settings: AppFlags,
+ pub g_settings: AppFlags,
+ pub flags: Vec<FlagBuilder<'a, 'b>>,
+ pub opts: Vec<OptBuilder<'a, 'b>>,
+ pub positionals: VecMap<PosBuilder<'a, 'b>>,
+ pub subcommands: Vec<App<'a, 'b>>,
+ pub groups: Vec<ArgGroup<'a>>,
+ pub global_args: Vec<Arg<'a, 'b>>,
+ pub required: Vec<&'a str>,
+ pub r_ifs: Vec<(&'a str, &'b str, &'a str)>,
+ pub overrides: Vec<(&'b str, &'a str)>,
+ help_short: Option<char>,
+ version_short: Option<char>,
+ cache: Option<&'a str>,
+ pub help_message: Option<&'a str>,
+ pub version_message: Option<&'a str>,
+ cur_idx: Cell<usize>,
+}
+
+impl<'a, 'b> Parser<'a, 'b>
+where
+ 'a: 'b,
+{
+ pub fn with_name(n: String) -> Self {
+ Parser {
+ meta: AppMeta::with_name(n),
+ g_settings: AppFlags::zeroed(),
+ cur_idx: Cell::new(0),
+ ..Default::default()
+ }
+ }
+
+ pub fn help_short(&mut self, s: &str) {
+ let c = s.trim_left_matches(|c| c == '-')
+ .chars()
+ .nth(0)
+ .unwrap_or('h');
+ self.help_short = Some(c);
+ }
+
+ pub fn version_short(&mut self, s: &str) {
+ let c = s.trim_left_matches(|c| c == '-')
+ .chars()
+ .nth(0)
+ .unwrap_or('V');
+ self.version_short = Some(c);
+ }
+
+ pub fn gen_completions_to<W: Write>(&mut self, for_shell: Shell, buf: &mut W) {
+ if !self.is_set(AS::Propagated) {
+ self.propagate_help_version();
+ self.build_bin_names();
+ self.propagate_globals();
+ self.propagate_settings();
+ self.set(AS::Propagated);
+ }
+
+ ComplGen::new(self).generate(for_shell, buf)
+ }
+
+ pub fn gen_completions(&mut self, for_shell: Shell, od: OsString) {
+ use std::error::Error;
+
+ let out_dir = PathBuf::from(od);
+ let name = &*self.meta.bin_name.as_ref().unwrap().clone();
+ let file_name = match for_shell {
+ Shell::Bash => format!("{}.bash", name),
+ Shell::Fish => format!("{}.fish", name),
+ Shell::Zsh => format!("_{}", name),
+ Shell::PowerShell => format!("_{}.ps1", name),
+ Shell::Elvish => format!("{}.elv", name),
+ };
+
+ let mut file = match File::create(out_dir.join(file_name)) {
+ Err(why) => panic!("couldn't create completion file: {}", why.description()),
+ Ok(file) => file,
+ };
+ self.gen_completions_to(for_shell, &mut file)
+ }
+
+ #[inline]
+ fn app_debug_asserts(&self) -> bool {
+ assert!(self.verify_positionals());
+ let should_err = self.groups.iter().all(|g| {
+ g.args.iter().all(|arg| {
+ (self.flags.iter().any(|f| &f.b.name == arg)
+ || self.opts.iter().any(|o| &o.b.name == arg)
+ || self.positionals.values().any(|p| &p.b.name == arg)
+ || self.groups.iter().any(|g| &g.name == arg))
+ })
+ });
+ let g = self.groups.iter().find(|g| {
+ g.args.iter().any(|arg| {
+ !(self.flags.iter().any(|f| &f.b.name == arg)
+ || self.opts.iter().any(|o| &o.b.name == arg)
+ || self.positionals.values().any(|p| &p.b.name == arg)
+ || self.groups.iter().any(|g| &g.name == arg))
+ })
+ });
+ assert!(
+ should_err,
+ "The group '{}' contains the arg '{}' that doesn't actually exist.",
+ g.unwrap().name,
+ g.unwrap()
+ .args
+ .iter()
+ .find(|arg| !(self.flags.iter().any(|f| &&f.b.name == arg)
+ || self.opts.iter().any(|o| &&o.b.name == arg)
+ || self.positionals.values().any(|p| &&p.b.name == arg)
+ || self.groups.iter().any(|g| &&g.name == arg)))
+ .unwrap()
+ );
+ true
+ }
+
+ #[inline]
+ fn debug_asserts(&self, a: &Arg) -> bool {
+ assert!(
+ !arg_names!(self).any(|name| name == a.b.name),
+ format!("Non-unique argument name: {} is already in use", a.b.name)
+ );
+ if let Some(l) = a.s.long {
+ assert!(
+ !self.contains_long(l),
+ "Argument long must be unique\n\n\t--{} is already in use",
+ l
+ );
+ }
+ if let Some(s) = a.s.short {
+ assert!(
+ !self.contains_short(s),
+ "Argument short must be unique\n\n\t-{} is already in use",
+ s
+ );
+ }
+ let i = if a.index.is_none() {
+ (self.positionals.len() + 1)
+ } else {
+ a.index.unwrap() as usize
+ };
+ assert!(
+ !self.positionals.contains_key(i),
+ "Argument \"{}\" has the same index as another positional \
+ argument\n\n\tPerhaps try .multiple(true) to allow one positional argument \
+ to take multiple values",
+ a.b.name
+ );
+ assert!(
+ !(a.is_set(ArgSettings::Required) && a.is_set(ArgSettings::Global)),
+ "Global arguments cannot be required.\n\n\t'{}' is marked as \
+ global and required",
+ a.b.name
+ );
+ if a.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."
+ );
+ assert!(a.s.long.is_none(),
+ "Flags or Options may not have last(true) set. {} has both a long and last(true) set.",
+ a.b.name);
+ assert!(a.s.short.is_none(),
+ "Flags or Options may not have last(true) set. {} has both a short and last(true) set.",
+ a.b.name);
+ }
+ true
+ }
+
+ #[inline]
+ fn add_conditional_reqs(&mut self, a: &Arg<'a, 'b>) {
+ if let Some(ref r_ifs) = a.r_ifs {
+ for &(arg, val) in r_ifs {
+ self.r_ifs.push((arg, val, a.b.name));
+ }
+ }
+ }
+
+ #[inline]
+ fn add_arg_groups(&mut self, a: &Arg<'a, 'b>) {
+ if let Some(ref grps) = a.b.groups {
+ for g in grps {
+ let mut found = false;
+ if let Some(ref mut ag) = self.groups.iter_mut().find(|grp| &grp.name == g) {
+ ag.args.push(a.b.name);
+ found = true;
+ }
+ if !found {
+ let mut ag = ArgGroup::with_name(g);
+ ag.args.push(a.b.name);
+ self.groups.push(ag);
+ }
+ }
+ }
+ }
+
+ #[inline]
+ fn add_reqs(&mut self, a: &Arg<'a, 'b>) {
+ if a.is_set(ArgSettings::Required) {
+ // If the arg is required, add all it's requirements to master required list
+ self.required.push(a.b.name);
+ if let Some(ref areqs) = a.b.requires {
+ for name in areqs
+ .iter()
+ .filter(|&&(val, _)| val.is_none())
+ .map(|&(_, name)| name)
+ {
+ self.required.push(name);
+ }
+ }
+ }
+ }
+
+ #[inline]
+ fn implied_settings(&mut self, a: &Arg<'a, 'b>) {
+ if a.is_set(ArgSettings::Last) {
+ // if an arg has `Last` set, we need to imply DontCollapseArgsInUsage so that args
+ // in the usage string don't get confused or left out.
+ self.set(AS::DontCollapseArgsInUsage);
+ self.set(AS::ContainsLast);
+ }
+ if let Some(l) = a.s.long {
+ if l == "version" {
+ self.unset(AS::NeedsLongVersion);
+ } else if l == "help" {
+ self.unset(AS::NeedsLongHelp);
+ }
+ }
+ }
+
+ // actually adds the arguments
+ pub fn add_arg(&mut self, a: Arg<'a, 'b>) {
+ // if it's global we have to clone anyways
+ if a.is_set(ArgSettings::Global) {
+ return self.add_arg_ref(&a);
+ }
+ debug_assert!(self.debug_asserts(&a));
+ self.add_conditional_reqs(&a);
+ self.add_arg_groups(&a);
+ self.add_reqs(&a);
+ self.implied_settings(&a);
+ if a.index.is_some() || (a.s.short.is_none() && a.s.long.is_none()) {
+ let i = if a.index.is_none() {
+ (self.positionals.len() + 1)
+ } else {
+ a.index.unwrap() as usize
+ };
+ self.positionals
+ .insert(i, PosBuilder::from_arg(a, i as u64));
+ } else if a.is_set(ArgSettings::TakesValue) {
+ let mut ob = OptBuilder::from(a);
+ ob.s.unified_ord = self.flags.len() + self.opts.len();
+ self.opts.push(ob);
+ } else {
+ let mut fb = FlagBuilder::from(a);
+ fb.s.unified_ord = self.flags.len() + self.opts.len();
+ self.flags.push(fb);
+ }
+ }
+ // actually adds the arguments but from a borrow (which means we have to do some cloning)
+ pub fn add_arg_ref(&mut self, a: &Arg<'a, 'b>) {
+ debug_assert!(self.debug_asserts(a));
+ self.add_conditional_reqs(a);
+ self.add_arg_groups(a);
+ self.add_reqs(a);
+ self.implied_settings(a);
+ if a.index.is_some() || (a.s.short.is_none() && a.s.long.is_none()) {
+ let i = if a.index.is_none() {
+ (self.positionals.len() + 1)
+ } else {
+ a.index.unwrap() as usize
+ };
+ let pb = PosBuilder::from_arg_ref(a, i as u64);
+ self.positionals.insert(i, pb);
+ } else if a.is_set(ArgSettings::TakesValue) {
+ let mut ob = OptBuilder::from(a);
+ ob.s.unified_ord = self.flags.len() + self.opts.len();
+ self.opts.push(ob);
+ } else {
+ let mut fb = FlagBuilder::from(a);
+ fb.s.unified_ord = self.flags.len() + self.opts.len();
+ self.flags.push(fb);
+ }
+ if a.is_set(ArgSettings::Global) {
+ self.global_args.push(a.into());
+ }
+ }
+
+ pub fn add_group(&mut self, group: ArgGroup<'a>) {
+ if group.required {
+ self.required.push(group.name);
+ if let Some(ref reqs) = group.requires {
+ self.required.extend_from_slice(reqs);
+ }
+ // if let Some(ref bl) = group.conflicts {
+ // self.blacklist.extend_from_slice(bl);
+ // }
+ }
+ if self.groups.iter().any(|g| g.name == group.name) {
+ let grp = self.groups
+ .iter_mut()
+ .find(|g| g.name == group.name)
+ .expect(INTERNAL_ERROR_MSG);
+ grp.args.extend_from_slice(&group.args);
+ grp.requires = group.requires.clone();
+ grp.conflicts = group.conflicts.clone();
+ grp.required = group.required;
+ } else {
+ self.groups.push(group);
+ }
+ }
+
+ pub fn add_subcommand(&mut self, mut subcmd: App<'a, 'b>) {
+ debugln!(
+ "Parser::add_subcommand: term_w={:?}, name={}",
+ self.meta.term_w,
+ subcmd.p.meta.name
+ );
+ subcmd.p.meta.term_w = self.meta.term_w;
+ if subcmd.p.meta.name == "help" {
+ self.unset(AS::NeedsSubcommandHelp);
+ }
+
+ self.subcommands.push(subcmd);
+ }
+
+ pub fn propagate_settings(&mut self) {
+ debugln!(
+ "Parser::propagate_settings: self={}, g_settings={:#?}",
+ self.meta.name,
+ self.g_settings
+ );
+ for sc in &mut self.subcommands {
+ debugln!(
+ "Parser::propagate_settings: sc={}, settings={:#?}, g_settings={:#?}",
+ sc.p.meta.name,
+ sc.p.settings,
+ sc.p.g_settings
+ );
+ // We have to create a new scope in order to tell rustc the borrow of `sc` is
+ // done and to recursively call this method
+ {
+ let vsc = self.settings.is_set(AS::VersionlessSubcommands);
+ let gv = self.settings.is_set(AS::GlobalVersion);
+
+ if vsc {
+ sc.p.set(AS::DisableVersion);
+ }
+ if gv && sc.p.meta.version.is_none() && self.meta.version.is_some() {
+ sc.p.set(AS::GlobalVersion);
+ sc.p.meta.version = Some(self.meta.version.unwrap());
+ }
+ sc.p.settings = sc.p.settings | self.g_settings;
+ sc.p.g_settings = sc.p.g_settings | self.g_settings;
+ sc.p.meta.term_w = self.meta.term_w;
+ sc.p.meta.max_w = self.meta.max_w;
+ }
+ sc.p.propagate_settings();
+ }
+ }
+
+ #[cfg_attr(feature = "lints", allow(needless_borrow))]
+ pub fn derive_display_order(&mut self) {
+ if self.is_set(AS::DeriveDisplayOrder) {
+ let unified = self.is_set(AS::UnifiedHelpMessage);
+ for (i, o) in self.opts
+ .iter_mut()
+ .enumerate()
+ .filter(|&(_, ref o)| o.s.disp_ord == 999)
+ {
+ o.s.disp_ord = if unified { o.s.unified_ord } else { i };
+ }
+ for (i, f) in self.flags
+ .iter_mut()
+ .enumerate()
+ .filter(|&(_, ref f)| f.s.disp_ord == 999)
+ {
+ f.s.disp_ord = if unified { f.s.unified_ord } else { i };
+ }
+ for (i, sc) in &mut self.subcommands
+ .iter_mut()
+ .enumerate()
+ .filter(|&(_, ref sc)| sc.p.meta.disp_ord == 999)
+ {
+ sc.p.meta.disp_ord = i;
+ }
+ }
+ for sc in &mut self.subcommands {
+ sc.p.derive_display_order();
+ }
+ }
+
+ pub fn required(&self) -> Iter<&str> { self.required.iter() }
+
+ #[cfg_attr(feature = "lints", allow(needless_borrow))]
+ #[inline]
+ pub fn has_args(&self) -> bool {
+ !(self.flags.is_empty() && self.opts.is_empty() && self.positionals.is_empty())
+ }
+
+ #[inline]
+ pub fn has_opts(&self) -> bool { !self.opts.is_empty() }
+
+ #[inline]
+ pub fn has_flags(&self) -> bool { !self.flags.is_empty() }
+
+ #[inline]
+ pub fn has_positionals(&self) -> bool { !self.positionals.is_empty() }
+
+ #[inline]
+ pub fn has_subcommands(&self) -> bool { !self.subcommands.is_empty() }
+
+ #[inline]
+ pub fn has_visible_opts(&self) -> bool {
+ if self.opts.is_empty() {
+ return false;
+ }
+ self.opts.iter().any(|o| !o.is_set(ArgSettings::Hidden))
+ }
+
+ #[inline]
+ pub fn has_visible_flags(&self) -> bool {
+ if self.flags.is_empty() {
+ return false;
+ }
+ self.flags.iter().any(|f| !f.is_set(ArgSettings::Hidden))
+ }
+
+ #[inline]
+ pub fn has_visible_positionals(&self) -> bool {
+ if self.positionals.is_empty() {
+ return false;
+ }
+ self.positionals
+ .values()
+ .any(|p| !p.is_set(ArgSettings::Hidden))
+ }
+
+ #[inline]
+ pub fn has_visible_subcommands(&self) -> bool {
+ self.has_subcommands()
+ && self.subcommands
+ .iter()
+ .filter(|sc| sc.p.meta.name != "help")
+ .any(|sc| !sc.p.is_set(AS::Hidden))
+ }
+
+ #[inline]
+ pub fn is_set(&self, s: AS) -> bool { self.settings.is_set(s) }
+
+ #[inline]
+ pub fn set(&mut self, s: AS) { self.settings.set(s) }
+
+ #[inline]
+ pub fn unset(&mut self, s: AS) { self.settings.unset(s) }
+
+ #[cfg_attr(feature = "lints", allow(block_in_if_condition_stmt))]
+ pub fn verify_positionals(&self) -> bool {
+ // Because you must wait until all arguments have been supplied, this is the first chance
+ // to make assertions on positional argument indexes
+ //
+ // First 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
+ // but no 2)
+ if let Some((idx, p)) = self.positionals.iter().rev().next() {
+ assert!(
+ !(idx != self.positionals.len()),
+ "Found positional argument \"{}\" whose index is {} but there \
+ are only {} positional arguments defined",
+ p.b.name,
+ idx,
+ self.positionals.len()
+ );
+ }
+
+ // Next we verify that only the highest index has a .multiple(true) (if any)
+ if self.positionals.values().any(|a| {
+ a.b.is_set(ArgSettings::Multiple) && (a.index as usize != self.positionals.len())
+ }) {
+ let mut it = self.positionals.values().rev();
+ let last = it.next().unwrap();
+ let second_to_last = it.next().unwrap();
+ // Either the final positional is required
+ // Or the second to last has a terminator or .last(true) set
+ let ok = last.is_set(ArgSettings::Required)
+ || (second_to_last.v.terminator.is_some()
+ || second_to_last.b.is_set(ArgSettings::Last))
+ || last.is_set(ArgSettings::Last);
+ assert!(
+ ok,
+ "When using a positional argument with .multiple(true) that is *not the \
+ last* positional argument, the last positional argument (i.e the one \
+ with the highest index) *must* have .required(true) or .last(true) set."
+ );
+ let ok = second_to_last.is_set(ArgSettings::Multiple) || last.is_set(ArgSettings::Last);
+ assert!(
+ ok,
+ "Only the last positional argument, or second to last positional \
+ argument may be set to .multiple(true)"
+ );
+
+ let count = self.positionals
+ .values()
+ .filter(|p| p.b.settings.is_set(ArgSettings::Multiple) && p.v.num_vals.is_none())
+ .count();
+ let ok = count <= 1
+ || (last.is_set(ArgSettings::Last) && last.is_set(ArgSettings::Multiple)
+ && second_to_last.is_set(ArgSettings::Multiple)
+ && count == 2);
+ assert!(
+ ok,
+ "Only one positional argument with .multiple(true) set is allowed per \
+ command, unless the second one also has .last(true) set"
+ );
+ }
+
+ if self.is_set(AS::AllowMissingPositional) {
+ // Check that if a required positional argument is found, all positions with a lower
+ // index are also required.
+ let mut found = false;
+ let mut foundx2 = false;
+ for p in self.positionals.values().rev() {
+ if foundx2 && !p.b.settings.is_set(ArgSettings::Required) {
+ assert!(
+ p.b.is_set(ArgSettings::Required),
+ "Found positional argument which is not required with a lower \
+ index than a required positional argument by two or more: {:?} \
+ index {}",
+ p.b.name,
+ p.index
+ );
+ } else if p.b.is_set(ArgSettings::Required) && !p.b.is_set(ArgSettings::Last) {
+ // Args that .last(true) don't count since they can be required and have
+ // positionals with a lower index that aren't required
+ // Imagine: prog <req1> [opt1] -- <req2>
+ // Both of these are valid invocations:
+ // $ prog r1 -- r2
+ // $ prog r1 o1 -- r2
+ if found {
+ foundx2 = true;
+ continue;
+ }
+ found = true;
+ continue;
+ } else {
+ found = false;
+ }
+ }
+ } else {
+ // Check that if a required positional argument is found, all positions with a lower
+ // index are also required
+ let mut found = false;
+ for p in self.positionals.values().rev() {
+ if found {
+ assert!(
+ p.b.is_set(ArgSettings::Required),
+ "Found positional argument which is not required with a lower \
+ index than a required positional argument: {:?} index {}",
+ p.b.name,
+ p.index
+ );
+ } else if p.b.is_set(ArgSettings::Required) && !p.b.is_set(ArgSettings::Last) {
+ // Args that .last(true) don't count since they can be required and have
+ // positionals with a lower index that aren't required
+ // Imagine: prog <req1> [opt1] -- <req2>
+ // Both of these are valid invocations:
+ // $ prog r1 -- r2
+ // $ prog r1 o1 -- r2
+ found = true;
+ continue;
+ }
+ }
+ }
+ if self.positionals
+ .values()
+ .any(|p| p.b.is_set(ArgSettings::Last) && p.b.is_set(ArgSettings::Required))
+ && self.has_subcommands() && !self.is_set(AS::SubcommandsNegateReqs)
+ {
+ panic!(
+ "Having a required positional argument with .last(true) set *and* child \
+ subcommands without setting SubcommandsNegateReqs isn't compatible."
+ );
+ }
+
+ true
+ }
+
+ pub fn propagate_globals(&mut self) {
+ for sc in &mut self.subcommands {
+ // We have to create a new scope in order to tell rustc the borrow of `sc` is
+ // done and to recursively call this method
+ {
+ for a in &self.global_args {
+ sc.p.add_arg_ref(a);
+ }
+ }
+ sc.p.propagate_globals();
+ }
+ }
+
+ // Checks if the arg matches a subcommand name, or any of it's aliases (if defined)
+ fn possible_subcommand(&self, arg_os: &OsStr) -> (bool, Option<&str>) {
+ #[cfg(not(any(target_os = "windows", target_arch = "wasm32")))]
+ use std::os::unix::ffi::OsStrExt;
+ #[cfg(any(target_os = "windows", target_arch = "wasm32"))]
+ use osstringext::OsStrExt3;
+ debugln!("Parser::possible_subcommand: arg={:?}", arg_os);
+ fn starts(h: &str, n: &OsStr) -> bool {
+ let n_bytes = n.as_bytes();
+ let h_bytes = OsStr::new(h).as_bytes();
+
+ h_bytes.starts_with(n_bytes)
+ }
+
+ if self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound) {
+ return (false, None);
+ }
+ if !self.is_set(AS::InferSubcommands) {
+ if let Some(sc) = find_subcmd!(self, arg_os) {
+ return (true, Some(&sc.p.meta.name));
+ }
+ } else {
+ let v = self.subcommands
+ .iter()
+ .filter(|s| {
+ starts(&s.p.meta.name[..], &*arg_os)
+ || (s.p.meta.aliases.is_some()
+ && s.p
+ .meta
+ .aliases
+ .as_ref()
+ .unwrap()
+ .iter()
+ .filter(|&&(a, _)| starts(a, &*arg_os))
+ .count() == 1)
+ })
+ .map(|sc| &sc.p.meta.name)
+ .collect::<Vec<_>>();
+
+ for sc in &v {
+ if OsStr::new(sc) == arg_os {
+ return (true, Some(sc));
+ }
+ }
+
+ if v.len() == 1 {
+ return (true, Some(v[0]));
+ }
+ }
+ (false, None)
+ }
+
+ fn parse_help_subcommand<I, T>(&self, it: &mut I) -> ClapResult<ParseResult<'a>>
+ where
+ I: Iterator<Item = T>,
+ T: Into<OsString>,
+ {
+ debugln!("Parser::parse_help_subcommand;");
+ let cmds: Vec<OsString> = it.map(|c| c.into()).collect();
+ let mut help_help = false;
+ let mut bin_name = self.meta
+ .bin_name
+ .as_ref()
+ .unwrap_or(&self.meta.name)
+ .clone();
+ let mut sc = {
+ let mut sc: &Parser = self;
+ for (i, cmd) in cmds.iter().enumerate() {
+ if &*cmd.to_string_lossy() == "help" {
+ // cmd help help
+ help_help = true;
+ }
+ if let Some(c) = sc.subcommands
+ .iter()
+ .find(|s| &*s.p.meta.name == cmd)
+ .map(|sc| &sc.p)
+ {
+ sc = c;
+ if i == cmds.len() - 1 {
+ break;
+ }
+ } else if let Some(c) = sc.subcommands
+ .iter()
+ .find(|s| {
+ if let Some(ref als) = s.p.meta.aliases {
+ als.iter().any(|&(a, _)| a == &*cmd.to_string_lossy())
+ } else {
+ false
+ }
+ })
+ .map(|sc| &sc.p)
+ {
+ sc = c;
+ if i == cmds.len() - 1 {
+ break;
+ }
+ } else {
+ return Err(Error::unrecognized_subcommand(
+ cmd.to_string_lossy().into_owned(),
+ self.meta.bin_name.as_ref().unwrap_or(&self.meta.name),
+ self.color(),
+ ));
+ }
+ bin_name = format!("{} {}", bin_name, &*sc.meta.name);
+ }
+ sc.clone()
+ };
+ if help_help {
+ let mut pb = PosBuilder::new("subcommand", 1);
+ pb.b.help = Some("The subcommand whose help message to display");
+ pb.set(ArgSettings::Multiple);
+ sc.positionals.insert(1, pb);
+ sc.settings = sc.settings | self.g_settings;
+ } else {
+ sc.create_help_and_version();
+ }
+ if sc.meta.bin_name != self.meta.bin_name {
+ sc.meta.bin_name = Some(format!("{} {}", bin_name, sc.meta.name));
+ }
+ Err(sc._help(false))
+ }
+
+ // allow wrong self convention due to self.valid_neg_num = true and it's a private method
+ #[cfg_attr(feature = "lints", allow(wrong_self_convention))]
+ fn is_new_arg(&mut self, arg_os: &OsStr, needs_val_of: ParseResult) -> bool {
+ debugln!("Parser::is_new_arg:{:?}:{:?}", arg_os, needs_val_of);
+ let app_wide_settings = if self.is_set(AS::AllowLeadingHyphen) {
+ true
+ } else if self.is_set(AS::AllowNegativeNumbers) {
+ let a = arg_os.to_string_lossy();
+ if a.parse::<i64>().is_ok() || a.parse::<f64>().is_ok() {
+ self.set(AS::ValidNegNumFound);
+ true
+ } else {
+ false
+ }
+ } else {
+ false
+ };
+ let arg_allows_tac = match needs_val_of {
+ ParseResult::Opt(name) => {
+ let o = self.opts
+ .iter()
+ .find(|o| o.b.name == name)
+ .expect(INTERNAL_ERROR_MSG);
+ (o.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings)
+ }
+ ParseResult::Pos(name) => {
+ let p = self.positionals
+ .values()
+ .find(|p| p.b.name == name)
+ .expect(INTERNAL_ERROR_MSG);
+ (p.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings)
+ }
+ ParseResult::ValuesDone => return true,
+ _ => false,
+ };
+ debugln!("Parser::is_new_arg: arg_allows_tac={:?}", arg_allows_tac);
+
+ // Is this a new argument, or values from a previous option?
+ let mut ret = if arg_os.starts_with(b"--") {
+ debugln!("Parser::is_new_arg: -- found");
+ if arg_os.len() == 2 && !arg_allows_tac {
+ return true; // We have to return true so override everything else
+ } else if arg_allows_tac {
+ return false;
+ }
+ true
+ } else if arg_os.starts_with(b"-") {
+ debugln!("Parser::is_new_arg: - found");
+ // a singe '-' by itself is a value and typically means "stdin" on unix systems
+ !(arg_os.len() == 1)
+ } else {
+ debugln!("Parser::is_new_arg: probably value");
+ false
+ };
+
+ ret = ret && !arg_allows_tac;
+
+ debugln!("Parser::is_new_arg: starts_new_arg={:?}", ret);
+ ret
+ }
+
+ // The actual parsing function
+ #[cfg_attr(feature = "lints", allow(while_let_on_iterator, collapsible_if))]
+ pub fn get_matches_with<I, T>(
+ &mut self,
+ matcher: &mut ArgMatcher<'a>,
+ it: &mut Peekable<I>,
+ ) -> ClapResult<()>
+ where
+ I: Iterator<Item = T>,
+ T: Into<OsString> + Clone,
+ {
+ debugln!("Parser::get_matches_with;");
+ // Verify all positional assertions pass
+ debug_assert!(self.app_debug_asserts());
+ if self.positionals.values().any(|a| {
+ a.b.is_set(ArgSettings::Multiple) && (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);
+ }
+ let has_args = self.has_args();
+
+ // Next we create the `--help` and `--version` arguments and add them if
+ // necessary
+ self.create_help_and_version();
+
+ let mut subcmd_name: Option<String> = None;
+ let mut needs_val_of: ParseResult<'a> = ParseResult::NotFound;
+ let mut pos_counter = 1;
+ let mut sc_is_external = false;
+ while let Some(arg) = it.next() {
+ let arg_os = arg.into();
+ debugln!(
+ "Parser::get_matches_with: Begin parsing '{:?}' ({:?})",
+ arg_os,
+ &*arg_os.as_bytes()
+ );
+
+ self.unset(AS::ValidNegNumFound);
+ // Is this a new argument, or values from a previous option?
+ let starts_new_arg = self.is_new_arg(&arg_os, needs_val_of);
+ if !self.is_set(AS::TrailingValues) && arg_os.starts_with(b"--") && arg_os.len() == 2
+ && starts_new_arg
+ {
+ debugln!("Parser::get_matches_with: setting TrailingVals=true");
+ self.set(AS::TrailingValues);
+ continue;
+ }
+
+ // Has the user already passed '--'? Meaning only positional args follow
+ if !self.is_set(AS::TrailingValues) {
+ // Does the arg match a subcommand name, or any of it's aliases (if defined)
+ {
+ match needs_val_of {
+ ParseResult::Opt(_) | ParseResult::Pos(_) => (),
+ _ => {
+ let (is_match, sc_name) = self.possible_subcommand(&arg_os);
+ debugln!(
+ "Parser::get_matches_with: possible_sc={:?}, sc={:?}",
+ is_match,
+ sc_name
+ );
+ if is_match {
+ let sc_name = sc_name.expect(INTERNAL_ERROR_MSG);
+ if sc_name == "help" && self.is_set(AS::NeedsSubcommandHelp) {
+ self.parse_help_subcommand(it)?;
+ }
+ subcmd_name = Some(sc_name.to_owned());
+ break;
+ }
+ }
+ }
+ }
+
+ if starts_new_arg {
+ let check_all = self.is_set(AS::AllArgsOverrideSelf);
+ {
+ let any_arg = find_any_by_name!(self, self.cache.unwrap_or(""));
+ matcher.process_arg_overrides(
+ any_arg,
+ &mut self.overrides,
+ &mut self.required,
+ check_all,
+ );
+ }
+
+ if arg_os.starts_with(b"--") {
+ needs_val_of = self.parse_long_arg(matcher, &arg_os, it)?;
+ debugln!(
+ "Parser:get_matches_with: After parse_long_arg {:?}",
+ needs_val_of
+ );
+ match needs_val_of {
+ ParseResult::Flag | ParseResult::Opt(..) | ParseResult::ValuesDone => {
+ continue
+ }
+ _ => (),
+ }
+ } else if arg_os.starts_with(b"-") && arg_os.len() != 1 {
+ // Try to parse short args like normal, if AllowLeadingHyphen or
+ // AllowNegativeNumbers is set, parse_short_arg will *not* throw
+ // an error, and instead return Ok(None)
+ needs_val_of = self.parse_short_arg(matcher, &arg_os)?;
+ // If it's None, we then check if one of those two AppSettings was set
+ debugln!(
+ "Parser:get_matches_with: After parse_short_arg {:?}",
+ needs_val_of
+ );
+ match needs_val_of {
+ ParseResult::MaybeNegNum => {
+ if !(arg_os.to_string_lossy().parse::<i64>().is_ok()
+ || arg_os.to_string_lossy().parse::<f64>().is_ok())
+ {
+ return Err(Error::unknown_argument(
+ &*arg_os.to_string_lossy(),
+ "",
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ }
+ }
+ ParseResult::Opt(..) | ParseResult::Flag | ParseResult::ValuesDone => {
+ continue
+ }
+ _ => (),
+ }
+ }
+ } else {
+ if let ParseResult::Opt(name) = needs_val_of {
+ // Check to see if parsing a value from a previous arg
+ let arg = self.opts
+ .iter()
+ .find(|o| o.b.name == name)
+ .expect(INTERNAL_ERROR_MSG);
+ // get the OptBuilder so we can check the settings
+ needs_val_of = self.add_val_to_arg(arg, &arg_os, matcher)?;
+ // get the next value from the iterator
+ continue;
+ }
+ }
+ }
+
+ if !(self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound))
+ && !self.is_set(AS::InferSubcommands) && !self.is_set(AS::AllowExternalSubcommands)
+ {
+ if let Some(cdate) =
+ suggestions::did_you_mean(&*arg_os.to_string_lossy(), sc_names!(self))
+ {
+ return Err(Error::invalid_subcommand(
+ arg_os.to_string_lossy().into_owned(),
+ cdate,
+ self.meta.bin_name.as_ref().unwrap_or(&self.meta.name),
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ }
+ }
+
+ let low_index_mults = self.is_set(AS::LowIndexMultiplePositional)
+ && pos_counter == (self.positionals.len() - 1);
+ let missing_pos = self.is_set(AS::AllowMissingPositional)
+ && (pos_counter == (self.positionals.len() - 1)
+ && !self.is_set(AS::TrailingValues));
+ debugln!(
+ "Parser::get_matches_with: Positional counter...{}",
+ pos_counter
+ );
+ debugln!(
+ "Parser::get_matches_with: Low index multiples...{:?}",
+ low_index_mults
+ );
+ if low_index_mults || missing_pos {
+ if let Some(na) = it.peek() {
+ let n = (*na).clone().into();
+ needs_val_of = if needs_val_of != ParseResult::ValuesDone {
+ if let Some(p) = self.positionals.get(pos_counter) {
+ ParseResult::Pos(p.b.name)
+ } else {
+ ParseResult::ValuesDone
+ }
+ } else {
+ ParseResult::ValuesDone
+ };
+ let sc_match = { self.possible_subcommand(&n).0 };
+ if self.is_new_arg(&n, needs_val_of) || sc_match
+ || suggestions::did_you_mean(&n.to_string_lossy(), sc_names!(self))
+ .is_some()
+ {
+ debugln!("Parser::get_matches_with: Bumping the positional counter...");
+ pos_counter += 1;
+ }
+ } else {
+ debugln!("Parser::get_matches_with: Bumping the positional counter...");
+ pos_counter += 1;
+ }
+ } else if (self.is_set(AS::AllowMissingPositional) && self.is_set(AS::TrailingValues))
+ || (self.is_set(AS::ContainsLast) && self.is_set(AS::TrailingValues))
+ {
+ // Came to -- and one postional has .last(true) set, so we go immediately
+ // to the last (highest index) positional
+ debugln!("Parser::get_matches_with: .last(true) and --, setting last pos");
+ pos_counter = self.positionals.len();
+ }
+ if let Some(p) = self.positionals.get(pos_counter) {
+ if p.is_set(ArgSettings::Last) && !self.is_set(AS::TrailingValues) {
+ return Err(Error::unknown_argument(
+ &*arg_os.to_string_lossy(),
+ "",
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ }
+ if !self.is_set(AS::TrailingValues)
+ && (self.is_set(AS::TrailingVarArg) && pos_counter == self.positionals.len())
+ {
+ self.settings.set(AS::TrailingValues);
+ }
+ if self.cache.map_or(true, |name| name != p.b.name) {
+ let check_all = self.is_set(AS::AllArgsOverrideSelf);
+ {
+ let any_arg = find_any_by_name!(self, self.cache.unwrap_or(""));
+ matcher.process_arg_overrides(
+ any_arg,
+ &mut self.overrides,
+ &mut self.required,
+ check_all,
+ );
+ }
+ self.cache = Some(p.b.name);
+ }
+ let _ = self.add_val_to_arg(p, &arg_os, matcher)?;
+
+ matcher.inc_occurrence_of(p.b.name);
+ let _ = self.groups_for_arg(p.b.name)
+ .and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));
+
+ self.settings.set(AS::ValidArgFound);
+ // Only increment the positional counter if it doesn't allow multiples
+ if !p.b.settings.is_set(ArgSettings::Multiple) {
+ pos_counter += 1;
+ }
+ self.settings.set(AS::ValidArgFound);
+ } else if self.is_set(AS::AllowExternalSubcommands) {
+ // Get external subcommand name
+ let sc_name = match arg_os.to_str() {
+ Some(s) => s.to_string(),
+ None => {
+ if !self.is_set(AS::StrictUtf8) {
+ return Err(Error::invalid_utf8(
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ }
+ arg_os.to_string_lossy().into_owned()
+ }
+ };
+
+ // Collect the external subcommand args
+ let mut sc_m = ArgMatcher::new();
+ while let Some(v) = it.next() {
+ let a = v.into();
+ if a.to_str().is_none() && !self.is_set(AS::StrictUtf8) {
+ return Err(Error::invalid_utf8(
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ }
+ sc_m.add_val_to("", &a);
+ }
+
+ matcher.subcommand(SubCommand {
+ name: sc_name,
+ matches: sc_m.into(),
+ });
+ sc_is_external = true;
+ } else if !((self.is_set(AS::AllowLeadingHyphen)
+ || self.is_set(AS::AllowNegativeNumbers))
+ && arg_os.starts_with(b"-"))
+ && !self.is_set(AS::InferSubcommands)
+ {
+ return Err(Error::unknown_argument(
+ &*arg_os.to_string_lossy(),
+ "",
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ } else if !has_args || self.is_set(AS::InferSubcommands) && self.has_subcommands() {
+ if let Some(cdate) =
+ suggestions::did_you_mean(&*arg_os.to_string_lossy(), sc_names!(self))
+ {
+ return Err(Error::invalid_subcommand(
+ arg_os.to_string_lossy().into_owned(),
+ cdate,
+ self.meta.bin_name.as_ref().unwrap_or(&self.meta.name),
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ } else {
+ return Err(Error::unrecognized_subcommand(
+ arg_os.to_string_lossy().into_owned(),
+ self.meta.bin_name.as_ref().unwrap_or(&self.meta.name),
+ self.color(),
+ ));
+ }
+ } else {
+ return Err(Error::unknown_argument(
+ &*arg_os.to_string_lossy(),
+ "",
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ }
+ }
+
+ if !sc_is_external {
+ if let Some(ref pos_sc_name) = subcmd_name {
+ let sc_name = {
+ find_subcmd!(self, pos_sc_name)
+ .expect(INTERNAL_ERROR_MSG)
+ .p
+ .meta
+ .name
+ .clone()
+ };
+ self.parse_subcommand(&*sc_name, matcher, it)?;
+ } else if self.is_set(AS::SubcommandRequired) {
+ let bn = self.meta.bin_name.as_ref().unwrap_or(&self.meta.name);
+ return Err(Error::missing_subcommand(
+ bn,
+ &usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ } else if self.is_set(AS::SubcommandRequiredElseHelp) {
+ debugln!("Parser::get_matches_with: SubcommandRequiredElseHelp=true");
+ let mut out = vec![];
+ self.write_help_err(&mut out)?;
+ return Err(Error {
+ message: String::from_utf8_lossy(&*out).into_owned(),
+ kind: ErrorKind::MissingArgumentOrSubcommand,
+ info: None,
+ });
+ }
+ }
+
+ // In case the last arg was new, we need to process it's overrides
+ let check_all = self.is_set(AS::AllArgsOverrideSelf);
+ {
+ let any_arg = find_any_by_name!(self, self.cache.unwrap_or(""));
+ matcher.process_arg_overrides(
+ any_arg,
+ &mut self.overrides,
+ &mut self.required,
+ check_all,
+ );
+ }
+
+ self.remove_overrides(matcher);
+
+ Validator::new(self).validate(needs_val_of, subcmd_name, matcher)
+ }
+
+ fn remove_overrides(&mut self, matcher: &mut ArgMatcher) {
+ debugln!("Parser::remove_overrides:{:?};", self.overrides);
+ for &(overr, name) in &self.overrides {
+ debugln!("Parser::remove_overrides:iter:({},{});", overr, name);
+ if matcher.is_present(overr) {
+ debugln!(
+ "Parser::remove_overrides:iter:({},{}): removing {};",
+ overr,
+ name,
+ name
+ );
+ matcher.remove(name);
+ for i in (0..self.required.len()).rev() {
+ debugln!(
+ "Parser::remove_overrides:iter:({},{}): removing required {};",
+ overr,
+ name,
+ name
+ );
+ if self.required[i] == name {
+ self.required.swap_remove(i);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ fn propagate_help_version(&mut self) {
+ debugln!("Parser::propagate_help_version;");
+ self.create_help_and_version();
+ for sc in &mut self.subcommands {
+ sc.p.propagate_help_version();
+ }
+ }
+
+ fn build_bin_names(&mut self) {
+ debugln!("Parser::build_bin_names;");
+ for sc in &mut self.subcommands {
+ debug!("Parser::build_bin_names:iter: bin_name set...");
+ if sc.p.meta.bin_name.is_none() {
+ sdebugln!("No");
+ let bin_name = format!(
+ "{}{}{}",
+ self.meta
+ .bin_name
+ .as_ref()
+ .unwrap_or(&self.meta.name.clone()),
+ if self.meta.bin_name.is_some() {
+ " "
+ } else {
+ ""
+ },
+ &*sc.p.meta.name
+ );
+ debugln!(
+ "Parser::build_bin_names:iter: Setting bin_name of {} to {}",
+ self.meta.name,
+ bin_name
+ );
+ sc.p.meta.bin_name = Some(bin_name);
+ } else {
+ sdebugln!("yes ({:?})", sc.p.meta.bin_name);
+ }
+ debugln!(
+ "Parser::build_bin_names:iter: Calling build_bin_names from...{}",
+ sc.p.meta.name
+ );
+ sc.p.build_bin_names();
+ }
+ }
+
+ fn parse_subcommand<I, T>(
+ &mut self,
+ sc_name: &str,
+ matcher: &mut ArgMatcher<'a>,
+ it: &mut Peekable<I>,
+ ) -> ClapResult<()>
+ where
+ I: Iterator<Item = T>,
+ T: Into<OsString> + Clone,
+ {
+ use std::fmt::Write;
+ debugln!("Parser::parse_subcommand;");
+ let mut mid_string = String::new();
+ if !self.is_set(AS::SubcommandsNegateReqs) {
+ let mut hs: Vec<&str> = self.required.iter().map(|n| &**n).collect();
+ for k in matcher.arg_names() {
+ hs.push(k);
+ }
+ let reqs = usage::get_required_usage_from(self, &hs, Some(matcher), None, false);
+
+ for s in &reqs {
+ write!(&mut mid_string, " {}", s).expect(INTERNAL_ERROR_MSG);
+ }
+ }
+ mid_string.push_str(" ");
+ if let Some(ref mut sc) = self.subcommands
+ .iter_mut()
+ .find(|s| s.p.meta.name == sc_name)
+ {
+ let mut sc_matcher = ArgMatcher::new();
+ // bin_name should be parent's bin_name + [<reqs>] + the sc's name separated by
+ // a space
+ sc.p.meta.usage = Some(format!(
+ "{}{}{}",
+ self.meta.bin_name.as_ref().unwrap_or(&String::new()),
+ if self.meta.bin_name.is_some() {
+ &*mid_string
+ } else {
+ ""
+ },
+ &*sc.p.meta.name
+ ));
+ sc.p.meta.bin_name = Some(format!(
+ "{}{}{}",
+ self.meta.bin_name.as_ref().unwrap_or(&String::new()),
+ if self.meta.bin_name.is_some() {
+ " "
+ } else {
+ ""
+ },
+ &*sc.p.meta.name
+ ));
+ debugln!(
+ "Parser::parse_subcommand: About to parse sc={}",
+ sc.p.meta.name
+ );
+ debugln!("Parser::parse_subcommand: sc settings={:#?}", sc.p.settings);
+ sc.p.get_matches_with(&mut sc_matcher, it)?;
+ matcher.subcommand(SubCommand {
+ name: sc.p.meta.name.clone(),
+ matches: sc_matcher.into(),
+ });
+ }
+ Ok(())
+ }
+
+ pub fn groups_for_arg(&self, name: &str) -> Option<Vec<&'a str>> {
+ debugln!("Parser::groups_for_arg: name={}", name);
+
+ if self.groups.is_empty() {
+ debugln!("Parser::groups_for_arg: No groups defined");
+ return None;
+ }
+ let mut res = vec![];
+ debugln!("Parser::groups_for_arg: Searching through groups...");
+ for grp in &self.groups {
+ for a in &grp.args {
+ if a == &name {
+ sdebugln!("\tFound '{}'", grp.name);
+ res.push(&*grp.name);
+ }
+ }
+ }
+ if res.is_empty() {
+ return None;
+ }
+
+ Some(res)
+ }
+
+ pub fn args_in_group(&self, group: &str) -> Vec<String> {
+ debug_assert!(self.app_debug_asserts());
+
+ let mut g_vec = vec![];
+ let mut args = vec![];
+
+ for n in &self.groups
+ .iter()
+ .find(|g| g.name == group)
+ .expect(INTERNAL_ERROR_MSG)
+ .args
+ {
+ if let Some(f) = self.flags.iter().find(|f| &f.b.name == n) {
+ args.push(f.to_string());
+ } else if let Some(f) = self.opts.iter().find(|o| &o.b.name == n) {
+ args.push(f.to_string());
+ } else if let Some(p) = self.positionals.values().find(|p| &p.b.name == n) {
+ args.push(p.b.name.to_owned());
+ } else {
+ g_vec.push(*n);
+ }
+ }
+
+ for av in g_vec.iter().map(|g| self.args_in_group(g)) {
+ args.extend(av);
+ }
+ args.dedup();
+ args.iter().map(ToOwned::to_owned).collect()
+ }
+
+ pub fn arg_names_in_group(&self, group: &str) -> Vec<&'a str> {
+ let mut g_vec = vec![];
+ let mut args = vec![];
+
+ for n in &self.groups
+ .iter()
+ .find(|g| g.name == group)
+ .expect(INTERNAL_ERROR_MSG)
+ .args
+ {
+ if self.groups.iter().any(|g| g.name == *n) {
+ args.extend(self.arg_names_in_group(n));
+ g_vec.push(*n);
+ } else if !args.contains(n) {
+ args.push(*n);
+ }
+ }
+
+ args.iter().map(|s| *s).collect()
+ }
+
+ pub fn create_help_and_version(&mut self) {
+ debugln!("Parser::create_help_and_version;");
+ // name is "hclap_help" because flags are sorted by name
+ if !self.is_set(AS::DisableHelpFlags) && !self.contains_long("help") {
+ debugln!("Parser::create_help_and_version: Building --help");
+ if self.help_short.is_none() && !self.contains_short('h') {
+ self.help_short = Some('h');
+ }
+ let arg = FlagBuilder {
+ b: Base {
+ name: "hclap_help",
+ help: self.help_message.or(Some("Prints help information")),
+ ..Default::default()
+ },
+ s: Switched {
+ short: self.help_short,
+ long: Some("help"),
+ ..Default::default()
+ },
+ };
+ self.flags.push(arg);
+ }
+ if !self.is_set(AS::DisableVersion) && !self.contains_long("version") {
+ debugln!("Parser::create_help_and_version: Building --version");
+ if self.version_short.is_none() && !self.contains_short('V') {
+ self.version_short = Some('V');
+ }
+ // name is "vclap_version" because flags are sorted by name
+ let arg = FlagBuilder {
+ b: Base {
+ name: "vclap_version",
+ help: self.version_message.or(Some("Prints version information")),
+ ..Default::default()
+ },
+ s: Switched {
+ short: self.version_short,
+ long: Some("version"),
+ ..Default::default()
+ },
+ };
+ self.flags.push(arg);
+ }
+ if !self.subcommands.is_empty() && !self.is_set(AS::DisableHelpSubcommand)
+ && self.is_set(AS::NeedsSubcommandHelp)
+ {
+ debugln!("Parser::create_help_and_version: Building help");
+ self.subcommands.push(
+ App::new("help")
+ .about("Prints this message or the help of the given subcommand(s)"),
+ );
+ }
+ }
+
+ // Retrieves the names of all args the user has supplied thus far, except required ones
+ // because those will be listed in self.required
+ fn check_for_help_and_version_str(&self, arg: &OsStr) -> ClapResult<()> {
+ debugln!("Parser::check_for_help_and_version_str;");
+ debug!(
+ "Parser::check_for_help_and_version_str: Checking if --{} is help or version...",
+ arg.to_str().unwrap()
+ );
+ if arg == "help" && self.is_set(AS::NeedsLongHelp) {
+ sdebugln!("Help");
+ return Err(self._help(true));
+ }
+ if arg == "version" && self.is_set(AS::NeedsLongVersion) {
+ sdebugln!("Version");
+ return Err(self._version(true));
+ }
+ sdebugln!("Neither");
+
+ Ok(())
+ }
+
+ fn check_for_help_and_version_char(&self, arg: char) -> ClapResult<()> {
+ debugln!("Parser::check_for_help_and_version_char;");
+ debug!(
+ "Parser::check_for_help_and_version_char: Checking if -{} is help or version...",
+ arg
+ );
+ if let Some(h) = self.help_short {
+ if arg == h && self.is_set(AS::NeedsLongHelp) {
+ sdebugln!("Help");
+ return Err(self._help(false));
+ }
+ }
+ if let Some(v) = self.version_short {
+ if arg == v && self.is_set(AS::NeedsLongVersion) {
+ sdebugln!("Version");
+ return Err(self._version(false));
+ }
+ }
+ sdebugln!("Neither");
+ Ok(())
+ }
+
+ fn use_long_help(&self) -> bool {
+ // In this case, both must be checked. This allows the retention of
+ // original formatting, but also ensures that the actual -h or --help
+ // specified by the user is sent through. If HiddenShortHelp is not included,
+ // then items specified with hidden_short_help will also be hidden.
+ let should_long = |v: &Base| {
+ v.long_help.is_some() ||
+ v.is_set(ArgSettings::HiddenLongHelp) ||
+ v.is_set(ArgSettings::HiddenShortHelp)
+ };
+
+ self.meta.long_about.is_some()
+ || self.flags.iter().any(|f| should_long(&f.b))
+ || self.opts.iter().any(|o| should_long(&o.b))
+ || self.positionals.values().any(|p| should_long(&p.b))
+ || self.subcommands
+ .iter()
+ .any(|s| s.p.meta.long_about.is_some())
+ }
+
+ fn _help(&self, mut use_long: bool) -> Error {
+ debugln!("Parser::_help: use_long={:?}", use_long);
+ use_long = use_long && self.use_long_help();
+ let mut buf = vec![];
+ match Help::write_parser_help(&mut buf, self, use_long) {
+ Err(e) => e,
+ _ => Error {
+ message: String::from_utf8(buf).unwrap_or_default(),
+ kind: ErrorKind::HelpDisplayed,
+ info: None,
+ },
+ }
+ }
+
+ fn _version(&self, use_long: bool) -> Error {
+ debugln!("Parser::_version: ");
+ let out = io::stdout();
+ let mut buf_w = BufWriter::new(out.lock());
+ match self.print_version(&mut buf_w, use_long) {
+ Err(e) => e,
+ _ => Error {
+ message: String::new(),
+ kind: ErrorKind::VersionDisplayed,
+ info: None,
+ },
+ }
+ }
+
+ fn parse_long_arg<I, T>(
+ &mut self,
+ matcher: &mut ArgMatcher<'a>,
+ full_arg: &OsStr,
+ it: &mut Peekable<I>,
+ ) -> ClapResult<ParseResult<'a>>
+ where
+ I: Iterator<Item = T>,
+ T: Into<OsString> + Clone,
+ {
+ // maybe here lifetime should be 'a
+ debugln!("Parser::parse_long_arg;");
+
+ // Update the current index
+ self.cur_idx.set(self.cur_idx.get() + 1);
+
+ let mut val = None;
+ debug!("Parser::parse_long_arg: Does it contain '='...");
+ let arg = if full_arg.contains_byte(b'=') {
+ let (p0, p1) = full_arg.trim_left_matches(b'-').split_at_byte(b'=');
+ sdebugln!("Yes '{:?}'", p1);
+ val = Some(p1);
+ p0
+ } else {
+ sdebugln!("No");
+ full_arg.trim_left_matches(b'-')
+ };
+
+ if let Some(opt) = find_opt_by_long!(@os self, arg) {
+ debugln!(
+ "Parser::parse_long_arg: Found valid opt '{}'",
+ opt.to_string()
+ );
+ self.settings.set(AS::ValidArgFound);
+ let ret = self.parse_opt(val, opt, val.is_some(), matcher)?;
+ if self.cache.map_or(true, |name| name != opt.b.name) {
+ self.cache = Some(opt.b.name);
+ }
+
+ return Ok(ret);
+ } else if let Some(flag) = find_flag_by_long!(@os self, arg) {
+ debugln!(
+ "Parser::parse_long_arg: Found valid flag '{}'",
+ flag.to_string()
+ );
+ self.settings.set(AS::ValidArgFound);
+ // Only flags could be help or version, and we need to check the raw long
+ // so this is the first point to check
+ self.check_for_help_and_version_str(arg)?;
+
+ self.parse_flag(flag, matcher)?;
+
+ // Handle conflicts, requirements, etc.
+ if self.cache.map_or(true, |name| name != flag.b.name) {
+ self.cache = Some(flag.b.name);
+ }
+
+ return Ok(ParseResult::Flag);
+ } else if self.is_set(AS::AllowLeadingHyphen) {
+ return Ok(ParseResult::MaybeHyphenValue);
+ } else if self.is_set(AS::ValidNegNumFound) {
+ return Ok(ParseResult::MaybeNegNum);
+ }
+
+ debugln!("Parser::parse_long_arg: Didn't match anything");
+
+ let args_rest: Vec<_> = it.map(|x| x.clone().into()).collect();
+ let args_rest2: Vec<_> = args_rest.iter().map(|x| x.to_str().expect(INVALID_UTF8)).collect();
+ self.did_you_mean_error(
+ arg.to_str().expect(INVALID_UTF8),
+ matcher,
+ &args_rest2[..]
+ ).map(|_| ParseResult::NotFound)
+ }
+
+ #[cfg_attr(feature = "lints", allow(len_zero))]
+ fn parse_short_arg(
+ &mut self,
+ matcher: &mut ArgMatcher<'a>,
+ full_arg: &OsStr,
+ ) -> ClapResult<ParseResult<'a>> {
+ debugln!("Parser::parse_short_arg: full_arg={:?}", full_arg);
+ let arg_os = full_arg.trim_left_matches(b'-');
+ let arg = arg_os.to_string_lossy();
+
+ // If AllowLeadingHyphen is set, we want to ensure `-val` gets parsed as `-val` and not
+ // `-v` `-a` `-l` assuming `v` `a` and `l` are all, or mostly, valid shorts.
+ if self.is_set(AS::AllowLeadingHyphen) {
+ if arg.chars().any(|c| !self.contains_short(c)) {
+ debugln!(
+ "Parser::parse_short_arg: LeadingHyphenAllowed yet -{} isn't valid",
+ arg
+ );
+ return Ok(ParseResult::MaybeHyphenValue);
+ }
+ } else if self.is_set(AS::ValidNegNumFound) {
+ // TODO: Add docs about having AllowNegativeNumbers and `-2` as a valid short
+ // May be better to move this to *after* not finding a valid flag/opt?
+ debugln!("Parser::parse_short_arg: Valid negative num...");
+ return Ok(ParseResult::MaybeNegNum);
+ }
+
+ let mut ret = ParseResult::NotFound;
+ for c in arg.chars() {
+ debugln!("Parser::parse_short_arg:iter:{}", c);
+
+ // update each index because `-abcd` is four indices to clap
+ self.cur_idx.set(self.cur_idx.get() + 1);
+
+ // Check for matching short options, and return the name if there is no trailing
+ // concatenated value: -oval
+ // Option: -o
+ // Value: val
+ if let Some(opt) = find_opt_by_short!(self, c) {
+ debugln!("Parser::parse_short_arg:iter:{}: Found valid opt", c);
+ self.settings.set(AS::ValidArgFound);
+ // Check for trailing concatenated value
+ let p: Vec<_> = arg.splitn(2, c).collect();
+ debugln!(
+ "Parser::parse_short_arg:iter:{}: p[0]={:?}, p[1]={:?}",
+ c,
+ p[0].as_bytes(),
+ p[1].as_bytes()
+ );
+ let i = p[0].as_bytes().len() + 1;
+ let val = if p[1].as_bytes().len() > 0 {
+ debugln!(
+ "Parser::parse_short_arg:iter:{}: val={:?} (bytes), val={:?} (ascii)",
+ c,
+ arg_os.split_at(i).1.as_bytes(),
+ arg_os.split_at(i).1
+ );
+ Some(arg_os.split_at(i).1)
+ } else {
+ None
+ };
+
+ // Default to "we're expecting a value later"
+ let ret = self.parse_opt(val, opt, false, matcher)?;
+
+ if self.cache.map_or(true, |name| name != opt.b.name) {
+ self.cache = Some(opt.b.name);
+ }
+
+ return Ok(ret);
+ } else if let Some(flag) = find_flag_by_short!(self, c) {
+ debugln!("Parser::parse_short_arg:iter:{}: Found valid flag", c);
+ self.settings.set(AS::ValidArgFound);
+ // Only flags can be help or version
+ self.check_for_help_and_version_char(c)?;
+ ret = self.parse_flag(flag, matcher)?;
+
+ // Handle conflicts, requirements, overrides, etc.
+ // Must be called here due to mutabililty
+ if self.cache.map_or(true, |name| name != flag.b.name) {
+ self.cache = Some(flag.b.name);
+ }
+ } else {
+ let arg = format!("-{}", c);
+ return Err(Error::unknown_argument(
+ &*arg,
+ "",
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ }
+ }
+ Ok(ret)
+ }
+
+ fn parse_opt(
+ &self,
+ val: Option<&OsStr>,
+ opt: &OptBuilder<'a, 'b>,
+ had_eq: bool,
+ matcher: &mut ArgMatcher<'a>,
+ ) -> ClapResult<ParseResult<'a>> {
+ debugln!("Parser::parse_opt; opt={}, val={:?}", opt.b.name, val);
+ debugln!("Parser::parse_opt; opt.settings={:?}", opt.b.settings);
+ let mut has_eq = false;
+ let no_val = val.is_none();
+ let empty_vals = opt.is_set(ArgSettings::EmptyValues);
+ let min_vals_zero = opt.v.min_vals.unwrap_or(1) == 0;
+ let needs_eq = opt.is_set(ArgSettings::RequireEquals);
+
+ debug!("Parser::parse_opt; Checking for val...");
+ if let Some(fv) = val {
+ has_eq = fv.starts_with(&[b'=']) || had_eq;
+ let v = fv.trim_left_matches(b'=');
+ if !empty_vals && (v.len() == 0 || (needs_eq && !has_eq)) {
+ sdebugln!("Found Empty - Error");
+ return Err(Error::empty_value(
+ opt,
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ }
+ sdebugln!("Found - {:?}, len: {}", v, v.len());
+ debugln!(
+ "Parser::parse_opt: {:?} contains '='...{:?}",
+ fv,
+ fv.starts_with(&[b'='])
+ );
+ self.add_val_to_arg(opt, v, matcher)?;
+ } else if needs_eq && !(empty_vals || min_vals_zero) {
+ sdebugln!("None, but requires equals...Error");
+ return Err(Error::empty_value(
+ opt,
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ } else {
+ sdebugln!("None");
+ }
+
+ matcher.inc_occurrence_of(opt.b.name);
+ // Increment or create the group "args"
+ self.groups_for_arg(opt.b.name)
+ .and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));
+
+ let needs_delim = opt.is_set(ArgSettings::RequireDelimiter);
+ let mult = opt.is_set(ArgSettings::Multiple);
+ if no_val && min_vals_zero && !has_eq && needs_eq {
+ debugln!("Parser::parse_opt: More arg vals not required...");
+ return Ok(ParseResult::ValuesDone);
+ } else if no_val || (mult && !needs_delim) && !has_eq && matcher.needs_more_vals(opt) {
+ debugln!("Parser::parse_opt: More arg vals required...");
+ return Ok(ParseResult::Opt(opt.b.name));
+ }
+ debugln!("Parser::parse_opt: More arg vals not required...");
+ Ok(ParseResult::ValuesDone)
+ }
+
+ fn add_val_to_arg<A>(
+ &self,
+ arg: &A,
+ val: &OsStr,
+ matcher: &mut ArgMatcher<'a>,
+ ) -> ClapResult<ParseResult<'a>>
+ where
+ A: AnyArg<'a, 'b> + Display,
+ {
+ debugln!("Parser::add_val_to_arg; arg={}, val={:?}", arg.name(), val);
+ debugln!(
+ "Parser::add_val_to_arg; trailing_vals={:?}, DontDelimTrailingVals={:?}",
+ self.is_set(AS::TrailingValues),
+ self.is_set(AS::DontDelimitTrailingValues)
+ );
+ if !(self.is_set(AS::TrailingValues) && self.is_set(AS::DontDelimitTrailingValues)) {
+ if let Some(delim) = arg.val_delim() {
+ if val.is_empty() {
+ Ok(self.add_single_val_to_arg(arg, val, matcher)?)
+ } else {
+ let mut iret = ParseResult::ValuesDone;
+ for v in val.split(delim as u32 as u8) {
+ iret = self.add_single_val_to_arg(arg, v, matcher)?;
+ }
+ // If there was a delimiter used, we're not looking for more values
+ if val.contains_byte(delim as u32 as u8)
+ || arg.is_set(ArgSettings::RequireDelimiter)
+ {
+ iret = ParseResult::ValuesDone;
+ }
+ Ok(iret)
+ }
+ } else {
+ self.add_single_val_to_arg(arg, val, matcher)
+ }
+ } else {
+ self.add_single_val_to_arg(arg, val, matcher)
+ }
+ }
+
+ fn add_single_val_to_arg<A>(
+ &self,
+ arg: &A,
+ v: &OsStr,
+ matcher: &mut ArgMatcher<'a>,
+ ) -> ClapResult<ParseResult<'a>>
+ where
+ A: AnyArg<'a, 'b> + Display,
+ {
+ debugln!("Parser::add_single_val_to_arg;");
+ debugln!("Parser::add_single_val_to_arg: adding val...{:?}", v);
+
+ // update the current index because each value is a distinct index to clap
+ self.cur_idx.set(self.cur_idx.get() + 1);
+
+ // @TODO @docs @p4: docs for indices should probably note that a terminator isn't a value
+ // and therefore not reported in indices
+ if let Some(t) = arg.val_terminator() {
+ if t == v {
+ return Ok(ParseResult::ValuesDone);
+ }
+ }
+
+ matcher.add_val_to(arg.name(), v);
+ matcher.add_index_to(arg.name(), self.cur_idx.get());
+
+ // Increment or create the group "args"
+ if let Some(grps) = self.groups_for_arg(arg.name()) {
+ for grp in grps {
+ matcher.add_val_to(&*grp, v);
+ }
+ }
+
+ if matcher.needs_more_vals(arg) {
+ return Ok(ParseResult::Opt(arg.name()));
+ }
+ Ok(ParseResult::ValuesDone)
+ }
+
+ fn parse_flag(
+ &self,
+ flag: &FlagBuilder<'a, 'b>,
+ matcher: &mut ArgMatcher<'a>,
+ ) -> ClapResult<ParseResult<'a>> {
+ debugln!("Parser::parse_flag;");
+
+ matcher.inc_occurrence_of(flag.b.name);
+ matcher.add_index_to(flag.b.name, self.cur_idx.get());
+
+ // Increment or create the group "args"
+ self.groups_for_arg(flag.b.name)
+ .and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));
+
+ Ok(ParseResult::Flag)
+ }
+
+ fn did_you_mean_error(&self, arg: &str, matcher: &mut ArgMatcher<'a>, args_rest: &[&str]) -> ClapResult<()> {
+ // Didn't match a flag or option
+ let suffix = suggestions::did_you_mean_flag_suffix(arg, &args_rest, longs!(self), &self.subcommands);
+
+ // Add the arg to the matches to build a proper usage string
+ if let Some(name) = suffix.1 {
+ if let Some(opt) = find_opt_by_long!(self, name) {
+ self.groups_for_arg(&*opt.b.name)
+ .and_then(|grps| Some(matcher.inc_occurrences_of(&*grps)));
+ matcher.insert(&*opt.b.name);
+ } else if let Some(flg) = find_flag_by_long!(self, name) {
+ self.groups_for_arg(&*flg.b.name)
+ .and_then(|grps| Some(matcher.inc_occurrences_of(&*grps)));
+ matcher.insert(&*flg.b.name);
+ }
+ }
+
+ let used_arg = format!("--{}", arg);
+ Err(Error::unknown_argument(
+ &*used_arg,
+ &*suffix.0,
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ))
+ }
+
+ // Prints the version to the user and exits if quit=true
+ fn print_version<W: Write>(&self, w: &mut W, use_long: bool) -> ClapResult<()> {
+ self.write_version(w, use_long)?;
+ w.flush().map_err(Error::from)
+ }
+
+ 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_else(|| self.meta.version.unwrap_or(""))
+ } else {
+ self.meta
+ .version
+ .unwrap_or_else(|| self.meta.long_version.unwrap_or(""))
+ };
+ if let Some(bn) = self.meta.bin_name.as_ref() {
+ if bn.contains(' ') {
+ // Incase we're dealing with subcommands i.e. git mv is translated to git-mv
+ write!(w, "{} {}", bn.replace(" ", "-"), ver)
+ } else {
+ write!(w, "{} {}", &self.meta.name[..], ver)
+ }
+ } else {
+ write!(w, "{} {}", &self.meta.name[..], ver)
+ }
+ }
+
+ pub fn print_help(&self) -> ClapResult<()> {
+ let out = io::stdout();
+ let mut buf_w = BufWriter::new(out.lock());
+ self.write_help(&mut buf_w)
+ }
+
+ pub fn write_help<W: Write>(&self, w: &mut W) -> ClapResult<()> {
+ Help::write_parser_help(w, self, false)
+ }
+
+ pub fn write_long_help<W: Write>(&self, w: &mut W) -> ClapResult<()> {
+ Help::write_parser_help(w, self, true)
+ }
+
+ pub fn write_help_err<W: Write>(&self, w: &mut W) -> ClapResult<()> {
+ Help::write_parser_help_to_stderr(w, self)
+ }
+
+ pub fn add_defaults(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
+ debugln!("Parser::add_defaults;");
+ macro_rules! add_val {
+ (@default $_self:ident, $a:ident, $m:ident) => {
+ if let Some(ref val) = $a.v.default_val {
+ debugln!("Parser::add_defaults:iter:{}: has default vals", $a.b.name);
+ if $m.get($a.b.name).map(|ma| ma.vals.len()).map(|len| len == 0).unwrap_or(false) {
+ debugln!("Parser::add_defaults:iter:{}: has no user defined vals", $a.b.name);
+ $_self.add_val_to_arg($a, OsStr::new(val), $m)?;
+
+ if $_self.cache.map_or(true, |name| name != $a.name()) {
+ $_self.cache = Some($a.name());
+ }
+ } else if $m.get($a.b.name).is_some() {
+ debugln!("Parser::add_defaults:iter:{}: has user defined vals", $a.b.name);
+ } else {
+ debugln!("Parser::add_defaults:iter:{}: wasn't used", $a.b.name);
+
+ $_self.add_val_to_arg($a, OsStr::new(val), $m)?;
+
+ if $_self.cache.map_or(true, |name| name != $a.name()) {
+ $_self.cache = Some($a.name());
+ }
+ }
+ } else {
+ debugln!("Parser::add_defaults:iter:{}: doesn't have default vals", $a.b.name);
+ }
+ };
+ ($_self:ident, $a:ident, $m:ident) => {
+ if let Some(ref vm) = $a.v.default_vals_ifs {
+ sdebugln!(" has conditional defaults");
+ let mut done = false;
+ if $m.get($a.b.name).is_none() {
+ for &(arg, val, default) in vm.values() {
+ let add = if let Some(a) = $m.get(arg) {
+ if let Some(v) = val {
+ a.vals.iter().any(|value| v == value)
+ } else {
+ true
+ }
+ } else {
+ false
+ };
+ if add {
+ $_self.add_val_to_arg($a, OsStr::new(default), $m)?;
+ if $_self.cache.map_or(true, |name| name != $a.name()) {
+ $_self.cache = Some($a.name());
+ }
+ done = true;
+ break;
+ }
+ }
+ }
+
+ if done {
+ continue; // outer loop (outside macro)
+ }
+ } else {
+ sdebugln!(" doesn't have conditional defaults");
+ }
+ add_val!(@default $_self, $a, $m)
+ };
+ }
+
+ for o in &self.opts {
+ debug!("Parser::add_defaults:iter:{}:", o.b.name);
+ add_val!(self, o, matcher);
+ }
+ for p in self.positionals.values() {
+ debug!("Parser::add_defaults:iter:{}:", p.b.name);
+ add_val!(self, p, matcher);
+ }
+ Ok(())
+ }
+
+ pub fn add_env(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
+ macro_rules! add_val {
+ ($_self:ident, $a:ident, $m:ident) => {
+ if let Some(ref val) = $a.v.env {
+ if $m.get($a.b.name).map(|ma| ma.vals.len()).map(|len| len == 0).unwrap_or(false) {
+ if let Some(ref val) = val.1 {
+ $_self.add_val_to_arg($a, OsStr::new(val), $m)?;
+
+ if $_self.cache.map_or(true, |name| name != $a.name()) {
+ $_self.cache = Some($a.name());
+ }
+ }
+ } else {
+ if let Some(ref val) = val.1 {
+ $_self.add_val_to_arg($a, OsStr::new(val), $m)?;
+
+ if $_self.cache.map_or(true, |name| name != $a.name()) {
+ $_self.cache = Some($a.name());
+ }
+ }
+ }
+ }
+ };
+ }
+
+ for o in &self.opts {
+ add_val!(self, o, matcher);
+ }
+ for p in self.positionals.values() {
+ add_val!(self, p, matcher);
+ }
+ Ok(())
+ }
+
+ pub fn flags(&self) -> Iter<FlagBuilder<'a, 'b>> { self.flags.iter() }
+
+ pub fn opts(&self) -> Iter<OptBuilder<'a, 'b>> { self.opts.iter() }
+
+ pub fn positionals(&self) -> map::Values<PosBuilder<'a, 'b>> { self.positionals.values() }
+
+ pub fn subcommands(&self) -> Iter<App> { self.subcommands.iter() }
+
+ // Should we color the output? None=determined by output location, true=yes, false=no
+ #[doc(hidden)]
+ pub fn color(&self) -> ColorWhen {
+ debugln!("Parser::color;");
+ debug!("Parser::color: Color setting...");
+ if self.is_set(AS::ColorNever) {
+ sdebugln!("Never");
+ ColorWhen::Never
+ } else if self.is_set(AS::ColorAlways) {
+ sdebugln!("Always");
+ ColorWhen::Always
+ } else {
+ sdebugln!("Auto");
+ ColorWhen::Auto
+ }
+ }
+
+ pub fn find_any_arg(&self, name: &str) -> Option<&AnyArg<'a, 'b>> {
+ if let Some(f) = find_by_name!(self, name, flags, iter) {
+ return Some(f);
+ }
+ if let Some(o) = find_by_name!(self, name, opts, iter) {
+ return Some(o);
+ }
+ if let Some(p) = find_by_name!(self, name, positionals, values) {
+ return Some(p);
+ }
+ None
+ }
+
+ /// Check is a given string matches the binary name for this parser
+ fn is_bin_name(&self, value: &str) -> bool {
+ self.meta
+ .bin_name
+ .as_ref()
+ .and_then(|name| Some(value == name))
+ .unwrap_or(false)
+ }
+
+ /// Check is a given string is an alias for this parser
+ fn is_alias(&self, value: &str) -> bool {
+ self.meta
+ .aliases
+ .as_ref()
+ .and_then(|aliases| {
+ for alias in aliases {
+ if alias.0 == value {
+ return Some(true);
+ }
+ }
+ Some(false)
+ })
+ .unwrap_or(false)
+ }
+
+ // Only used for completion scripts due to bin_name messiness
+ #[cfg_attr(feature = "lints", allow(block_in_if_condition_stmt))]
+ pub fn find_subcommand(&'b self, sc: &str) -> Option<&'b App<'a, 'b>> {
+ debugln!("Parser::find_subcommand: sc={}", sc);
+ debugln!(
+ "Parser::find_subcommand: Currently in Parser...{}",
+ self.meta.bin_name.as_ref().unwrap()
+ );
+ for s in &self.subcommands {
+ if s.p.is_bin_name(sc) {
+ return Some(s);
+ }
+ // XXX: why do we split here?
+ // isn't `sc` supposed to be single word already?
+ let last = sc.split(' ').rev().next().expect(INTERNAL_ERROR_MSG);
+ if s.p.is_alias(last) {
+ return Some(s);
+ }
+
+ if let Some(app) = s.p.find_subcommand(sc) {
+ return Some(app);
+ }
+ }
+ None
+ }
+
+ #[inline]
+ fn contains_long(&self, l: &str) -> bool { longs!(self).any(|al| al == &l) }
+
+ #[inline]
+ fn contains_short(&self, s: char) -> bool { shorts!(self).any(|arg_s| arg_s == &s) }
+}