refactor: changes some arg fields to flags internally

This commit is contained in:
Kevin K 2015-09-30 23:07:28 -04:00
parent 7005cf8c47
commit b01667ebb3
9 changed files with 257 additions and 230 deletions

View file

@ -12,6 +12,7 @@ use yaml_rust::Yaml;
use args::{ArgMatches, Arg, SubCommand, MatchedArg};
use args::{FlagBuilder, OptBuilder, PosBuilder};
use args::settings::{ArgSettings, ArgFlags};
use args::ArgGroup;
use fmt::Format;
use super::settings::{AppSettings, AppFlags};
@ -790,7 +791,6 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
}
if let Some(l) = a.long {
// self.long_list.dedup();
if self.long_list.contains(&l) {
panic!("Argument long must be unique\n\n\t--{} is already in use", l);
} else {
@ -1084,7 +1084,6 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
}
}
res.dedup();
if res.is_empty() { return None }
Some(res)
@ -1112,7 +1111,6 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
}
g_vec.dedup();
if !g_vec.is_empty() {
for av in g_vec.iter().map(|g| self.get_group_members(g)) {
for a in av {
@ -1145,7 +1143,6 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
}
g_vec.dedup();
if !g_vec.is_empty() {
for av in g_vec.iter().map(|g| self.get_group_members_names(g)) {
for a in av {
@ -1159,10 +1156,9 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
fn get_required_from(&self,
mut reqs: Vec<&'ar str>,
reqs: Vec<&'ar str>,
matches: Option<&ArgMatches>)
-> VecDeque<String> {
reqs.dedup();
let mut c_flags = vec![];
let mut c_pos = vec![];
let mut c_opt = vec![];
@ -1318,7 +1314,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
reqs.push(p.name);
continue;
}
if p.required {
if p.settings.is_set(&ArgSettings::Required) {
found = true;
reqs.push(p.name);
}
@ -1336,19 +1332,19 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
usage.push_str(" [OPTIONS]");
}
if !self.settings.is_set(&AppSettings::UnifiedHelpMessage) && !self.opts.is_empty() &&
self.opts.values().any(|a| !a.required) {
self.opts.values().any(|a| !a.settings.is_set(&ArgSettings::Required)) {
usage.push_str(" [OPTIONS]");
}
// places a '--' in the usage string if there are args and options
// supporting multiple values
if !self.positionals_idx.is_empty() && self.opts.values().any(|a| a.multiple ) &&
!self.opts.values().any(|a| a.required) &&
if !self.positionals_idx.is_empty() && self.opts.values().any(|a| a.settings.is_set(&ArgSettings::Multiple)) &&
!self.opts.values().any(|a| a.settings.is_set(&ArgSettings::Required)) &&
self.subcommands.is_empty() {
usage.push_str(" [--]")
}
if !self.positionals_idx.is_empty() &&
self.positionals_idx.values()
.any(|a| !a.required) {
.any(|a| !a.settings.is_set(&ArgSettings::Required)) {
usage.push_str(" [ARGS]");
}
@ -1412,7 +1408,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
let mut longest_flag = 0;
for fl in self.flags
.values()
.filter(|f| f.long.is_some() && !f.hidden)
.filter(|f| f.long.is_some() && !f.settings.is_set(&ArgSettings::Hidden))
// 2='--'
.map(|a| a.to_string().len() ) {
if fl > longest_flag {
@ -1422,7 +1418,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
let mut longest_opt = 0;
for ol in self.opts
.values()
.filter(|o| !o.hidden)
.filter(|o| !o.settings.is_set(&ArgSettings::Hidden))
.map(|a|
a.to_string().len()
) {
@ -1433,7 +1429,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
let mut longest_pos = 0;
for pl in self.positionals_idx
.values()
.filter(|p| !p.hidden)
.filter(|p| !p.settings.is_set(&ArgSettings::Hidden))
.map(|f| f.to_string().len() ) {
if pl > longest_pos {
longest_pos = pl;
@ -1471,7 +1467,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
for v in self.flags
.values()
.filter(|f| !f.hidden) {
.filter(|f| !f.settings.is_set(&ArgSettings::Hidden)) {
try!(write!(w, "{}", tab));
if let Some(s) = v.short {
try!(write!(w, "-{}",s));
@ -1530,7 +1526,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
for v in self.opts
.values()
.filter(|o| !o.hidden) {
.filter(|o| !o.settings.is_set(&ArgSettings::Hidden)) {
// if it supports multiple we add '...' i.e. 3 to the name length
try!(write!(w, "{}", tab));
if let Some(s) = v.short {
@ -1550,7 +1546,13 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
try!(write!(w, " <{}>", v.name));
}
} else {
try!(write!(w, " <{}>{}", v.name, if v.multiple{"..."} else {""}));
try!(write!(w, " <{}>{}", v.name,
if v.settings.is_set(&ArgSettings::Multiple) {
"..."
} else {
""
}
));
}
if v.long.is_some() {
try!(self.print_spaces(
@ -1568,11 +1570,10 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
try!(write!(w, "\nARGS:\n"));
for v in self.positionals_idx
.values()
.filter(|p| !p.hidden) {
// let mult = if v.multiple { 3 } else { 0 };
.filter(|p| !p.settings.is_set(&ArgSettings::Hidden)) {
try!(write!(w, "{}", tab));
try!(write!(w, "{}", v.name));
if v.multiple {
if v.settings.is_set(&ArgSettings::Multiple) {
try!(write!(w, "..."));
}
try!(self.print_spaces((longest_pos + 4) - (v.to_string().len()), w));
@ -2024,7 +2025,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
}
if let Some(ref p) = self.positionals_idx.values()
.filter(|a| a.multiple)
.filter(|a| a.settings.is_set(&ArgSettings::Multiple))
.filter(|a| {
a.index as usize != self.positionals_idx.len()
})
@ -2037,11 +2038,11 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
let mut found = false;
for (_, p) in self.positionals_idx.iter_mut().rev() {
if found {
p.required = true;
p.settings.set(&ArgSettings::Required);
self.required.push(p.name);
continue;
}
if p.required {
if p.settings.is_set(&ArgSettings::Required) {
found = true;
}
}
@ -2152,7 +2153,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
if let Some(num) = opt.num_vals {
if let Some(ref ma) = matches.args.get(opt.name) {
if let Some(ref vals) = ma.values {
if num == vals.len() as u8 && !opt.multiple {
if num == vals.len() as u8 && !opt.settings.is_set(&ArgSettings::Multiple) {
return Err(self.report_error(format!("The argument '{}' \
was found, but '{}' only expects {} values",
Format::Warning(arg_slice),
@ -2166,7 +2167,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
// if it's an empty value, and we don't allow that, report the error
if !opt.empty_vals && matches.args.contains_key(opt.name) &&
if !opt.settings.is_set(&ArgSettings::EmptyValues) && matches.args.contains_key(opt.name) &&
arg_slice.is_empty() {
return Err(self.report_error(
format!("The argument '{}' does not allow empty values, but one \
@ -2178,7 +2179,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
if let Some(ref vec) = self.groups_for(opt.name) {
for grp in vec {
if let Some(ref mut o) = matches.args.get_mut(grp) {
o.occurrences = if opt.multiple {
o.occurrences = if opt.settings.is_set(&ArgSettings::Multiple) {
o.occurrences + 1
} else {
1
@ -2196,7 +2197,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
if let Some(ref mut o) = matches.args.get_mut(opt.name) {
// if it's multiple; the occurrences are increased when originally
// found
o.occurrences = if opt.multiple {
o.occurrences = if opt.settings.is_set(&ArgSettings::Multiple) {
o.occurrences + 1
} else {
skip = true;
@ -2232,7 +2233,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
continue
}
} else if let Some(num) = opt.num_vals {
if opt.multiple {
if opt.settings.is_set(&ArgSettings::Multiple) {
val_counter += 1;
if val_counter != num {
continue
@ -2263,7 +2264,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
} else if let Some(ref name) = needs_val_of {
// We've reached more values for an option than it possibly accepts
if let Some(ref o) = self.opts.get(name) {
if !o.multiple {
if !o.settings.is_set(&ArgSettings::Multiple) {
return Err(self.report_error(
format!("The argument '{}' requires a value but none was supplied",
Format::Warning(o.to_string())),
@ -2340,12 +2341,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
Some(matches.args.keys().map(|k| *k).collect())));
} else if let Some(p) = self.positionals_idx.get(&pos_counter) {
// Make sure this one doesn't conflict with anything
self.blacklist.dedup();
if self.blacklist.contains(&p.name) {
// we shouldn't need to remove this arg...since it should be matched yet
// anyways
// matches.args.remove(p.name);
return Err(self.report_error(format!("The argument '{}' cannot be used \
with {}",
Format::Warning(p.to_string()),
@ -2369,7 +2365,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
// Have we made the update yet?
let mut done = false;
if p.multiple {
if p.settings.is_set(&ArgSettings::Multiple) {
if let Some(num) = p.num_vals {
if let Some(ref ma) = matches.args.get(p.name) {
if let Some(ref vals) = ma.values {
@ -2384,7 +2380,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
}
}
if !p.empty_vals && matches.args.contains_key(p.name) &&
if !p.settings.is_set(&ArgSettings::EmptyValues) && matches.args.contains_key(p.name) &&
arg_slice.is_empty() {
return Err(self.report_error(format!("The argument '{}' does not \
allow empty values, but one was found.",
@ -2407,7 +2403,6 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
// Was an update made, or is this the first occurrence?
if !done {
self.overrides.dedup();
if self.overrides.contains(&p.name) {
if let Some(name) = self.overriden_from(p.name, matches) {
matches.args.remove(&*name);
@ -2422,7 +2417,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
}
let mut bm = BTreeMap::new();
if !p.empty_vals && arg_slice.is_empty() {
if !p.settings.is_set(&ArgSettings::EmptyValues) && arg_slice.is_empty() {
return Err(self.report_error(format!("The argument '{}' does not \
allow empty values, but one was found.",
Format::Warning(p.to_string())),
@ -2483,7 +2478,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
if let Some(ref a) = needs_val_of {
if let Some(o) = self.opts.get(a) {
if o.multiple && self.required.is_empty() {
if o.settings.is_set(&ArgSettings::Multiple) && self.required.is_empty() {
let should_err = match matches.values_of(o.name) {
Some(ref v) => v.is_empty(),
None => true,
@ -2495,7 +2490,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
ClapErrorType::EmptyValue,
Some(matches.args.keys().map(|k| *k).collect())));
}
} else if !o.multiple {
} else if !o.settings.is_set(&ArgSettings::Multiple) {
return Err(self.report_error(
format!("The argument '{}' requires a value but none was supplied",
Format::Warning(o.to_string())),
@ -2517,10 +2512,10 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
.map(|k| *k)
.filter(|k| {
if let Some(o) = self.opts.get(k) {
!o.required
!o.settings.is_set(&ArgSettings::Required)
} else if let Some(p) = self.positionals_name.get(k) {
if let Some(p) = self.positionals_idx.get(p) {
!p.required
!p.settings.is_set(&ArgSettings::Required)
} else {
true
}
@ -2632,10 +2627,10 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
.map(|k| *k)
.filter(|k| {
if let Some(o) = self.opts.get(k) {
!o.required
!o.settings.is_set(&ArgSettings::Required)
} else if let Some(p) = self.positionals_name.get(k) {
if let Some(p) = self.positionals_idx.get(p) {
!p.required
!p.settings.is_set(&ArgSettings::Required)
} else {
true
}
@ -2740,11 +2735,9 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
long: Some("help"),
help: Some("Prints help information"),
blacklist: None,
multiple: false,
global: false,
requires: None,
overrides: None,
hidden: false,
settings: ArgFlags::new()
};
self.long_list.push("help");
self.flags.insert("hclap_help", arg);
@ -2763,11 +2756,9 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
long: Some("version"),
help: Some("Prints version information"),
blacklist: None,
multiple: false,
global: false,
requires: None,
overrides: None,
hidden: false,
settings: ArgFlags::new()
};
self.long_list.push("version");
self.flags.insert("vclap_version", arg);
@ -2838,7 +2829,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
.filter(|&v| v.long.is_some())
.filter(|&v| v.long.unwrap() == arg).nth(0) {
// prevents "--config= value" typo
if arg_vec[1].len() == 0 && !v.empty_vals {
if arg_vec[1].len() == 0 && !v.settings.is_set(&ArgSettings::EmptyValues) {
if let Some(ref vec) = self.groups_for(v.name) {
for grp in vec {
matches.args.insert(grp, MatchedArg{
@ -2872,8 +2863,6 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
ClapErrorType::ArgumentConflict,
Some(matches.args.keys().map(|k| *k).collect())));
}
self.overrides.dedup();
debugln!("checking if {} is in overrides", v.name);
if self.overrides.contains(&v.name) {
debugln!("it is...");
debugln!("checking who defined it...");
@ -2902,7 +2891,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
if matches.args.contains_key(v.name) {
if !v.multiple {
if !v.settings.is_set(&ArgSettings::Multiple) {
return Err(self.report_error(format!("The argument '{}' was supplied more \
than once, but does not support multiple values",
Format::Warning(format!("--{}", arg))),
@ -3006,7 +2995,6 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
.filter(|&v| v.long.is_some())
.filter(|&v| v.long.unwrap() == arg).nth(0) {
// Ensure this flag isn't on the mutually excludes list
self.blacklist.dedup();
if self.blacklist.contains(&v.name) {
matches.args.remove(v.name);
return Err(self.report_error(format!("The argument '{}' cannot be used with {}",
@ -3018,8 +3006,6 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
ClapErrorType::ArgumentConflict,
Some(matches.args.keys().map(|k| *k).collect())));
}
self.overrides.dedup();
debugln!("checking if {} is in overrides", v.name);
if self.overrides.contains(&v.name) {
debugln!("it is...");
debugln!("checking who defined it...");
@ -3038,7 +3024,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
// Make sure this isn't one being added multiple times if it doesn't suppor it
if matches.args.contains_key(v.name) && !v.multiple {
if matches.args.contains_key(v.name) && !v.settings.is_set(&ArgSettings::Multiple) {
return Err(self.report_error(format!("The argument '{}' was supplied more than \
once, but does not support multiple values",
Format::Warning(v.to_string())),
@ -3050,7 +3036,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
done = false;
if let Some(ref mut f) = matches.args.get_mut(v.name) {
done = true;
f.occurrences = if v.multiple {
f.occurrences = if v.settings.is_set(&ArgSettings::Multiple) {
f.occurrences + 1
} else {
1
@ -3169,7 +3155,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
return Err(self.possible_values_error(av, &v.to_string(), p_vals, matches));
}
}
if !v.empty_vals && av.is_empty() && matches.args.contains_key(v.name) {
if !v.settings.is_set(&ArgSettings::EmptyValues) && av.is_empty() && matches.args.contains_key(v.name) {
return Err(self.report_error(format!("The argument '{}' does not allow empty \
values, but one was found.", Format::Warning(v.to_string())),
ClapErrorType::EmptyValue,
@ -3244,7 +3230,6 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
.filter(|&v| v.short.is_some())
.filter(|&v| v.short.unwrap() == arg_c).nth(0) {
// Ensure this option isn't on the master mutually excludes list
self.blacklist.dedup();
if self.blacklist.contains(&v.name) {
matches.args.remove(v.name);
return Err(self.report_error(format!("The argument '{}' cannot be used with {}",
@ -3256,7 +3241,6 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
ClapErrorType::ArgumentConflict,
Some(matches.args.keys().map(|k| *k).collect())));
}
self.overrides.dedup();
if self.overrides.contains(&v.name) {
if let Some(name) = self.overriden_from(v.name, matches) {
matches.args.remove(&*name);
@ -3272,7 +3256,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
if matches.args.contains_key(v.name) {
if !v.multiple {
if !v.settings.is_set(&ArgSettings::Multiple) {
return Err(self.report_error(format!("The argument '{}' was supplied more \
than once, but does not support multiple values",
Format::Warning(format!("-{}", arg))),
@ -3334,7 +3318,6 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
.filter(|&v| v.short.is_some())
.filter(|&v| v.short.unwrap() == arg).nth(0) {
// Ensure this flag isn't on the mutually excludes list
self.blacklist.dedup();
if self.blacklist.contains(&v.name) {
matches.args.remove(v.name);
return Err(self.report_error(format!("The argument '{}' cannot be used {}",
@ -3347,8 +3330,6 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
ClapErrorType::ArgumentConflict,
Some(matches.args.keys().map(|k| *k).collect())));
}
self.overrides.dedup();
debugln!("checking if {} is in overrides", v.name);
if self.overrides.contains(&v.name) {
debugln!("it is...");
debugln!("checking who defined it...");
@ -3367,7 +3348,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
// Make sure this isn't one being added multiple times if it doesn't suppor it
if matches.args.contains_key(v.name) && !v.multiple {
if matches.args.contains_key(v.name) && !v.settings.is_set(&ArgSettings::Multiple) {
return Err(self.report_error(format!("The argument '{}' was supplied more than \
once, but does not support multiple values",
Format::Warning(format!("-{}", arg))),
@ -3378,7 +3359,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
if let Some(ref vec) = self.groups_for(v.name) {
for grp in vec {
if let Some(ref mut f) = matches.args.get_mut(grp) {
f.occurrences = if v.multiple {
f.occurrences = if v.settings.is_set(&ArgSettings::Multiple) {
f.occurrences + 1
} else {
1
@ -3389,7 +3370,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
let mut done = false;
if let Some(ref mut f) = matches.args.get_mut(v.name) {
done = true;
f.occurrences = if v.multiple {
f.occurrences = if v.settings.is_set(&ArgSettings::Multiple) {
f.occurrences + 1
} else {
1
@ -3495,7 +3476,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
} else if let Some(ref vals) = ma.values {
if let Some(f) = self.opts.get(name) {
if let Some(num) = f.num_vals {
let should_err = if f.multiple {
let should_err = if f.settings.is_set(&ArgSettings::Multiple) {
((vals.len() as u8) % num) != 0
} else {
num != (vals.len() as u8)
@ -3505,13 +3486,13 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
values, but {} w{} provided",
Format::Warning(f.to_string()),
Format::Good(num.to_string()),
Format::Error(if f.multiple {
Format::Error(if f.settings.is_set(&ArgSettings::Multiple) {
(vals.len() % num as usize).to_string()
} else {
vals.len().to_string()
}),
if vals.len() == 1 ||
( f.multiple &&
( f.settings.is_set(&ArgSettings::Multiple) &&
( vals.len() % num as usize) == 1) {"as"}else{"ere"}),
ClapErrorType::EmptyValue,
Some(matches.args.keys().map(|k| *k).collect())));

View file

@ -85,7 +85,7 @@ pub struct Arg<'n, 'l, 'h, 'g, 'p, 'r> {
pub min_vals: Option<u8>,
/// Specifies whether or not this argument accepts explicit empty values such as `--option ""`
pub empty_vals: bool,
/// Specifies whether or not this argument is global and should be propogated through all
/// Specifies whether or not this argument is global and should be propagated through all
/// child subcommands
pub global: bool,
/// A function used to check the validity of an argument value. Failing this validation results

View file

@ -3,6 +3,7 @@ use std::fmt::{Display, Formatter, Result};
use std::convert::From;
use Arg;
use args::settings::{ArgFlags, ArgSettings};
pub struct FlagBuilder<'n> {
pub name: &'n str,
@ -13,10 +14,6 @@ pub struct FlagBuilder<'n> {
/// the user when the application's `help`
/// text is displayed
pub help: Option<&'n str>,
/// Determines if multiple instances of the same
/// flag are allowed
/// I.e. `-v -v -v` or `-vvv`
pub multiple: bool,
/// A list of names for other arguments that
/// *may not* be used with this flag
pub blacklist: Option<Vec<&'n str>>,
@ -27,10 +24,24 @@ pub struct FlagBuilder<'n> {
/// The short version (i.e. single character)
/// of the argument, no preceding `-`
pub short: Option<char>,
pub global: bool,
/// A list of names for other arguments that *mutually override* this flag
pub overrides: Option<Vec<&'n str>>,
pub hidden: bool
pub settings: ArgFlags,
}
impl<'n> FlagBuilder<'n> {
pub fn new(name: &'n str) -> Self {
FlagBuilder {
name: name,
short: None,
long: None,
help: None,
blacklist: None,
requires: None,
overrides: None,
settings: ArgFlags::new()
}
}
}
impl<'n, 'a> From<&'a Arg<'n, 'n, 'n, 'n, 'n, 'n>> for FlagBuilder<'n> {
@ -60,12 +71,19 @@ impl<'n, 'a> From<&'a Arg<'n, 'n, 'n, 'n, 'n, 'n>> for FlagBuilder<'n> {
long: a.long,
help: a.help,
blacklist: None,
global: a.global,
multiple: a.multiple,
requires: None,
overrides: None,
hidden: a.hidden
settings: ArgFlags::new()
};
if a.multiple {
fb.settings.set(&ArgSettings::Multiple);
}
if a.global {
fb.settings.set(&ArgSettings::Global);
}
if a.hidden {
fb.settings.set(&ArgSettings::Hidden);
}
// Check if there is anything in the blacklist (mutually excludes list) and add any
// values
if let Some(ref bl) = a.blacklist {
@ -74,7 +92,6 @@ impl<'n, 'a> From<&'a Arg<'n, 'n, 'n, 'n, 'n, 'n>> for FlagBuilder<'n> {
for n in bl {
bhs.push(*n);
}
bhs.dedup();
fb.blacklist = Some(bhs);
}
// Check if there is anything in the requires list and add any values
@ -84,7 +101,6 @@ impl<'n, 'a> From<&'a Arg<'n, 'n, 'n, 'n, 'n, 'n>> for FlagBuilder<'n> {
for n in r {
rhs.push(*n);
}
rhs.dedup();
fb.requires = Some(rhs);
}
if let Some(ref or) = a.overrides {
@ -93,7 +109,6 @@ impl<'n, 'a> From<&'a Arg<'n, 'n, 'n, 'n, 'n, 'n>> for FlagBuilder<'n> {
for n in or {
bhs.push(*n);
}
bhs.dedup();
fb.overrides = Some(bhs);
}
@ -115,36 +130,18 @@ impl<'n> Display for FlagBuilder<'n> {
#[cfg(test)]
mod test {
use super::FlagBuilder;
use args::settings::ArgSettings;
#[test]
fn flagbuilder_display() {
let f = FlagBuilder {
name: "flg",
short: None,
long: Some("flag"),
help: None,
multiple: true,
blacklist: None,
requires: None,
global: false,
overrides: None,
hidden: false,
};
let mut f = FlagBuilder::new("flg");
f.settings.set(&ArgSettings::Multiple);
f.long = Some("flag");
assert_eq!(&*format!("{}", f), "--flag");
let f2 = FlagBuilder {
name: "flg",
short: Some('f'),
long: None,
help: None,
multiple: false,
blacklist: None,
requires: None,
global: false,
overrides: None,
hidden: false,
};
let mut f2 = FlagBuilder::new("flg");
f2.short = Some('f');
assert_eq!(&*format!("{}", f2), "-f");
}

View file

@ -2,6 +2,9 @@ pub use self::flag::FlagBuilder;
pub use self::option::OptBuilder;
pub use self::positional::PosBuilder;
#[allow(dead_code)]
mod flag;
#[allow(dead_code)]
mod positional;
#[allow(dead_code)]
mod option;

View file

@ -4,6 +4,7 @@ use std::fmt::{Display, Formatter, Result};
use std::result::Result as StdResult;
use Arg;
use args::settings::{ArgFlags, ArgSettings};
pub struct OptBuilder<'n> {
pub name: &'n str,
@ -14,15 +15,8 @@ pub struct OptBuilder<'n> {
/// The string of text that will displayed to the user when the application's
/// `help` text is displayed
pub help: Option<&'n str>,
/// Allow multiple occurrences of an option argument such as "-c some -c other"
pub multiple: bool,
/// A list of names for other arguments that *may not* be used with this flag
pub blacklist: Option<Vec<&'n str>>,
/// If this is a required by default when using the command line program
/// i.e. a configuration file that's required for the program to function
/// **NOTE:** required by default means, it is required *until* mutually
/// exclusive arguments are evaluated.
pub required: bool,
/// A list of possible values for this argument
pub possible_vals: Option<Vec<&'n str>>,
/// A list of names of other arguments that are *required* to be used when
@ -32,15 +26,32 @@ pub struct OptBuilder<'n> {
pub min_vals: Option<u8>,
pub max_vals: Option<u8>,
pub val_names: Option<BTreeSet<&'n str>>,
pub empty_vals: bool,
pub global: bool,
pub validator: Option<Rc<Fn(String) -> StdResult<(), String>>>,
/// A list of names for other arguments that *mutually override* this flag
pub overrides: Option<Vec<&'n str>>,
pub hidden: bool
pub settings: ArgFlags,
}
impl<'n> OptBuilder<'n> {
pub fn new(name: &'n str) -> Self {
OptBuilder {
name: name,
short: None,
long: None,
help: None,
blacklist: None,
possible_vals: None,
requires: None,
num_vals: None,
min_vals: None,
max_vals: None,
val_names: None,
validator: None,
overrides: None,
settings: ArgFlags::new()
}
}
pub fn from_arg(a: &Arg<'n, 'n, 'n, 'n, 'n,'n>,
reqs: &mut Vec<&'n str>) -> Self {
if a.short.is_none() && a.long.is_none() {
@ -52,30 +63,41 @@ impl<'n> OptBuilder<'n> {
name: a.name,
short: a.short,
long: a.long,
multiple: a.multiple,
blacklist: None,
help: a.help,
global: a.global,
possible_vals: None,
num_vals: a.num_vals,
min_vals: a.min_vals,
max_vals: a.max_vals,
val_names: a.val_names.clone(),
requires: None,
required: a.required,
empty_vals: a.empty_vals,
validator: None,
overrides: None,
hidden: a.hidden
settings: ArgFlags::new()
};
if a.multiple {
ob.settings.set(&ArgSettings::Multiple);
}
if a.required {
ob.settings.set(&ArgSettings::Required);
}
if a.global {
ob.settings.set(&ArgSettings::Global);
}
if !a.empty_vals {
ob.settings.unset(&ArgSettings::Global);
}
if a.hidden {
ob.settings.set(&ArgSettings::Hidden);
}
if let Some(ref vec) = ob.val_names {
ob.num_vals = Some(vec.len() as u8);
}
if ob.min_vals.is_some() && !ob.multiple {
if ob.min_vals.is_some() && !a.multiple {
panic!("Argument \"{}\" does not allow multiple values, yet it is expecting {} \
values", ob.name, ob.num_vals.unwrap());
}
if ob.max_vals.is_some() && !ob.multiple {
if ob.max_vals.is_some() && !a.multiple {
panic!("Argument \"{}\" does not allow multiple values, yet it is expecting {} \
values", ob.name, ob.num_vals.unwrap());
}
@ -87,7 +109,6 @@ impl<'n> OptBuilder<'n> {
for n in bl {
bhs.push(*n);
}
bhs.dedup();
ob.blacklist = Some(bhs);
}
if let Some(ref p) = a.validator {
@ -99,11 +120,10 @@ impl<'n> OptBuilder<'n> {
// without derefing n = &&str
for n in r {
rhs.push(*n);
if ob.required {
if a.required {
reqs.push(*n);
}
}
rhs.dedup();
ob.requires = Some(rhs);
}
if let Some(ref or) = a.overrides {
@ -112,7 +132,6 @@ impl<'n> OptBuilder<'n> {
for n in or {
bhs.push(*n);
}
bhs.dedup();
ob.overrides = Some(bhs);
}
// Check if there is anything in the possible values and add those as well
@ -150,7 +169,7 @@ impl<'n> Display for OptBuilder<'n> {
for _ in (0..num) {
try!(write!(f, " <{}>", self.name));
}
if self.multiple && num == 1 {
if self.settings.is_set(&ArgSettings::Multiple) && num == 1 {
try!(write!(f, "..."));
}
}
@ -163,29 +182,13 @@ impl<'n> Display for OptBuilder<'n> {
mod test {
use super::OptBuilder;
use std::collections::BTreeSet;
use args::settings::ArgSettings;
#[test]
fn optbuilder_display() {
let o = OptBuilder {
name: "opt",
short: None,
long: Some("option"),
help: None,
multiple: true,
blacklist: None,
required: false,
possible_vals: None,
requires: None,
num_vals: None,
min_vals: None,
max_vals: None,
val_names: None,
empty_vals: true,
global: false,
validator: None,
overrides: None,
hidden: false,
};
let mut o = OptBuilder::new("opt");
o.long = Some("option");
o.settings.set(&ArgSettings::Multiple);
assert_eq!(&*format!("{}", o), "--option <opt>...");
@ -193,26 +196,9 @@ mod test {
v_names.insert("file");
v_names.insert("name");
let o2 = OptBuilder {
name: "opt",
short: Some('o'),
long: None,
help: None,
multiple: false,
blacklist: None,
required: false,
possible_vals: None,
requires: None,
num_vals: None,
min_vals: None,
max_vals: None,
val_names: Some(v_names),
empty_vals: true,
global: false,
validator: None,
overrides: None,
hidden: false,
};
let mut o2 = OptBuilder::new("opt");
o2.short = Some('o');
o2.val_names = Some(v_names);
assert_eq!(&*format!("{}", o2), "-o <file> <name>");
}

View file

@ -3,19 +3,13 @@ use std::result::Result as StdResult;
use std::rc::Rc;
use Arg;
use args::settings::{ArgFlags, ArgSettings};
pub struct PosBuilder<'n> {
pub name: &'n str,
/// The string of text that will displayed to the user when the application's
/// `help` text is displayed
pub help: Option<&'n str>,
/// If this is a required by default when using the command line program
/// i.e. a configuration file that's required for the program to function
/// **NOTE:** required by default means, it is required *until* mutually
/// exclusive arguments are evaluated.
pub required: bool,
/// Allow multiple occurrences of an option argument such as "-c some -c other"
pub multiple: bool,
/// A list of names of other arguments that are *required* to be used when
/// this flag is used
pub requires: Option<Vec<&'n str>>,
@ -28,15 +22,30 @@ pub struct PosBuilder<'n> {
pub num_vals: Option<u8>,
pub max_vals: Option<u8>,
pub min_vals: Option<u8>,
pub empty_vals: bool,
pub global: bool,
pub validator: Option<Rc<Fn(String) -> StdResult<(), String>>>,
/// A list of names for other arguments that *mutually override* this flag
pub overrides: Option<Vec<&'n str>>,
pub hidden: bool
pub settings: ArgFlags,
}
impl<'n> PosBuilder<'n> {
pub fn new(name: &'n str, idx: u8) -> Self {
PosBuilder {
name: name,
index: idx,
help: None,
blacklist: None,
possible_vals: None,
requires: None,
num_vals: None,
min_vals: None,
max_vals: None,
validator: None,
overrides: None,
settings: ArgFlags::new()
}
}
pub fn from_arg(a: &Arg<'n, 'n, 'n, 'n, 'n, 'n>,
idx: u8,
reqs: &mut Vec<&'n str>) -> Self {
@ -61,8 +70,6 @@ impl<'n> PosBuilder<'n> {
let mut pb = PosBuilder {
name: a.name,
index: idx,
required: a.required,
multiple: a.multiple,
blacklist: None,
requires: None,
possible_vals: None,
@ -70,17 +77,27 @@ impl<'n> PosBuilder<'n> {
min_vals: a.min_vals,
max_vals: a.max_vals,
help: a.help,
global: a.global,
empty_vals: a.empty_vals,
validator: None,
overrides: None,
hidden: a.hidden
settings: ArgFlags::new()
};
if pb.min_vals.is_some() && !pb.multiple {
if a.multiple {
pb.settings.set(&ArgSettings::Multiple);
}
if a.required {
pb.settings.set(&ArgSettings::Required);
}
if a.global {
pb.settings.set(&ArgSettings::Global);
}
if a.hidden {
pb.settings.set(&ArgSettings::Hidden);
}
if pb.min_vals.is_some() && !a.multiple {
panic!("Argument \"{}\" does not allow multiple values, yet it is expecting {} \
values", pb.name, pb.num_vals.unwrap());
}
if pb.max_vals.is_some() && !pb.multiple {
if pb.max_vals.is_some() && !a.multiple {
panic!("Argument \"{}\" does not allow multiple values, yet it is expecting {} \
values", pb.name, pb.num_vals.unwrap());
}
@ -92,7 +109,6 @@ impl<'n> PosBuilder<'n> {
for n in bl {
bhs.push(*n);
}
bhs.dedup();
pb.blacklist = Some(bhs);
}
if let Some(ref or) = a.overrides {
@ -101,7 +117,6 @@ impl<'n> PosBuilder<'n> {
for n in or {
bhs.push(*n);
}
bhs.dedup();
pb.overrides = Some(bhs);
}
// Check if there is anything in the possible values and add those as well
@ -122,11 +137,10 @@ impl<'n> PosBuilder<'n> {
// without derefing n = &&str
for n in r {
rhs.push(*n);
if pb.required {
if a.required {
reqs.push(*n);
}
}
rhs.dedup();
pb.requires = Some(rhs);
}
@ -138,12 +152,12 @@ impl<'n> Display for PosBuilder<'n> {
fn fmt(&self,
f: &mut Formatter)
-> Result {
if self.required {
if self.settings.is_set(&ArgSettings::Required) {
try!(write!(f, "<{}>", self.name));
} else {
try!(write!(f, "[{}]", self.name));
}
if self.multiple {
if self.settings.is_set(&ArgSettings::Multiple) {
try!(write!(f, "..."));
}
@ -153,48 +167,17 @@ impl<'n> Display for PosBuilder<'n> {
#[cfg(test)]
mod test {
use super::PosBuilder;
use args::settings::ArgSettings;
#[test]
fn posbuilder_display() {
let p = PosBuilder {
name: "pos",
help: None,
multiple: true,
blacklist: None,
required: false,
possible_vals: None,
requires: None,
num_vals: None,
min_vals: None,
max_vals: None,
index: 1,
empty_vals: true,
global: false,
validator: None,
overrides: None,
hidden: false,
};
let mut p = PosBuilder::new("pos", 1);
p.settings.set(&ArgSettings::Multiple);
assert_eq!(&*format!("{}", p), "[pos]...");
let p2 = PosBuilder {
name: "pos",
help: None,
multiple: false,
blacklist: None,
required: true,
possible_vals: None,
requires: None,
num_vals: None,
min_vals: None,
max_vals: None,
index: 1,
empty_vals: true,
global: false,
validator: None,
overrides: None,
hidden: false,
};
let mut p2 = PosBuilder::new("pos", 1);
p2.settings.set(&ArgSettings::Required);
assert_eq!(&*format!("{}", p2), "<pos>");
}

View file

@ -11,3 +11,5 @@ mod subcommand;
mod argbuilder;
mod matchedarg;
mod group;
#[allow(dead_code)]
pub mod settings;

74
src/args/settings.rs Normal file
View file

@ -0,0 +1,74 @@
use std::str::FromStr;
use std::ascii::AsciiExt;
bitflags! {
flags Flags: u8 {
const REQUIRED = 0b000001,
const MULTIPLE = 0b000100,
const EMPTY_VALS = 0b001000,
const GLOBAL = 0b010000,
const HIDDEN = 0b100000,
}
}
pub struct ArgFlags(Flags);
impl ArgFlags {
pub fn new() -> Self {
ArgFlags(EMPTY_VALS)
}
pub fn set(&mut self, s: &ArgSettings) {
match *s {
ArgSettings::Required => self.0.insert(REQUIRED),
ArgSettings::Multiple => self.0.insert(MULTIPLE),
ArgSettings::EmptyValues => self.0.insert(EMPTY_VALS),
ArgSettings::Global => self.0.insert(GLOBAL),
ArgSettings::Hidden => self.0.insert(HIDDEN),
}
}
pub fn unset(&mut self, s: &ArgSettings) {
match *s {
ArgSettings::Required => self.0.remove(REQUIRED),
ArgSettings::Multiple => self.0.remove(MULTIPLE),
ArgSettings::EmptyValues => self.0.remove(EMPTY_VALS),
ArgSettings::Global => self.0.remove(GLOBAL),
ArgSettings::Hidden => self.0.remove(HIDDEN),
}
}
pub fn is_set(&self, s: &ArgSettings) -> bool {
match *s {
ArgSettings::Required => self.0.contains(REQUIRED),
ArgSettings::Multiple => self.0.contains(MULTIPLE),
ArgSettings::EmptyValues => self.0.contains(EMPTY_VALS),
ArgSettings::Global => self.0.contains(GLOBAL),
ArgSettings::Hidden => self.0.contains(HIDDEN),
}
}
}
#[doc(hidden)]
#[derive(Debug, PartialEq)]
pub enum ArgSettings {
Required,
Multiple,
EmptyValues,
Global,
Hidden,
}
impl FromStr for ArgSettings {
type Err = String;
fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
match &*s.to_ascii_lowercase() {
"required" => Ok(ArgSettings::Required),
"multiple" => Ok(ArgSettings::Multiple),
"global" => Ok(ArgSettings::Global),
"emptyvalues" => Ok(ArgSettings::EmptyValues),
"hidden" => Ok(ArgSettings::Hidden),
_ => Err("unknown ArgSetting, cannot convert from str".to_owned())
}
}
}

View file

@ -56,6 +56,7 @@ macro_rules! vec_remove {
}
}
if let Some(i) = ix {
$vec.dedup();
$vec.remove(i);
}
}