diff --git a/src/app/mod.rs b/src/app/mod.rs index 9711ba56..191b9994 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -10,6 +10,7 @@ use std::path::Path; use std::process; use std::ffi::OsStr; use std::borrow::Borrow; +use std::fmt::Display; #[cfg(feature = "yaml")] use yaml_rust::Yaml; @@ -18,7 +19,7 @@ use vec_map::VecMap; use args::{Arg, ArgMatches, MatchedArg, SubCommand}; use args::{FlagBuilder, OptBuilder, PosBuilder}; use args::settings::{ArgFlags, ArgSettings}; -use args::ArgGroup; +use args::{ArgGroup, AnyArg}; use fmt::Format; use self::settings::AppFlags; use suggestions; @@ -3059,43 +3060,12 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar> { matches: &mut ArgMatches<'ar, 'ar>, arg: char) -> ClapResult { - if let Some(v) = self.flags - .iter() - .filter(|&v| v.short.is_some() && v.short.unwrap() == arg) - .next() { - // Ensure this flag isn't on the mutually excludes list - if self.blacklist.contains(&v.name) { - matches.args.remove(v.name); - return Err(error_builder::ArgumentConflict( - v.to_string(), - self.blacklisted_from(v.name, &matches), - try!(self.create_current_usage(matches)))); - } - if self.overrides.contains(&v.name) { - debugln!("it is..."); - debugln!("checking who defined it..."); - if let Some(ref name) = self.overriden_from(v.name, matches) { - debugln!("found {}", name); - matches.args.remove(name); - remove_overriden!(self, name); - } - } - if let Some(ref or) = v.overrides { - for pa in or { - matches.args.remove(pa); - remove_overriden!(self, pa); - self.overrides.push(pa); - } - } + let v = self.flags.iter().filter(|&v| v.short.is_some() && v.short.unwrap() == arg).next(); + if v.is_some() { + let flag = v.unwrap(); + try!(self.validate_arg(flag, matches)); - // Make sure this isn't one being added multiple times if it doesn't suppor it - if matches.args.contains_key(v.name) && !v.settings.is_set(&ArgSettings::Multiple) { - return Err(error_builder::UnexpectedMultipleUsage( - &*format!("-{}", arg), - &*try!(self.create_current_usage(matches)))); - } - - if let Some(ref vec) = self.groups_for_arg(v.name) { + if let Some(ref vec) = self.groups_for_arg(flag.name) { for grp in vec { if let Some(ref mut f) = matches.args.get_mut(grp) { f.occurrences = if v.settings.is_set(&ArgSettings::Multiple) { @@ -3159,6 +3129,40 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar> { Ok(false) } + fn validate_arg(&mut self, arg: &A, matches: &mut ArgMatches<'ar, 'ar>) -> ClapResult<()> + where A: AnyArg<'ar> + Display { + // Ensure this arg isn't on the mutually excludes list + if self.blacklist.contains(&arg.name()) { + matches.args.remove(arg.name()); + return Err(error_builder::ArgumentConflict( + arg.to_string(), + self.blacklisted_from(arg.name(), &matches), + try!(self.create_current_usage(matches)))); + } + if self.overrides.contains(&arg.name()) { + if let Some(ref name) = self.overriden_from(arg.name(), matches) { + matches.args.remove(name); + remove_overriden!(self, name); + } + } + if let Some(or) = arg.overrides() { + for pa in or { + matches.args.remove(pa); + remove_overriden!(self, pa); + self.overrides.push(pa); + } + } + + // Make sure this isn't one being added multiple times if it doesn't suppor it + if matches.args.contains_key(arg.name()) && !arg.is_set(&ArgSettings::Multiple) { + return Err(error_builder::UnexpectedMultipleUsage( + &*format!("-{}", arg), + &*try!(self.create_current_usage(matches)))); + } + + Ok(()) + } + fn validate_blacklist(&self, matches: &mut ArgMatches<'ar, 'ar>) -> ClapResult<()> { for name in self.blacklist.iter() { if matches.args.contains_key(name) { @@ -3254,8 +3258,8 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar> { return Err(error_builder::TooManyValues( vals.get(vals.keys() .last() - .expect("error getting last key. This is a bug")) - .expect("failed to retrieve last value. This is a bug"), + .expect(INTERNAL_ERROR_MSG)) + .expect(INTERNAL_ERROR_MSG), &f.to_string(), &try!(self.create_current_usage(matches)))); } diff --git a/src/args/any_arg.rs b/src/args/any_arg.rs new file mode 100644 index 00000000..00728419 --- /dev/null +++ b/src/args/any_arg.rs @@ -0,0 +1,8 @@ +use args::settings::ArgSettings; + +pub trait AnyArg<'n> { + fn name(&self) -> &'n str; + fn overrides(&self) -> Option<&[&'n str]>; + fn is_set(&self, &ArgSettings) -> bool; + fn set(&mut self, &ArgSettings); +} diff --git a/src/args/arg_builder/flag.rs b/src/args/arg_builder/flag.rs index 861096e8..1d9dac9e 100644 --- a/src/args/arg_builder/flag.rs +++ b/src/args/arg_builder/flag.rs @@ -4,6 +4,7 @@ use std::convert::From; use std::io; use Arg; +use args::AnyArg; use args::settings::{ArgFlags, ArgSettings}; #[derive(Debug)] @@ -167,6 +168,25 @@ impl<'n> Display for FlagBuilder<'n> { } } } + +impl<'n> AnyArg<'n> for FlagBuilder<'n> { + fn name(&self) -> &'n str { + self.name + } + + fn overrides(&self) -> Option<&[&'n str]> { + self.overrides.as_ref().map(|o| &o[..]) + } + + fn is_set(&self, s: &ArgSettings) -> bool { + self.settings.is_set(s) + } + + fn set(&mut self, s: &ArgSettings) { + self.settings.set(s) + } +} + #[cfg(test)] mod test { use super::FlagBuilder; diff --git a/src/args/mod.rs b/src/args/mod.rs index 97dd8b71..b8ac2fa8 100644 --- a/src/args/mod.rs +++ b/src/args/mod.rs @@ -1,15 +1,18 @@ pub use self::arg::Arg; -pub use self::argmatches::ArgMatches; +pub use self::arg_matches::ArgMatches; pub use self::subcommand::SubCommand; -pub use self::argbuilder::{FlagBuilder, OptBuilder, PosBuilder}; -pub use self::matchedarg::MatchedArg; +pub use self::arg_builder::{FlagBuilder, OptBuilder, PosBuilder}; +pub use self::matched_arg::MatchedArg; pub use self::group::ArgGroup; +pub use self::any_arg::AnyArg; mod arg; -mod argmatches; +pub mod any_arg; +mod arg_matches; +mod arg_matcher; mod subcommand; -mod argbuilder; -mod matchedarg; +mod arg_builder; +mod matched_arg; mod group; #[allow(dead_code)] pub mod settings;