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, 0 insertions, 2167 deletions
diff --git a/clap/src/app/parser.rs b/clap/src/app/parser.rs
deleted file mode 100644
index decfde4..0000000
--- a/clap/src/app/parser.rs
+++ /dev/null
@@ -1,2167 +0,0 @@
-// 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) }
-}