mirror of
https://github.com/clap-rs/clap
synced 2024-11-13 08:07:11 +00:00
fix(RequiredArgs): fixes bug where required-by-default arguments are not listed in usage
Closes #96
This commit is contained in:
parent
82b0c5c3d7
commit
12aea9612d
2 changed files with 167 additions and 139 deletions
302
src/app.rs
302
src/app.rs
|
@ -5,9 +5,7 @@ use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::vec::IntoIter;
|
use std::vec::IntoIter;
|
||||||
use std::borrow::ToOwned;
|
|
||||||
use std::process;
|
use std::process;
|
||||||
use std::fmt::Write;
|
|
||||||
|
|
||||||
use args::{ ArgMatches, Arg, SubCommand, MatchedArg};
|
use args::{ ArgMatches, Arg, SubCommand, MatchedArg};
|
||||||
use args::{ FlagBuilder, OptBuilder, PosBuilder};
|
use args::{ FlagBuilder, OptBuilder, PosBuilder};
|
||||||
|
@ -336,7 +334,11 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
|
||||||
let mut rhs = HashSet::new();
|
let mut rhs = HashSet::new();
|
||||||
// without derefing n = &&str
|
// without derefing n = &&str
|
||||||
for n in r {
|
for n in r {
|
||||||
rhs.insert(*n); }
|
rhs.insert(*n);
|
||||||
|
if pb.required {
|
||||||
|
self.required.insert(*n);
|
||||||
|
}
|
||||||
|
}
|
||||||
pb.requires = Some(rhs);
|
pb.requires = Some(rhs);
|
||||||
}
|
}
|
||||||
// Check if there is anything in the possible values and add those as well
|
// Check if there is anything in the possible values and add those as well
|
||||||
|
@ -387,7 +389,12 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
|
||||||
if let Some(ref r) = a.requires {
|
if let Some(ref r) = a.requires {
|
||||||
let mut rhs = HashSet::new();
|
let mut rhs = HashSet::new();
|
||||||
// without derefing n = &&str
|
// without derefing n = &&str
|
||||||
for n in r { rhs.insert(*n); }
|
for n in r {
|
||||||
|
rhs.insert(*n);
|
||||||
|
if ob.required {
|
||||||
|
self.required.insert(*n);
|
||||||
|
}
|
||||||
|
}
|
||||||
ob.requires = Some(rhs);
|
ob.requires = Some(rhs);
|
||||||
}
|
}
|
||||||
// Check if there is anything in the possible values and add those as well
|
// Check if there is anything in the possible values and add those as well
|
||||||
|
@ -657,10 +664,10 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn group_string(&self, g: &ArgGroup, r: &str, vec: &Vec<&str>) -> Option<Vec<String>> {
|
fn group_string(&self, g: &ArgGroup, r: &str, vec: &HashSet<&'ar str>) -> Option<Vec<String>> {
|
||||||
let mut g_vec = vec![];
|
let mut g_vec = vec![];
|
||||||
for a in g.args.iter() {
|
for a in g.args.iter() {
|
||||||
if vec.contains(&a) { return None }
|
if vec.contains(a) { return None }
|
||||||
if let Some(f) = self.flags.get(r) {
|
if let Some(f) = self.flags.get(r) {
|
||||||
g_vec.push(format!("{}", f));
|
g_vec.push(format!("{}", f));
|
||||||
} else if let Some(o) = self.opts.get(r) {
|
} else if let Some(o) = self.opts.get(r) {
|
||||||
|
@ -677,141 +684,149 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
|
||||||
Some(g_vec)
|
Some(g_vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_required_from(&self, reqs: HashSet<&'ar str>) -> Vec<String> {
|
||||||
|
let mut c_flags = vec![];
|
||||||
|
let mut c_pos = vec![];
|
||||||
|
let mut c_opt = vec![];
|
||||||
|
let mut grps = vec![];
|
||||||
|
reqs.iter().map(|name| if let Some(f) = self.flags.get(name) {
|
||||||
|
c_flags.push(f);
|
||||||
|
} else if let Some(o) = self.opts.get(name) {
|
||||||
|
c_opt.push(o);
|
||||||
|
} else {
|
||||||
|
c_pos.push(
|
||||||
|
self.positionals_idx.get(self.positionals_name.get(name)
|
||||||
|
.unwrap())
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
}).collect::<Vec<_>>();
|
||||||
|
let mut tmp_f = vec![];
|
||||||
|
for f in c_flags.iter_mut() {
|
||||||
|
if let Some(ref rl) = f.requires {
|
||||||
|
for r in rl {
|
||||||
|
if !reqs.contains(r) {
|
||||||
|
if let Some(f) = self.flags.get(r) {
|
||||||
|
tmp_f.push(f);
|
||||||
|
} else if let Some(o) = self.opts.get(r) {
|
||||||
|
c_opt.push(o);
|
||||||
|
} else if let Some(g) = self.groups.get(r) {
|
||||||
|
if let Some(vec) = self.group_string(g, r, &reqs) {
|
||||||
|
let g_string = vec.iter()
|
||||||
|
.map(|s| format!("{}|", s))
|
||||||
|
.fold(String::new(), |acc, i| {
|
||||||
|
acc + &format!("{}",i)[..]
|
||||||
|
});
|
||||||
|
grps.push(format!("[{}]", &g_string[..g_string.len()-1]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c_pos.push(
|
||||||
|
self.positionals_idx.get(self.positionals_name.get(r)
|
||||||
|
.unwrap())
|
||||||
|
.unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for f in tmp_f {
|
||||||
|
c_flags.push(f);
|
||||||
|
}
|
||||||
|
let mut tmp_o = vec![];
|
||||||
|
for o in c_opt.iter_mut() {
|
||||||
|
if let Some(ref rl) = o.requires {
|
||||||
|
for r in rl {
|
||||||
|
if !reqs.contains(r) {
|
||||||
|
if let Some(f) = self.flags.get(r) {
|
||||||
|
c_flags.push(f);
|
||||||
|
} else if let Some(o) = self.opts.get(r) {
|
||||||
|
tmp_o.push(o);
|
||||||
|
} else if let Some(g) = self.groups.get(r) {
|
||||||
|
if let Some(vec) = self.group_string(g, r, &reqs) {
|
||||||
|
let g_string = vec.iter()
|
||||||
|
.map(|s| format!("{}|", s))
|
||||||
|
.fold(String::new(), |acc, i| {
|
||||||
|
acc + &format!("{}",i)[..]
|
||||||
|
});
|
||||||
|
grps.push(format!("[{}]", &g_string[..g_string.len()-1]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c_pos.push(self.positionals_idx.get(self.positionals_name.get(r)
|
||||||
|
.unwrap())
|
||||||
|
.unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for o in tmp_o {
|
||||||
|
c_opt.push(o);
|
||||||
|
}
|
||||||
|
let mut tmp_p = vec![];
|
||||||
|
for p in c_pos.iter_mut() {
|
||||||
|
if let Some(ref rl) = p.requires {
|
||||||
|
for r in rl {
|
||||||
|
if !reqs.contains(r) {
|
||||||
|
if let Some(f) = self.flags.get(r) {
|
||||||
|
c_flags.push(f);
|
||||||
|
} else if let Some(o) = self.opts.get(r) {
|
||||||
|
c_opt.push(o);
|
||||||
|
} else if let Some(g) = self.groups.get(r) {
|
||||||
|
if let Some(vec) = self.group_string(g, r, &reqs) {
|
||||||
|
let g_string = vec.iter()
|
||||||
|
.map(|s| format!("{}|", s))
|
||||||
|
.fold(String::new(), |acc, i| {
|
||||||
|
acc + &format!("{}",i)[..]
|
||||||
|
});
|
||||||
|
grps.push(format!("[{}]", &g_string[..g_string.len()-1]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tmp_p.push(self.positionals_idx.get(self.positionals_name.get(r)
|
||||||
|
.unwrap())
|
||||||
|
.unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for p in tmp_p {
|
||||||
|
c_pos.push(p);
|
||||||
|
}
|
||||||
|
let mut ret_val = vec![];
|
||||||
|
|
||||||
|
c_pos.iter()
|
||||||
|
.map(|f| ret_val.push(format!("{}", f))).collect::<Vec<_>>();
|
||||||
|
c_flags.iter()
|
||||||
|
.map(|f| ret_val.push(format!("{}", f))).collect::<Vec<_>>();
|
||||||
|
c_opt.iter()
|
||||||
|
.map(|f| ret_val.push(format!("{}", f))).collect::<Vec<_>>();
|
||||||
|
grps.iter()
|
||||||
|
.map(|f| ret_val.push(format!("{}", f))).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
ret_val
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Creates a usage string if one was not provided by the user manually. This happens just
|
// Creates a usage string if one was not provided by the user manually. This happens just
|
||||||
// after all arguments were parsed, but before any subcommands have been parsed (so as to
|
// after all arguments were parsed, but before any subcommands have been parsed (so as to
|
||||||
// give subcommands their own usage recursively)
|
// give subcommands their own usage recursively)
|
||||||
fn create_usage(&self, matches: Option<Vec<&str>>) -> String {
|
fn create_usage(&self, matches: Option<Vec<&'ar str>>) -> String {
|
||||||
let tab = " ";
|
let tab = " ";
|
||||||
let mut usage = String::with_capacity(75);
|
let mut usage = String::with_capacity(75);
|
||||||
usage.push_str("USAGE:\n");
|
usage.push_str("USAGE:\n");
|
||||||
usage.push_str(tab);
|
usage.push_str(tab);
|
||||||
if let Some(u) = self.usage_str {
|
if let Some(u) = self.usage_str {
|
||||||
usage.push_str(u);
|
usage.push_str(u);
|
||||||
} else if let Some(vec) = matches {
|
} else if let Some(tmp_vec) = matches {
|
||||||
let mut c_flags = vec![];
|
let mut hs = HashSet::new();
|
||||||
let mut c_pos = vec![];
|
self.required.iter().map(|n| hs.insert(*n)).collect::<Vec<_>>();
|
||||||
let mut c_opt = vec![];
|
tmp_vec.iter().map(|n| hs.insert(*n)).collect::<Vec<_>>();
|
||||||
let mut grps = vec![];
|
let reqs = self.get_required_from(hs);
|
||||||
vec.iter().map(|name| if let Some(f) = self.flags.get(name) {
|
|
||||||
c_flags.push(f);
|
let r_string = reqs.iter().fold(String::new(), |acc, s| acc + &format!(" {}", s)[..]);
|
||||||
} else if let Some(o) = self.opts.get(name) {
|
|
||||||
c_opt.push(o);
|
usage.push_str(&format!("{}{}",
|
||||||
} else {
|
|
||||||
c_pos.push(
|
|
||||||
self.positionals_idx.get(self.positionals_name.get(name)
|
|
||||||
.unwrap())
|
|
||||||
.unwrap()
|
|
||||||
);
|
|
||||||
}).collect::<Vec<_>>();
|
|
||||||
let mut tmp_f = vec![];
|
|
||||||
for f in c_flags.iter_mut() {
|
|
||||||
if let Some(ref rl) = f.requires {
|
|
||||||
for r in rl {
|
|
||||||
if !vec.contains(&&r) {
|
|
||||||
if let Some(f) = self.flags.get(r) {
|
|
||||||
tmp_f.push(f);
|
|
||||||
} else if let Some(o) = self.opts.get(r) {
|
|
||||||
c_opt.push(o);
|
|
||||||
} else if let Some(g) = self.groups.get(r) {
|
|
||||||
if let Some(vec) = self.group_string(g, r, &vec) {
|
|
||||||
let g_string = vec.iter()
|
|
||||||
.map(|s| format!("{}|", s))
|
|
||||||
.fold(String::new(), |acc, i| {
|
|
||||||
acc + &format!("{}",i)[..]
|
|
||||||
});
|
|
||||||
grps.push(format!("[{}]", &g_string[..g_string.len()-1]));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
c_pos.push(
|
|
||||||
self.positionals_idx.get(self.positionals_name.get(r)
|
|
||||||
.unwrap())
|
|
||||||
.unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for f in tmp_f {
|
|
||||||
c_flags.push(f);
|
|
||||||
}
|
|
||||||
let mut tmp_o = vec![];
|
|
||||||
for o in c_opt.iter_mut() {
|
|
||||||
if let Some(ref rl) = o.requires {
|
|
||||||
for r in rl {
|
|
||||||
if !vec.contains(&&r) {
|
|
||||||
if let Some(f) = self.flags.get(r) {
|
|
||||||
c_flags.push(f);
|
|
||||||
} else if let Some(o) = self.opts.get(r) {
|
|
||||||
tmp_o.push(o);
|
|
||||||
} else if let Some(g) = self.groups.get(r) {
|
|
||||||
if let Some(vec) = self.group_string(g, r, &vec) {
|
|
||||||
let g_string = vec.iter()
|
|
||||||
.map(|s| format!("{}|", s))
|
|
||||||
.fold(String::new(), |acc, i| {
|
|
||||||
acc + &format!("{}",i)[..]
|
|
||||||
});
|
|
||||||
grps.push(format!("[{}]", &g_string[..g_string.len()-1]));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
c_pos.push(self.positionals_idx.get(self.positionals_name.get(r)
|
|
||||||
.unwrap())
|
|
||||||
.unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for o in tmp_o {
|
|
||||||
c_opt.push(o);
|
|
||||||
}
|
|
||||||
let mut tmp_p = vec![];
|
|
||||||
for p in c_pos.iter_mut() {
|
|
||||||
if let Some(ref rl) = p.requires {
|
|
||||||
for r in rl {
|
|
||||||
if !vec.contains(&&r) {
|
|
||||||
if let Some(f) = self.flags.get(r) {
|
|
||||||
c_flags.push(f);
|
|
||||||
} else if let Some(o) = self.opts.get(r) {
|
|
||||||
c_opt.push(o);
|
|
||||||
} else if let Some(g) = self.groups.get(r) {
|
|
||||||
if let Some(vec) = self.group_string(g, r, &vec) {
|
|
||||||
let g_string = vec.iter()
|
|
||||||
.map(|s| format!("{}|", s))
|
|
||||||
.fold(String::new(), |acc, i| {
|
|
||||||
acc + &format!("{}",i)[..]
|
|
||||||
});
|
|
||||||
grps.push(format!("[{}]", &g_string[..g_string.len()-1]));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tmp_p.push(self.positionals_idx.get(self.positionals_name.get(r)
|
|
||||||
.unwrap())
|
|
||||||
.unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for p in tmp_p {
|
|
||||||
c_pos.push(p);
|
|
||||||
}
|
|
||||||
let f_string = c_flags.iter()
|
|
||||||
.map(|f| format!("{}", f))
|
|
||||||
.fold(String::new(),|acc, i| acc + &format!(" {}", i));
|
|
||||||
let o_string = c_opt.iter()
|
|
||||||
.map(|f| format!("{}", f))
|
|
||||||
.fold(String::new(),|acc, i| acc + &format!(" {}", i));
|
|
||||||
let p_string = c_pos.iter()
|
|
||||||
.map(|f| format!("{}", f))
|
|
||||||
.fold(String::new(),|acc, i| acc + &format!(" {}", i));
|
|
||||||
let g_string = grps.iter()
|
|
||||||
.map(|f| format!(" {}", f))
|
|
||||||
.fold(String::new(), |acc, i| acc + &format!("{}", i));
|
|
||||||
usage.push_str(&format!("{} {} {} {} {}",
|
|
||||||
self.bin_name.clone().unwrap_or(self.name.clone()),
|
self.bin_name.clone().unwrap_or(self.name.clone()),
|
||||||
p_string,
|
r_string)[..]);
|
||||||
f_string,
|
|
||||||
o_string,
|
|
||||||
g_string)[..]);
|
|
||||||
} else {
|
} else {
|
||||||
let flags = !self.flags.is_empty();
|
let flags = !self.flags.is_empty();
|
||||||
let pos = !self.positionals_idx.is_empty();
|
let pos = !self.positionals_idx.is_empty();
|
||||||
|
@ -1448,10 +1463,15 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
|
||||||
if let Some(o) = self.opts.get(a) {
|
if let Some(o) = self.opts.get(a) {
|
||||||
if o.multiple && self.required.is_empty() { () }
|
if o.multiple && self.required.is_empty() { () }
|
||||||
else {
|
else {
|
||||||
self.report_error("One or more required arguments were not \
|
self.report_error(format!("The following required arguments were not \
|
||||||
supplied".to_owned(),
|
supplied:\n{}",
|
||||||
true,
|
self.get_required_from(self.required.iter()
|
||||||
true,
|
.map(|s| *s)
|
||||||
|
.collect::<HashSet<_>>())
|
||||||
|
.iter()
|
||||||
|
.fold(String::new(), |acc, s| acc + &format!("\t{}\n",s)[..])),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
Some(matches.args.keys().map(|k| *k).collect::<Vec<_>>()));
|
Some(matches.args.keys().map(|k| *k).collect::<Vec<_>>()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1478,8 +1498,16 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
|
||||||
|
|
||||||
if !self.required.is_empty() {
|
if !self.required.is_empty() {
|
||||||
if self.validate_required(&matches) {
|
if self.validate_required(&matches) {
|
||||||
self.report_error("One or more required arguments were not supplied".to_owned(),
|
self.report_error(format!("The following required arguments were not \
|
||||||
true, true, Some(matches.args.keys().map(|k| *k).collect::<Vec<_>>()));
|
supplied:\n{}",
|
||||||
|
self.get_required_from(self.required.iter()
|
||||||
|
.map(|s| *s)
|
||||||
|
.collect::<HashSet<_>>())
|
||||||
|
.iter()
|
||||||
|
.fold(String::new(), |acc, s| acc + &format!("\t{}\n",s)[..])),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
Some(matches.args.keys().map(|k| *k).collect::<Vec<_>>()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,13 +35,13 @@ impl<'n> Display for OptBuilder<'n> {
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||||
write!(f, "{}",
|
write!(f, "{}",
|
||||||
if let Some(ref vec) = self.val_names {
|
if let Some(ref vec) = self.val_names {
|
||||||
format!("[ {} {}]",
|
format!("{}{}",
|
||||||
if self.long.is_some() {
|
if self.long.is_some() {
|
||||||
format!("--{}", self.long.unwrap())
|
format!("--{}", self.long.unwrap())
|
||||||
} else {
|
} else {
|
||||||
format!("-{}", self.short.unwrap())
|
format!("-{}", self.short.unwrap())
|
||||||
},
|
},
|
||||||
vec.iter().fold(String::new(),|acc, i| acc + &format!("<{}> ",i)[..]) )
|
vec.iter().fold(String::new(),|acc, i| acc + &format!(" <{}>",i)[..]) )
|
||||||
} else {
|
} else {
|
||||||
format!("{} <{}>{}",
|
format!("{} <{}>{}",
|
||||||
if self.long.is_some() {
|
if self.long.is_some() {
|
||||||
|
|
Loading…
Reference in a new issue