mirror of
https://github.com/clap-rs/clap
synced 2024-12-14 14:52:33 +00:00
refactor: moves usage string generation code into it's own module
This commit is contained in:
parent
44ed8b663c
commit
622b609c57
5 changed files with 435 additions and 314 deletions
|
@ -11,6 +11,7 @@ use app::parser::Parser;
|
||||||
use args::{AnyArg, ArgSettings, DispOrder};
|
use args::{AnyArg, ArgSettings, DispOrder};
|
||||||
use errors::{Error, Result as ClapResult};
|
use errors::{Error, Result as ClapResult};
|
||||||
use fmt::{Format, Colorizer};
|
use fmt::{Format, Colorizer};
|
||||||
|
use app::usage;
|
||||||
|
|
||||||
// Third Party
|
// Third Party
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
@ -682,7 +683,7 @@ impl<'a> Help<'a> {
|
||||||
try!(write!(self.writer,
|
try!(write!(self.writer,
|
||||||
"\n{}{}\n\n",
|
"\n{}{}\n\n",
|
||||||
TAB,
|
TAB,
|
||||||
parser.create_usage_no_title(&[])));
|
usage::create_help_usage(parser)));
|
||||||
|
|
||||||
let flags = parser.has_flags();
|
let flags = parser.has_flags();
|
||||||
let pos = parser.has_positionals();
|
let pos = parser.has_positionals();
|
||||||
|
@ -879,7 +880,7 @@ impl<'a> Help<'a> {
|
||||||
parser.meta.about.unwrap_or("unknown about")));
|
parser.meta.about.unwrap_or("unknown about")));
|
||||||
}
|
}
|
||||||
b"usage" => {
|
b"usage" => {
|
||||||
try!(write!(self.writer, "{}", parser.create_usage_no_title(&[])));
|
try!(write!(self.writer, "{}", usage::create_help_usage(parser)));
|
||||||
}
|
}
|
||||||
b"all-args" => {
|
b"all-args" => {
|
||||||
try!(self.write_all_args(&parser));
|
try!(self.write_all_args(&parser));
|
||||||
|
|
|
@ -5,6 +5,7 @@ pub mod parser;
|
||||||
mod meta;
|
mod meta;
|
||||||
mod help;
|
mod help;
|
||||||
mod validator;
|
mod validator;
|
||||||
|
mod usage;
|
||||||
|
|
||||||
// Std
|
// Std
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
|
@ -32,6 +32,7 @@ use completions::Shell;
|
||||||
use suggestions;
|
use suggestions;
|
||||||
use app::settings::AppSettings as AS;
|
use app::settings::AppSettings as AS;
|
||||||
use app::validator::Validator;
|
use app::validator::Validator;
|
||||||
|
use app::usage;
|
||||||
|
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -98,7 +99,11 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
let out_dir = PathBuf::from(od);
|
let out_dir = PathBuf::from(od);
|
||||||
let name = &*self.meta.bin_name.as_ref().unwrap().clone();
|
let name = &*self.meta
|
||||||
|
.bin_name
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.clone();
|
||||||
let file_name = match for_shell {
|
let file_name = match for_shell {
|
||||||
Shell::Bash => format!("{}.bash-completion", name),
|
Shell::Bash => format!("{}.bash-completion", name),
|
||||||
Shell::Fish => format!("{}.fish", name),
|
Shell::Fish => format!("{}.fish", name),
|
||||||
|
@ -249,8 +254,10 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.groups.iter().any(|g| g.name == group.name) {
|
if self.groups.iter().any(|g| g.name == group.name) {
|
||||||
let grp =
|
let grp = self.groups
|
||||||
self.groups.iter_mut().find(|g| g.name == group.name).expect(INTERNAL_ERROR_MSG);
|
.iter_mut()
|
||||||
|
.find(|g| g.name == group.name)
|
||||||
|
.expect(INTERNAL_ERROR_MSG);
|
||||||
grp.args.extend_from_slice(&group.args);
|
grp.args.extend_from_slice(&group.args);
|
||||||
grp.requires = group.requires.clone();
|
grp.requires = group.requires.clone();
|
||||||
grp.conflicts = group.conflicts.clone();
|
grp.conflicts = group.conflicts.clone();
|
||||||
|
@ -290,7 +297,11 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
if vsc {
|
if vsc {
|
||||||
sc.p.set(AS::DisableVersion);
|
sc.p.set(AS::DisableVersion);
|
||||||
}
|
}
|
||||||
if gv && sc.p.meta.version.is_none() && self.meta.version.is_some() {
|
if gv &&
|
||||||
|
sc.p
|
||||||
|
.meta
|
||||||
|
.version
|
||||||
|
.is_none() && self.meta.version.is_some() {
|
||||||
sc.p.set(AS::GlobalVersion);
|
sc.p.set(AS::GlobalVersion);
|
||||||
sc.p.meta.version = Some(self.meta.version.unwrap());
|
sc.p.meta.version = Some(self.meta.version.unwrap());
|
||||||
}
|
}
|
||||||
|
@ -444,7 +455,9 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
.filter(|name| !self.positionals.values().any(|p| &&p.b.name == name))
|
.filter(|name| !self.positionals.values().any(|p| &&p.b.name == name))
|
||||||
.filter(|name| !self.groups.iter().any(|g| &&g.name == name))
|
.filter(|name| !self.groups.iter().any(|g| &&g.name == name))
|
||||||
.filter(|name| !args_in_groups.contains(name))
|
.filter(|name| !args_in_groups.contains(name))
|
||||||
.filter(|name| !(matcher.is_some() && matcher.as_ref().unwrap().contains(name))) {
|
.filter(|name| {
|
||||||
|
!(matcher.is_some() && matcher.as_ref().unwrap().contains(name))
|
||||||
|
}) {
|
||||||
debugln!("Parser::get_required_from:iter:{}:", a);
|
debugln!("Parser::get_required_from:iter:{}:", a);
|
||||||
let arg = find_by_name!(self, a, flags, iter)
|
let arg = find_by_name!(self, a, flags, iter)
|
||||||
.map(|f| f.to_string())
|
.map(|f| f.to_string())
|
||||||
|
@ -457,8 +470,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
}
|
}
|
||||||
let mut g_vec = vec![];
|
let mut g_vec = vec![];
|
||||||
for g in desc_reqs.iter().filter(|n| self.groups.iter().any(|g| &&g.name == n)) {
|
for g in desc_reqs.iter().filter(|n| self.groups.iter().any(|g| &&g.name == n)) {
|
||||||
let g_string = self.args_in_group(g)
|
let g_string = self.args_in_group(g).join("|");
|
||||||
.join("|");
|
|
||||||
g_vec.push(format!("<{}>", &g_string[..g_string.len()]));
|
g_vec.push(format!("<{}>", &g_string[..g_string.len()]));
|
||||||
}
|
}
|
||||||
g_vec.sort();
|
g_vec.sort();
|
||||||
|
@ -474,8 +486,10 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
pub fn get_args_tag(&self) -> Option<String> {
|
pub fn get_args_tag(&self) -> Option<String> {
|
||||||
debugln!("Parser::get_args_tag;");
|
debugln!("Parser::get_args_tag;");
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
'outer: for p in self.positionals.values().filter(|p| !p.is_set(ArgSettings::Required) &&
|
'outer: for p in self.positionals.values().filter(|p| {
|
||||||
!p.is_set(ArgSettings::Hidden)) {
|
!p.is_set(ArgSettings::Required) &&
|
||||||
|
!p.is_set(ArgSettings::Hidden)
|
||||||
|
}) {
|
||||||
debugln!("Parser::get_args_tag:iter:{}:", p.b.name);
|
debugln!("Parser::get_args_tag:iter:{}:", p.b.name);
|
||||||
if let Some(g_vec) = self.groups_for_arg(p.b.name) {
|
if let Some(g_vec) = self.groups_for_arg(p.b.name) {
|
||||||
for grp_s in &g_vec {
|
for grp_s in &g_vec {
|
||||||
|
@ -487,7 +501,8 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
count += 1;
|
count += 1;
|
||||||
debugln!("Parser::get_args_tag:iter: {} Args not required or hidden", count);
|
debugln!("Parser::get_args_tag:iter: {} Args not required or hidden",
|
||||||
|
count);
|
||||||
}
|
}
|
||||||
if !self.is_set(AS::DontCollapseArgsInUsage) && count > 1 {
|
if !self.is_set(AS::DontCollapseArgsInUsage) && count > 1 {
|
||||||
return None; // [ARGS]
|
return None; // [ARGS]
|
||||||
|
@ -502,7 +517,9 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
.values()
|
.values()
|
||||||
.filter(|p| !p.is_set(ArgSettings::Required))
|
.filter(|p| !p.is_set(ArgSettings::Required))
|
||||||
.filter(|p| !p.is_set(ArgSettings::Hidden))
|
.filter(|p| !p.is_set(ArgSettings::Hidden))
|
||||||
.map(|p| format!(" [{}]{}", p.name_no_brackets(), p.multiple_str()))
|
.map(|p| {
|
||||||
|
format!(" [{}]{}", p.name_no_brackets(), p.multiple_str())
|
||||||
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(""));
|
.join(""));
|
||||||
}
|
}
|
||||||
|
@ -559,25 +576,33 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn has_visible_opts(&self) -> bool {
|
pub fn has_visible_opts(&self) -> bool {
|
||||||
if self.opts.is_empty() { return false; }
|
if self.opts.is_empty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
self.opts.iter().any(|o| !o.is_set(ArgSettings::Hidden))
|
self.opts.iter().any(|o| !o.is_set(ArgSettings::Hidden))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn has_visible_flags(&self) -> bool {
|
pub fn has_visible_flags(&self) -> bool {
|
||||||
if self.flags.is_empty() { return false; }
|
if self.flags.is_empty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
self.flags.iter().any(|f| !f.is_set(ArgSettings::Hidden))
|
self.flags.iter().any(|f| !f.is_set(ArgSettings::Hidden))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn has_visible_positionals(&self) -> bool {
|
pub fn has_visible_positionals(&self) -> bool {
|
||||||
if self.positionals.is_empty() { return false; }
|
if self.positionals.is_empty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
self.positionals.values().any(|p| !p.is_set(ArgSettings::Hidden))
|
self.positionals.values().any(|p| !p.is_set(ArgSettings::Hidden))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn has_visible_subcommands(&self) -> bool {
|
pub fn has_visible_subcommands(&self) -> bool {
|
||||||
if self.subcommands.is_empty() { return false; }
|
if self.subcommands.is_empty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
self.subcommands.iter().any(|s| !s.p.is_set(AS::Hidden))
|
self.subcommands.iter().any(|s| !s.p.is_set(AS::Hidden))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -598,7 +623,10 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
// Firt we verify that the index highest supplied index, is equal to the number of
|
// Firt 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
|
// positional arguments to verify there are no gaps (i.e. supplying an index of 1 and 3
|
||||||
// but no 2)
|
// but no 2)
|
||||||
if let Some((idx, p)) = self.positionals.iter().rev().next() {
|
if let Some((idx, p)) = self.positionals
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.next() {
|
||||||
debug_assert!(!(idx != self.positionals.len()),
|
debug_assert!(!(idx != self.positionals.len()),
|
||||||
format!("Found positional argument \"{}\" who's index is {} but there \
|
format!("Found positional argument \"{}\" who's index is {} but there \
|
||||||
are only {} positional arguments defined",
|
are only {} positional arguments defined",
|
||||||
|
@ -608,11 +636,9 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next we verify that only the highest index has a .multiple(true) (if any)
|
// Next we verify that only the highest index has a .multiple(true) (if any)
|
||||||
if
|
if self.positionals.values().any(|a| {
|
||||||
self.positionals
|
a.is_set(ArgSettings::Multiple) &&
|
||||||
.values()
|
(a.index as usize != self.positionals.len())
|
||||||
.any(|a| {
|
|
||||||
a.is_set(ArgSettings::Multiple) && (a.index as usize != self.positionals.len())
|
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
debug_assert!({
|
debug_assert!({
|
||||||
|
@ -628,7 +654,10 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
|
|
||||||
debug_assert!({
|
debug_assert!({
|
||||||
let num = self.positionals.len() - 1;
|
let num = self.positionals.len() - 1;
|
||||||
self.positionals.get(num).unwrap().is_set(ArgSettings::Multiple)
|
self.positionals
|
||||||
|
.get(num)
|
||||||
|
.unwrap()
|
||||||
|
.is_set(ArgSettings::Multiple)
|
||||||
},
|
},
|
||||||
"Only the last positional argument, or second to last positional \
|
"Only the last positional argument, or second to last positional \
|
||||||
argument may be set to .multiple(true)");
|
argument may be set to .multiple(true)");
|
||||||
|
@ -639,7 +668,8 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
debug_assert!(self.positionals
|
debug_assert!(self.positionals
|
||||||
.values()
|
.values()
|
||||||
.filter(|p| {
|
.filter(|p| {
|
||||||
p.b.settings.is_set(ArgSettings::Multiple) && p.v.num_vals.is_none()
|
p.b.settings.is_set(ArgSettings::Multiple) &&
|
||||||
|
p.v.num_vals.is_none()
|
||||||
})
|
})
|
||||||
.map(|_| 1)
|
.map(|_| 1)
|
||||||
.sum::<u64>() <= 1,
|
.sum::<u64>() <= 1,
|
||||||
|
@ -729,7 +759,10 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|s| {
|
.filter(|s| {
|
||||||
starts(&s.p.meta.name[..], &*arg_os) ||
|
starts(&s.p.meta.name[..], &*arg_os) ||
|
||||||
(s.p.meta.aliases.is_some() &&
|
(s.p
|
||||||
|
.meta
|
||||||
|
.aliases
|
||||||
|
.is_some() &&
|
||||||
s.p
|
s.p
|
||||||
.meta
|
.meta
|
||||||
.aliases
|
.aliases
|
||||||
|
@ -778,11 +811,8 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
}
|
}
|
||||||
} else if let Some(c) = sc.subcommands
|
} else if let Some(c) = sc.subcommands
|
||||||
.iter()
|
.iter()
|
||||||
.find(|s| if let Some(ref als) = s.p
|
.find(|s| if let Some(ref als) = s.p.meta.aliases {
|
||||||
.meta
|
als.iter().any(|&(a, _)| &a == &&*cmd.to_string_lossy())
|
||||||
.aliases {
|
|
||||||
als.iter()
|
|
||||||
.any(|&(a, _)| &a == &&*cmd.to_string_lossy())
|
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
})
|
})
|
||||||
|
@ -957,7 +987,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
arg_os.to_string_lossy().parse::<f64>().is_ok()) {
|
arg_os.to_string_lossy().parse::<f64>().is_ok()) {
|
||||||
return Err(Error::unknown_argument(&*arg_os.to_string_lossy(),
|
return Err(Error::unknown_argument(&*arg_os.to_string_lossy(),
|
||||||
"",
|
"",
|
||||||
&*self.create_current_usage(matcher, None),
|
&*usage::create_error_usage(self, matcher, None),
|
||||||
self.color()));
|
self.color()));
|
||||||
}
|
}
|
||||||
} else if !self.is_set(AS::AllowLeadingHyphen) {
|
} else if !self.is_set(AS::AllowLeadingHyphen) {
|
||||||
|
@ -980,7 +1010,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
.bin_name
|
.bin_name
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap_or(&self.meta.name),
|
.unwrap_or(&self.meta.name),
|
||||||
&*self.create_current_usage(matcher,
|
&*usage::create_error_usage(self, matcher,
|
||||||
None),
|
None),
|
||||||
self.color()));
|
self.color()));
|
||||||
}
|
}
|
||||||
|
@ -1029,7 +1059,8 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
Some(s) => s.to_string(),
|
Some(s) => s.to_string(),
|
||||||
None => {
|
None => {
|
||||||
if !self.is_set(AS::StrictUtf8) {
|
if !self.is_set(AS::StrictUtf8) {
|
||||||
return Err(Error::invalid_utf8(&*self.create_current_usage(matcher,
|
return Err(Error::invalid_utf8(&*usage::create_error_usage(self,
|
||||||
|
matcher,
|
||||||
None),
|
None),
|
||||||
self.color()));
|
self.color()));
|
||||||
}
|
}
|
||||||
|
@ -1042,7 +1073,9 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
while let Some(v) = it.next() {
|
while let Some(v) = it.next() {
|
||||||
let a = v.into();
|
let a = v.into();
|
||||||
if a.to_str().is_none() && !self.is_set(AS::StrictUtf8) {
|
if a.to_str().is_none() && !self.is_set(AS::StrictUtf8) {
|
||||||
return Err(Error::invalid_utf8(&*self.create_current_usage(matcher, None),
|
return Err(Error::invalid_utf8(&*usage::create_error_usage(self,
|
||||||
|
matcher,
|
||||||
|
None),
|
||||||
self.color()));
|
self.color()));
|
||||||
}
|
}
|
||||||
sc_m.add_val_to("", &a);
|
sc_m.add_val_to("", &a);
|
||||||
|
@ -1057,19 +1090,21 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
!self.is_set(AS::InferSubcommands) {
|
!self.is_set(AS::InferSubcommands) {
|
||||||
return Err(Error::unknown_argument(&*arg_os.to_string_lossy(),
|
return Err(Error::unknown_argument(&*arg_os.to_string_lossy(),
|
||||||
"",
|
"",
|
||||||
&*self.create_current_usage(matcher, None),
|
&*usage::create_error_usage(self,
|
||||||
|
matcher,
|
||||||
|
None),
|
||||||
self.color()));
|
self.color()));
|
||||||
} else if !(has_args) && self.has_subcommands() {
|
} else if !(has_args) && self.has_subcommands() {
|
||||||
if let Some(cdate) = suggestions::did_you_mean(&*arg_os.to_string_lossy(),
|
if let Some(cdate) = suggestions::did_you_mean(&*arg_os.to_string_lossy(),
|
||||||
sc_names!(self)) {
|
sc_names!(self)) {
|
||||||
return Err(Error::invalid_subcommand(arg_os.to_string_lossy()
|
return Err(Error::invalid_subcommand(arg_os.to_string_lossy().into_owned(),
|
||||||
.into_owned(),
|
|
||||||
cdate,
|
cdate,
|
||||||
self.meta
|
self.meta
|
||||||
.bin_name
|
.bin_name
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap_or(&self.meta.name),
|
.unwrap_or(&self.meta.name),
|
||||||
&*self.create_current_usage(matcher,
|
&*usage::create_error_usage(self,
|
||||||
|
matcher,
|
||||||
None),
|
None),
|
||||||
self.color()));
|
self.color()));
|
||||||
}
|
}
|
||||||
|
@ -1078,13 +1113,23 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
|
|
||||||
if let Some(ref pos_sc_name) = subcmd_name {
|
if let Some(ref pos_sc_name) = subcmd_name {
|
||||||
let sc_name = {
|
let sc_name = {
|
||||||
find_subcmd!(self, pos_sc_name).expect(INTERNAL_ERROR_MSG).p.meta.name.clone()
|
find_subcmd!(self, pos_sc_name)
|
||||||
|
.expect(INTERNAL_ERROR_MSG)
|
||||||
|
.p
|
||||||
|
.meta
|
||||||
|
.name
|
||||||
|
.clone()
|
||||||
};
|
};
|
||||||
try!(self.parse_subcommand(&*sc_name, matcher, it));
|
try!(self.parse_subcommand(&*sc_name, matcher, it));
|
||||||
} else if self.is_set(AS::SubcommandRequired) {
|
} else if self.is_set(AS::SubcommandRequired) {
|
||||||
let bn = self.meta.bin_name.as_ref().unwrap_or(&self.meta.name);
|
let bn = self.meta
|
||||||
|
.bin_name
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or(&self.meta.name);
|
||||||
return Err(Error::missing_subcommand(bn,
|
return Err(Error::missing_subcommand(bn,
|
||||||
&self.create_current_usage(matcher, None),
|
&usage::create_error_usage(self,
|
||||||
|
matcher,
|
||||||
|
None),
|
||||||
self.color()));
|
self.color()));
|
||||||
} else if self.is_set(AS::SubcommandRequiredElseHelp) {
|
} else if self.is_set(AS::SubcommandRequiredElseHelp) {
|
||||||
debugln!("parser::get_matches_with: SubcommandRequiredElseHelp=true");
|
debugln!("parser::get_matches_with: SubcommandRequiredElseHelp=true");
|
||||||
|
@ -1113,7 +1158,10 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
debugln!("Parser::build_bin_names;");
|
debugln!("Parser::build_bin_names;");
|
||||||
for sc in &mut self.subcommands {
|
for sc in &mut self.subcommands {
|
||||||
debug!("Parser::build_bin_names:iter: bin_name set...");
|
debug!("Parser::build_bin_names:iter: bin_name set...");
|
||||||
if sc.p.meta.bin_name.is_none() {
|
if sc.p
|
||||||
|
.meta
|
||||||
|
.bin_name
|
||||||
|
.is_none() {
|
||||||
sdebugln!("No");
|
sdebugln!("No");
|
||||||
let bin_name = format!("{}{}{}",
|
let bin_name = format!("{}{}{}",
|
||||||
self.meta
|
self.meta
|
||||||
|
@ -1151,7 +1199,10 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
debugln!("Parser::parse_subcommand;");
|
debugln!("Parser::parse_subcommand;");
|
||||||
let mut mid_string = String::new();
|
let mut mid_string = String::new();
|
||||||
if !self.is_set(AS::SubcommandsNegateReqs) {
|
if !self.is_set(AS::SubcommandsNegateReqs) {
|
||||||
let mut hs: Vec<&str> = self.required.iter().map(|n| &**n).collect();
|
let mut hs: Vec<&str> = self.required
|
||||||
|
.iter()
|
||||||
|
.map(|n| &**n)
|
||||||
|
.collect();
|
||||||
for k in matcher.arg_names() {
|
for k in matcher.arg_names() {
|
||||||
hs.push(k);
|
hs.push(k);
|
||||||
}
|
}
|
||||||
|
@ -1162,14 +1213,15 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mid_string.push_str(" ");
|
mid_string.push_str(" ");
|
||||||
if let Some(ref mut sc) = self.subcommands
|
if let Some(ref mut sc) = self.subcommands.iter_mut().find(|s| &s.p.meta.name == &sc_name) {
|
||||||
.iter_mut()
|
|
||||||
.find(|s| &s.p.meta.name == &sc_name) {
|
|
||||||
let mut sc_matcher = ArgMatcher::new();
|
let mut sc_matcher = ArgMatcher::new();
|
||||||
// bin_name should be parent's bin_name + [<reqs>] + the sc's name separated by
|
// bin_name should be parent's bin_name + [<reqs>] + the sc's name separated by
|
||||||
// a space
|
// a space
|
||||||
sc.p.meta.usage = Some(format!("{}{}{}",
|
sc.p.meta.usage = Some(format!("{}{}{}",
|
||||||
self.meta.bin_name.as_ref().unwrap_or(&String::new()),
|
self.meta
|
||||||
|
.bin_name
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or(&String::new()),
|
||||||
if self.meta.bin_name.is_some() {
|
if self.meta.bin_name.is_some() {
|
||||||
&*mid_string
|
&*mid_string
|
||||||
} else {
|
} else {
|
||||||
|
@ -1192,7 +1244,10 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
debugln!("Parser::parse_subcommand: sc settings={:#?}", sc.p.settings);
|
debugln!("Parser::parse_subcommand: sc settings={:#?}", sc.p.settings);
|
||||||
try!(sc.p.get_matches_with(&mut sc_matcher, it));
|
try!(sc.p.get_matches_with(&mut sc_matcher, it));
|
||||||
matcher.subcommand(SubCommand {
|
matcher.subcommand(SubCommand {
|
||||||
name: sc.p.meta.name.clone(),
|
name: sc.p
|
||||||
|
.meta
|
||||||
|
.name
|
||||||
|
.clone(),
|
||||||
matches: sc_matcher.into(),
|
matches: sc_matcher.into(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1228,14 +1283,16 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
let mut g_vec = vec![];
|
let mut g_vec = vec![];
|
||||||
let mut args = vec![];
|
let mut args = vec![];
|
||||||
|
|
||||||
for n in &self.groups.iter().find(|g| g.name == group).expect(INTERNAL_ERROR_MSG).args {
|
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) {
|
if let Some(f) = self.flags.iter().find(|f| &f.b.name == n) {
|
||||||
args.push(f.to_string());
|
args.push(f.to_string());
|
||||||
} else if let Some(f) = self.opts.iter().find(|o| &o.b.name == n) {
|
} else if let Some(f) = self.opts.iter().find(|o| &o.b.name == n) {
|
||||||
args.push(f.to_string());
|
args.push(f.to_string());
|
||||||
} else if let Some(p) = self.positionals
|
} else if let Some(p) = self.positionals.values().find(|p| &p.b.name == n) {
|
||||||
.values()
|
|
||||||
.find(|p| &p.b.name == n) {
|
|
||||||
args.push(p.b.name.to_owned());
|
args.push(p.b.name.to_owned());
|
||||||
} else {
|
} else {
|
||||||
g_vec.push(*n);
|
g_vec.push(*n);
|
||||||
|
@ -1253,7 +1310,11 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
let mut g_vec = vec![];
|
let mut g_vec = vec![];
|
||||||
let mut args = vec![];
|
let mut args = vec![];
|
||||||
|
|
||||||
for n in &self.groups.iter().find(|g| g.name == group).expect(INTERNAL_ERROR_MSG).args {
|
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) {
|
if self.groups.iter().any(|g| &g.name == &*n) {
|
||||||
args.extend(self.arg_names_in_group(&*n));
|
args.extend(self.arg_names_in_group(&*n));
|
||||||
g_vec.push(*n);
|
g_vec.push(*n);
|
||||||
|
@ -1321,26 +1382,6 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
|
|
||||||
// Retrieves the names of all args the user has supplied thus far, except required ones
|
// Retrieves the names of all args the user has supplied thus far, except required ones
|
||||||
// because those will be listed in self.required
|
// because those will be listed in self.required
|
||||||
pub fn create_current_usage(&self, matcher: &'b ArgMatcher<'a>, extra: Option<&str>) -> String {
|
|
||||||
let mut args: Vec<_> = matcher.arg_names()
|
|
||||||
.iter()
|
|
||||||
.filter(|n| {
|
|
||||||
if let Some(o) = find_by_name!(self, *n, opts, iter) {
|
|
||||||
!o.b.settings.is_set(ArgSettings::Required)
|
|
||||||
} else if let Some(p) = find_by_name!(self, *n, positionals, values) {
|
|
||||||
!p.b.settings.is_set(ArgSettings::Required)
|
|
||||||
} else {
|
|
||||||
true // flags can't be required, so they're always true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map(|&n| n)
|
|
||||||
.collect();
|
|
||||||
if let Some(r) = extra {
|
|
||||||
args.push(r);
|
|
||||||
}
|
|
||||||
self.create_usage(&*args)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_for_help_and_version_str(&self, arg: &OsStr) -> ClapResult<()> {
|
fn check_for_help_and_version_str(&self, arg: &OsStr) -> ClapResult<()> {
|
||||||
debugln!("Parser::check_for_help_and_version_str;");
|
debugln!("Parser::check_for_help_and_version_str;");
|
||||||
debug!("Parser::check_for_help_and_version_str: Checking if --{} is help or version...",
|
debug!("Parser::check_for_help_and_version_str: Checking if --{} is help or version...",
|
||||||
|
@ -1530,7 +1571,9 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
let arg = format!("-{}", c);
|
let arg = format!("-{}", c);
|
||||||
return Err(Error::unknown_argument(&*arg,
|
return Err(Error::unknown_argument(&*arg,
|
||||||
"",
|
"",
|
||||||
&*self.create_current_usage(matcher, None),
|
&*usage::create_error_usage(self,
|
||||||
|
matcher,
|
||||||
|
None),
|
||||||
self.color()));
|
self.color()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1555,7 +1598,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
(v.len_() == 0 || (opt.is_set(ArgSettings::RequireEquals) && !has_eq)) {
|
(v.len_() == 0 || (opt.is_set(ArgSettings::RequireEquals) && !has_eq)) {
|
||||||
sdebugln!("Found Empty - Error");
|
sdebugln!("Found Empty - Error");
|
||||||
return Err(Error::empty_value(opt,
|
return Err(Error::empty_value(opt,
|
||||||
&*self.create_current_usage(matcher, None),
|
&*usage::create_error_usage(self, matcher, None),
|
||||||
self.color()));
|
self.color()));
|
||||||
}
|
}
|
||||||
sdebugln!("Found - {:?}, len: {}", v, v.len_());
|
sdebugln!("Found - {:?}, len: {}", v, v.len_());
|
||||||
|
@ -1566,7 +1609,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
} else if opt.is_set(ArgSettings::RequireEquals) && !opt.is_set(ArgSettings::EmptyValues) {
|
} else if opt.is_set(ArgSettings::RequireEquals) && !opt.is_set(ArgSettings::EmptyValues) {
|
||||||
sdebugln!("None, but requires equals...Error");
|
sdebugln!("None, but requires equals...Error");
|
||||||
return Err(Error::empty_value(opt,
|
return Err(Error::empty_value(opt,
|
||||||
&*self.create_current_usage(matcher, None),
|
&*usage::create_error_usage(self, matcher, None),
|
||||||
self.color()));
|
self.color()));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -1689,130 +1732,10 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
let used_arg = format!("--{}", arg);
|
let used_arg = format!("--{}", arg);
|
||||||
Err(Error::unknown_argument(&*used_arg,
|
Err(Error::unknown_argument(&*used_arg,
|
||||||
&*suffix.0,
|
&*suffix.0,
|
||||||
&*self.create_current_usage(matcher, None),
|
&*usage::create_error_usage(self, matcher, None),
|
||||||
self.color()))
|
self.color()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 give subcommands their own usage recursively)
|
|
||||||
pub fn create_usage(&self, used: &[&str]) -> String {
|
|
||||||
debugln!("Parser::create_usage;");
|
|
||||||
let mut usage = String::with_capacity(75);
|
|
||||||
usage.push_str("USAGE:\n ");
|
|
||||||
usage.push_str(&self.create_usage_no_title(used));
|
|
||||||
usage
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates a usage string (*without title*) 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 give subcommands their own usage recursively)
|
|
||||||
pub fn create_usage_no_title(&self, used: &[&str]) -> String {
|
|
||||||
debugln!("Parser::create_usage_no_title;");
|
|
||||||
let mut usage = String::with_capacity(75);
|
|
||||||
if let Some(u) = self.meta.usage_str {
|
|
||||||
usage.push_str(&*u);
|
|
||||||
} else if used.is_empty() {
|
|
||||||
let name = self.meta
|
|
||||||
.usage
|
|
||||||
.as_ref()
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
self.meta
|
|
||||||
.bin_name
|
|
||||||
.as_ref()
|
|
||||||
.unwrap_or(&self.meta.name)
|
|
||||||
});
|
|
||||||
usage.push_str(&*name);
|
|
||||||
let mut reqs: Vec<&str> = self.required().map(|r| &**r).collect();
|
|
||||||
reqs.dedup();
|
|
||||||
let req_string = self.get_required_from(&reqs, None, None)
|
|
||||||
.iter()
|
|
||||||
.fold(String::new(), |a, s| a + &format!(" {}", s)[..]);
|
|
||||||
|
|
||||||
let flags = self.needs_flags_tag();
|
|
||||||
if flags && !self.is_set(AS::UnifiedHelpMessage) {
|
|
||||||
usage.push_str(" [FLAGS]");
|
|
||||||
} else if flags {
|
|
||||||
usage.push_str(" [OPTIONS]");
|
|
||||||
}
|
|
||||||
if !self.is_set(AS::UnifiedHelpMessage) &&
|
|
||||||
self.opts.iter().any(|o| !o.is_set(ArgSettings::Required) &&
|
|
||||||
!o.is_set(ArgSettings::Hidden)) {
|
|
||||||
usage.push_str(" [OPTIONS]");
|
|
||||||
}
|
|
||||||
|
|
||||||
usage.push_str(&req_string[..]);
|
|
||||||
|
|
||||||
// places a '--' in the usage string if there are args and options
|
|
||||||
// supporting multiple values
|
|
||||||
if self.has_positionals() &&
|
|
||||||
self.opts.iter().any(|o| o.is_set(ArgSettings::Multiple)) &&
|
|
||||||
self.positionals.values().any(|p| !p.is_set(ArgSettings::Required)) &&
|
|
||||||
!self.has_visible_subcommands() {
|
|
||||||
usage.push_str(" [--]")
|
|
||||||
}
|
|
||||||
if self.has_positionals() &&
|
|
||||||
self.positionals.values().any(|p| !p.is_set(ArgSettings::Required) &&
|
|
||||||
!p.is_set(ArgSettings::Hidden)) {
|
|
||||||
if let Some(args_tag) = self.get_args_tag() {
|
|
||||||
usage.push_str(&*args_tag);
|
|
||||||
} else {
|
|
||||||
usage.push_str(" [ARGS]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if self.is_set(AS::SubcommandsNegateReqs) || self.is_set(AS::ArgsNegateSubcommands) {
|
|
||||||
if self.has_visible_subcommands() {
|
|
||||||
usage.push_str("\n ");
|
|
||||||
usage.push_str(&*name);
|
|
||||||
usage.push_str(" <SUBCOMMAND>");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if self.has_visible_subcommands() && !self.is_set(AS::SubcommandRequired) {
|
|
||||||
usage.push_str(" [SUBCOMMAND]");
|
|
||||||
} else if (self.is_set(AS::SubcommandRequired) ||
|
|
||||||
self.is_set(AS::SubcommandRequiredElseHelp)) && self.has_subcommands() {
|
|
||||||
usage.push_str(" <SUBCOMMAND>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.smart_usage(&mut usage, used);
|
|
||||||
}
|
|
||||||
|
|
||||||
usage.shrink_to_fit();
|
|
||||||
usage
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates a context aware usage string, or "smart usage" from currently used
|
|
||||||
// args, and requirements
|
|
||||||
fn smart_usage(&self, usage: &mut String, used: &[&str]) {
|
|
||||||
debugln!("Parser::smart_usage;");
|
|
||||||
let mut hs: Vec<&str> = self.required().map(|s| &**s).collect();
|
|
||||||
hs.extend_from_slice(used);
|
|
||||||
|
|
||||||
let r_string = self.get_required_from(&hs, None, None)
|
|
||||||
.iter()
|
|
||||||
.fold(String::new(), |acc, s| acc + &format!(" {}", s)[..]);
|
|
||||||
|
|
||||||
usage.push_str(&self.meta
|
|
||||||
.usage
|
|
||||||
.as_ref()
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
self.meta
|
|
||||||
.bin_name
|
|
||||||
.as_ref()
|
|
||||||
.unwrap_or(&self.meta
|
|
||||||
.name)
|
|
||||||
})
|
|
||||||
[..]);
|
|
||||||
usage.push_str(&*r_string);
|
|
||||||
if self.is_set(AS::SubcommandRequired) {
|
|
||||||
usage.push_str(" <SUBCOMMAND>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prints the version to the user and exits if quit=true
|
// Prints the version to the user and exits if quit=true
|
||||||
fn print_version<W: Write>(&self, w: &mut W) -> ClapResult<()> {
|
fn print_version<W: Write>(&self, w: &mut W) -> ClapResult<()> {
|
||||||
try!(self.write_version(w));
|
try!(self.write_version(w));
|
||||||
|
@ -1955,17 +1878,33 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||||
pub fn find_subcommand(&'b self, sc: &str) -> Option<&'b App<'a, 'b>> {
|
pub fn find_subcommand(&'b self, sc: &str) -> Option<&'b App<'a, 'b>> {
|
||||||
debugln!("Parser::find_subcommand: sc={}", sc);
|
debugln!("Parser::find_subcommand: sc={}", sc);
|
||||||
debugln!("Parser::find_subcommand: Currently in Parser...{}",
|
debugln!("Parser::find_subcommand: Currently in Parser...{}",
|
||||||
self.meta.bin_name.as_ref().unwrap());
|
self.meta
|
||||||
|
.bin_name
|
||||||
|
.as_ref()
|
||||||
|
.unwrap());
|
||||||
for s in self.subcommands.iter() {
|
for s in self.subcommands.iter() {
|
||||||
if s.p.meta.bin_name.as_ref().unwrap_or(&String::new()) == sc ||
|
if s.p
|
||||||
(s.p.meta.aliases.is_some() &&
|
.meta
|
||||||
|
.bin_name
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or(&String::new()) == sc ||
|
||||||
|
(s.p
|
||||||
|
.meta
|
||||||
|
.aliases
|
||||||
|
.is_some() &&
|
||||||
s.p
|
s.p
|
||||||
.meta
|
.meta
|
||||||
.aliases
|
.aliases
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.iter()
|
.iter()
|
||||||
.any(|&(s, _)| s == sc.split(' ').rev().next().expect(INTERNAL_ERROR_MSG))) {
|
.any(|&(s, _)| {
|
||||||
|
s ==
|
||||||
|
sc.split(' ')
|
||||||
|
.rev()
|
||||||
|
.next()
|
||||||
|
.expect(INTERNAL_ERROR_MSG)
|
||||||
|
})) {
|
||||||
return Some(s);
|
return Some(s);
|
||||||
}
|
}
|
||||||
if let Some(app) = s.p.find_subcommand(sc) {
|
if let Some(app) = s.p.find_subcommand(sc) {
|
||||||
|
|
153
src/app/usage.rs
Normal file
153
src/app/usage.rs
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
use args::{AnyArg, ArgMatcher};
|
||||||
|
use args::settings::ArgSettings;
|
||||||
|
use app::settings::AppSettings as AS;
|
||||||
|
use app::parser::Parser;
|
||||||
|
|
||||||
|
// Creates a usage string for display. This happens just after all arguments were parsed, but before
|
||||||
|
// any subcommands have been parsed (so as to give subcommands their own usage recursively)
|
||||||
|
pub fn create_usage_with_title(p: &Parser, used: &[&str]) -> String {
|
||||||
|
debugln!("Parser::create_usage_with_title;");
|
||||||
|
let mut usage = String::with_capacity(75);
|
||||||
|
usage.push_str("USAGE:\n ");
|
||||||
|
usage.push_str(&*create_usage_no_title(p, used));
|
||||||
|
usage
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a usage string to be used in error message (i.e. one with currently used args)
|
||||||
|
pub fn create_error_usage<'a, 'b>(p: &Parser<'a, 'b>,
|
||||||
|
matcher: &'b ArgMatcher<'a>,
|
||||||
|
extra: Option<&str>)
|
||||||
|
-> String {
|
||||||
|
let mut args: Vec<_> = matcher.arg_names()
|
||||||
|
.iter()
|
||||||
|
.filter(|n| {
|
||||||
|
if let Some(o) = find_by_name!(p, *n, opts, iter) {
|
||||||
|
!o.b.is_set(ArgSettings::Required) && !o.b.is_set(ArgSettings::Hidden)
|
||||||
|
} else if let Some(p) = find_by_name!(p, *n, positionals, values) {
|
||||||
|
!p.b.is_set(ArgSettings::Required) && p.b.is_set(ArgSettings::Hidden)
|
||||||
|
} else {
|
||||||
|
true // flags can't be required, so they're always true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|&n| n)
|
||||||
|
.collect();
|
||||||
|
if let Some(r) = extra {
|
||||||
|
args.push(r);
|
||||||
|
}
|
||||||
|
create_usage_with_title(p, &*args)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a usage string (*without title*) if one was not provided by the user manually.
|
||||||
|
fn create_usage_no_title(p: &Parser, used: &[&str]) -> String {
|
||||||
|
debugln!("Parser::create_usage_no_title;");
|
||||||
|
if let Some(u) = p.meta.usage_str {
|
||||||
|
String::from(&*u)
|
||||||
|
} else if used.is_empty() {
|
||||||
|
create_help_usage(p)
|
||||||
|
} else {
|
||||||
|
create_smart_usage(p, used)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a usage string for display in help messages (i.e. not for errors)
|
||||||
|
pub fn create_help_usage(p: &Parser) -> String {
|
||||||
|
let mut usage = String::with_capacity(75);
|
||||||
|
let name = p.meta
|
||||||
|
.usage
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
p.meta
|
||||||
|
.bin_name
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or(&p.meta.name)
|
||||||
|
});
|
||||||
|
usage.push_str(&*name);
|
||||||
|
let mut reqs: Vec<&str> = p.required().map(|r| &**r).collect();
|
||||||
|
reqs.dedup();
|
||||||
|
let req_string =
|
||||||
|
p.get_required_from(&reqs, None, None).iter().fold(String::new(),
|
||||||
|
|a, s| a + &format!(" {}", s)[..]);
|
||||||
|
|
||||||
|
let flags = p.needs_flags_tag();
|
||||||
|
if flags && !p.is_set(AS::UnifiedHelpMessage) {
|
||||||
|
usage.push_str(" [FLAGS]");
|
||||||
|
} else if flags {
|
||||||
|
usage.push_str(" [OPTIONS]");
|
||||||
|
}
|
||||||
|
if !p.is_set(AS::UnifiedHelpMessage) &&
|
||||||
|
p.opts.iter().any(|o| {
|
||||||
|
!o.is_set(ArgSettings::Required) && !o.is_set(ArgSettings::Hidden)
|
||||||
|
}) {
|
||||||
|
usage.push_str(" [OPTIONS]");
|
||||||
|
}
|
||||||
|
|
||||||
|
usage.push_str(&req_string[..]);
|
||||||
|
|
||||||
|
// places a '--' in the usage string if there are args and options
|
||||||
|
// supporting multiple values
|
||||||
|
if p.has_positionals() && p.opts.iter().any(|o| o.is_set(ArgSettings::Multiple)) &&
|
||||||
|
p.positionals.values().any(|p| !p.is_set(ArgSettings::Required)) &&
|
||||||
|
!p.has_visible_subcommands() {
|
||||||
|
usage.push_str(" [--]")
|
||||||
|
}
|
||||||
|
if p.has_positionals() &&
|
||||||
|
p.positionals.values().any(|p| {
|
||||||
|
!p.is_set(ArgSettings::Required) &&
|
||||||
|
!p.is_set(ArgSettings::Hidden)
|
||||||
|
}) {
|
||||||
|
if let Some(args_tag) = p.get_args_tag() {
|
||||||
|
usage.push_str(&*args_tag);
|
||||||
|
} else {
|
||||||
|
usage.push_str(" [ARGS]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if p.is_set(AS::SubcommandsNegateReqs) || p.is_set(AS::ArgsNegateSubcommands) {
|
||||||
|
if p.has_visible_subcommands() {
|
||||||
|
usage.push_str("\n ");
|
||||||
|
usage.push_str(&*name);
|
||||||
|
usage.push_str(" <SUBCOMMAND>");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if p.has_visible_subcommands() && !p.is_set(AS::SubcommandRequired) {
|
||||||
|
usage.push_str(" [SUBCOMMAND]");
|
||||||
|
} else if (p.is_set(AS::SubcommandRequired) ||
|
||||||
|
p.is_set(AS::SubcommandRequiredElseHelp)) &&
|
||||||
|
p.has_subcommands() {
|
||||||
|
usage.push_str(" <SUBCOMMAND>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
usage.shrink_to_fit();
|
||||||
|
usage
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a context aware usage string, or "smart usage" from currently used
|
||||||
|
// args, and requirements
|
||||||
|
fn create_smart_usage(p: &Parser, used: &[&str]) -> String {
|
||||||
|
debugln!("Parser::smart_usage;");
|
||||||
|
let mut usage = String::with_capacity(75);
|
||||||
|
let mut hs: Vec<&str> = p.required().map(|s| &**s).collect();
|
||||||
|
hs.extend_from_slice(used);
|
||||||
|
|
||||||
|
let r_string = p.get_required_from(&hs, None, None).iter().fold(String::new(), |acc, s| {
|
||||||
|
acc + &format!(" {}", s)[..]
|
||||||
|
});
|
||||||
|
|
||||||
|
usage.push_str(&p.meta
|
||||||
|
.usage
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
p.meta
|
||||||
|
.bin_name
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or(&p.meta.name)
|
||||||
|
})
|
||||||
|
[..]);
|
||||||
|
usage.push_str(&*r_string);
|
||||||
|
if p.is_set(AS::SubcommandRequired) {
|
||||||
|
usage.push_str(" <SUBCOMMAND>");
|
||||||
|
}
|
||||||
|
usage.shrink_to_fit();
|
||||||
|
usage
|
||||||
|
}
|
|
@ -12,13 +12,14 @@ use osstringext::OsStrExt2;
|
||||||
use app::settings::AppSettings as AS;
|
use app::settings::AppSettings as AS;
|
||||||
use app::parser::Parser;
|
use app::parser::Parser;
|
||||||
use fmt::Colorizer;
|
use fmt::Colorizer;
|
||||||
|
use app::usage;
|
||||||
|
|
||||||
pub struct Validator<'a, 'b, 'z>(&'z mut Parser<'a, 'b>) where 'a: 'b, 'b: 'z;
|
pub struct Validator<'a, 'b, 'z>(&'z mut Parser<'a, 'b>)
|
||||||
|
where 'a: 'b,
|
||||||
|
'b: 'z;
|
||||||
|
|
||||||
impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||||
pub fn new(p: &'z mut Parser<'a, 'b>) -> Self {
|
pub fn new(p: &'z mut Parser<'a, 'b>) -> Self { Validator(p) }
|
||||||
Validator(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn validate(&mut self,
|
pub fn validate(&mut self,
|
||||||
needs_val_of: Option<&'a str>,
|
needs_val_of: Option<&'a str>,
|
||||||
|
@ -40,7 +41,9 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||||
};
|
};
|
||||||
if should_err {
|
if should_err {
|
||||||
return Err(Error::empty_value(o,
|
return Err(Error::empty_value(o,
|
||||||
&*self.0.create_current_usage(matcher, None),
|
&*usage::create_error_usage(self.0,
|
||||||
|
matcher,
|
||||||
|
None),
|
||||||
self.0.color()));
|
self.0.color()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +54,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||||
try!(self.validate_required(matcher));
|
try!(self.validate_required(matcher));
|
||||||
}
|
}
|
||||||
try!(self.validate_matched_args(matcher));
|
try!(self.validate_matched_args(matcher));
|
||||||
matcher.usage(self.0.create_usage(&[]));
|
matcher.usage(usage::create_help_usage(self.0));
|
||||||
|
|
||||||
if matcher.is_empty() && matcher.subcommand_name().is_none() &&
|
if matcher.is_empty() && matcher.subcommand_name().is_none() &&
|
||||||
self.0.is_set(AS::ArgRequiredElseHelp) {
|
self.0.is_set(AS::ArgRequiredElseHelp) {
|
||||||
|
@ -78,7 +81,9 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||||
if self.0.is_set(AS::StrictUtf8) && val.to_str().is_none() {
|
if self.0.is_set(AS::StrictUtf8) && val.to_str().is_none() {
|
||||||
debugln!("Validator::validate_values: invalid UTF-8 found in val {:?}",
|
debugln!("Validator::validate_values: invalid UTF-8 found in val {:?}",
|
||||||
val);
|
val);
|
||||||
return Err(Error::invalid_utf8(&*self.0.create_current_usage(matcher, None),
|
return Err(Error::invalid_utf8(&*usage::create_error_usage(self.0,
|
||||||
|
matcher,
|
||||||
|
None),
|
||||||
self.0.color()));
|
self.0.color()));
|
||||||
}
|
}
|
||||||
if let Some(p_vals) = arg.possible_vals() {
|
if let Some(p_vals) = arg.possible_vals() {
|
||||||
|
@ -88,7 +93,9 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||||
return Err(Error::invalid_value(val_str,
|
return Err(Error::invalid_value(val_str,
|
||||||
p_vals,
|
p_vals,
|
||||||
arg,
|
arg,
|
||||||
&*self.0.create_current_usage(matcher, None),
|
&*usage::create_error_usage(self.0,
|
||||||
|
matcher,
|
||||||
|
None),
|
||||||
self.0.color()));
|
self.0.color()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,7 +103,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||||
matcher.contains(&*arg.name()) {
|
matcher.contains(&*arg.name()) {
|
||||||
debugln!("Validator::validate_values: illegal empty val found");
|
debugln!("Validator::validate_values: illegal empty val found");
|
||||||
return Err(Error::empty_value(arg,
|
return Err(Error::empty_value(arg,
|
||||||
&*self.0.create_current_usage(matcher, None),
|
&*usage::create_error_usage(self.0, matcher, None),
|
||||||
self.0.color()));
|
self.0.color()));
|
||||||
}
|
}
|
||||||
if let Some(vtor) = arg.validator() {
|
if let Some(vtor) = arg.validator() {
|
||||||
|
@ -124,7 +131,8 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
|
fn validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
|
||||||
debugln!("Validator::validate_blacklist: blacklist={:?}", self.0.blacklist);
|
debugln!("Validator::validate_blacklist: blacklist={:?}",
|
||||||
|
self.0.blacklist);
|
||||||
macro_rules! build_err {
|
macro_rules! build_err {
|
||||||
($p:expr, $name:expr, $matcher:ident) => ({
|
($p:expr, $name:expr, $matcher:ident) => ({
|
||||||
debugln!("build_err!: name={}", $name);
|
debugln!("build_err!: name={}", $name);
|
||||||
|
@ -138,7 +146,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||||
);
|
);
|
||||||
debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, $name);
|
debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, $name);
|
||||||
$matcher.remove($name);
|
$matcher.remove($name);
|
||||||
let usg = $p.create_current_usage($matcher, None);
|
let usg = usage::create_error_usage($p, $matcher, None);
|
||||||
if let Some(f) = find_by_name!($p, $name, flags, iter) {
|
if let Some(f) = find_by_name!($p, $name, flags, iter) {
|
||||||
debugln!("build_err!: It was a flag...");
|
debugln!("build_err!: It was a flag...");
|
||||||
Error::argument_conflict(f, c_with, &*usg, self.0.color())
|
Error::argument_conflict(f, c_with, &*usg, self.0.color())
|
||||||
|
@ -160,7 +168,10 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||||
for name in &self.0.blacklist {
|
for name in &self.0.blacklist {
|
||||||
debugln!("Validator::validate_blacklist:iter: Checking blacklisted name: {}",
|
debugln!("Validator::validate_blacklist:iter: Checking blacklisted name: {}",
|
||||||
name);
|
name);
|
||||||
if self.0.groups.iter().any(|g| &g.name == name) {
|
if self.0
|
||||||
|
.groups
|
||||||
|
.iter()
|
||||||
|
.any(|g| &g.name == name) {
|
||||||
debugln!("Validator::validate_blacklist:iter: groups contains it...");
|
debugln!("Validator::validate_blacklist:iter: groups contains it...");
|
||||||
for n in self.0.arg_names_in_group(name) {
|
for n in self.0.arg_names_in_group(name) {
|
||||||
debugln!("Validator::validate_blacklist:iter:iter: Checking arg '{}' in group...",
|
debugln!("Validator::validate_blacklist:iter:iter: Checking arg '{}' in group...",
|
||||||
|
@ -198,7 +209,11 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||||
try!(self.validate_values(pos, ma, matcher));
|
try!(self.validate_values(pos, ma, matcher));
|
||||||
try!(self.validate_arg_requires(pos, ma, matcher));
|
try!(self.validate_arg_requires(pos, ma, matcher));
|
||||||
} else {
|
} else {
|
||||||
let grp = self.0.groups.iter().find(|g| &g.name == name).expect(INTERNAL_ERROR_MSG);
|
let grp = self.0
|
||||||
|
.groups
|
||||||
|
.iter()
|
||||||
|
.find(|g| &g.name == name)
|
||||||
|
.expect(INTERNAL_ERROR_MSG);
|
||||||
if let Some(ref g_reqs) = grp.requires {
|
if let Some(ref g_reqs) = grp.requires {
|
||||||
if g_reqs.iter().any(|&n| !matcher.contains(n)) {
|
if g_reqs.iter().any(|&n| !matcher.contains(n)) {
|
||||||
return self.missing_required_error(matcher, None);
|
return self.missing_required_error(matcher, None);
|
||||||
|
@ -220,7 +235,9 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||||
if ma.occurs > 1 && !a.is_set(ArgSettings::Multiple) {
|
if ma.occurs > 1 && !a.is_set(ArgSettings::Multiple) {
|
||||||
// Not the first time, and we don't allow multiples
|
// Not the first time, and we don't allow multiples
|
||||||
return Err(Error::unexpected_multiple_usage(a,
|
return Err(Error::unexpected_multiple_usage(a,
|
||||||
&*self.0.create_current_usage(matcher, None),
|
&*usage::create_error_usage(self.0,
|
||||||
|
matcher,
|
||||||
|
None),
|
||||||
self.0.color()));
|
self.0.color()));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -258,7 +275,9 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||||
} else {
|
} else {
|
||||||
"ere"
|
"ere"
|
||||||
},
|
},
|
||||||
&*self.0.create_current_usage(matcher, None),
|
&*usage::create_error_usage(self.0,
|
||||||
|
matcher,
|
||||||
|
None),
|
||||||
self.0.color()));
|
self.0.color()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -273,7 +292,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||||
.to_str()
|
.to_str()
|
||||||
.expect(INVALID_UTF8),
|
.expect(INVALID_UTF8),
|
||||||
a,
|
a,
|
||||||
&*self.0.create_current_usage(matcher, None),
|
&*usage::create_error_usage(self.0, matcher, None),
|
||||||
self.0.color()));
|
self.0.color()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -284,14 +303,14 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||||
return Err(Error::too_few_values(a,
|
return Err(Error::too_few_values(a,
|
||||||
num,
|
num,
|
||||||
ma.vals.len(),
|
ma.vals.len(),
|
||||||
&*self.0.create_current_usage(matcher, None),
|
&*usage::create_error_usage(self.0, matcher, None),
|
||||||
self.0.color()));
|
self.0.color()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Issue 665 (https://github.com/kbknapp/clap-rs/issues/665)
|
// Issue 665 (https://github.com/kbknapp/clap-rs/issues/665)
|
||||||
if a.takes_value() && !a.is_set(ArgSettings::EmptyValues) && ma.vals.is_empty() {
|
if a.takes_value() && !a.is_set(ArgSettings::EmptyValues) && ma.vals.is_empty() {
|
||||||
return Err(Error::empty_value(a,
|
return Err(Error::empty_value(a,
|
||||||
&*self.0.create_current_usage(matcher, None),
|
&*usage::create_error_usage(self.0, matcher, None),
|
||||||
self.0.color()));
|
self.0.color()));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -307,9 +326,10 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||||
debugln!("Validator::validate_arg_requires;");
|
debugln!("Validator::validate_arg_requires;");
|
||||||
if let Some(a_reqs) = a.requires() {
|
if let Some(a_reqs) = a.requires() {
|
||||||
for &(val, name) in a_reqs.iter().filter(|&&(val, _)| val.is_some()) {
|
for &(val, name) in a_reqs.iter().filter(|&&(val, _)| val.is_some()) {
|
||||||
if ma.vals
|
if ma.vals.iter().any(|v| {
|
||||||
.iter()
|
v == val.expect(INTERNAL_ERROR_MSG) &&
|
||||||
.any(|v| v == val.expect(INTERNAL_ERROR_MSG) && !matcher.contains(name)) {
|
!matcher.contains(name)
|
||||||
|
}) {
|
||||||
return self.missing_required_error(matcher, None);
|
return self.missing_required_error(matcher, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -318,7 +338,8 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_required(&self, matcher: &ArgMatcher) -> ClapResult<()> {
|
fn validate_required(&self, matcher: &ArgMatcher) -> ClapResult<()> {
|
||||||
debugln!("Validator::validate_required: required={:?};", self.0.required);
|
debugln!("Validator::validate_required: required={:?};",
|
||||||
|
self.0.required);
|
||||||
'outer: for name in &self.0.required {
|
'outer: for name in &self.0.required {
|
||||||
debugln!("Validator::validate_required:iter:{}:", name);
|
debugln!("Validator::validate_required:iter:{}:", name);
|
||||||
if matcher.contains(name) {
|
if matcher.contains(name) {
|
||||||
|
@ -360,7 +381,8 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||||
a.blacklist().map(|bl| {
|
a.blacklist().map(|bl| {
|
||||||
bl.iter().any(|conf| {
|
bl.iter().any(|conf| {
|
||||||
matcher.contains(conf) ||
|
matcher.contains(conf) ||
|
||||||
self.0.groups
|
self.0
|
||||||
|
.groups
|
||||||
.iter()
|
.iter()
|
||||||
.find(|g| &g.name == conf)
|
.find(|g| &g.name == conf)
|
||||||
.map_or(false, |g| g.args.iter().any(|arg| matcher.contains(arg)))
|
.map_or(false, |g| g.args.iter().any(|arg| matcher.contains(arg)))
|
||||||
|
@ -401,21 +423,26 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||||
use_stderr: true,
|
use_stderr: true,
|
||||||
when: self.0.color(),
|
when: self.0.color(),
|
||||||
};
|
};
|
||||||
let mut reqs = self.0.required.iter().map(|&r| &*r).collect::<Vec<_>>();
|
let mut reqs = self.0
|
||||||
|
.required
|
||||||
|
.iter()
|
||||||
|
.map(|&r| &*r)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
if let Some(r) = extra {
|
if let Some(r) = extra {
|
||||||
reqs.push(r);
|
reqs.push(r);
|
||||||
}
|
}
|
||||||
reqs.retain(|n| !matcher.contains(n));
|
reqs.retain(|n| !matcher.contains(n));
|
||||||
reqs.dedup();
|
reqs.dedup();
|
||||||
debugln!("Validator::missing_required_error: reqs={:#?}", reqs);
|
debugln!("Validator::missing_required_error: reqs={:#?}", reqs);
|
||||||
Err(Error::missing_required_argument(&*self.0.get_required_from(&reqs[..],
|
Err(Error::missing_required_argument(&*self.0
|
||||||
|
.get_required_from(&reqs[..],
|
||||||
Some(matcher),
|
Some(matcher),
|
||||||
extra)
|
extra)
|
||||||
.iter()
|
.iter()
|
||||||
.fold(String::new(), |acc, s| {
|
.fold(String::new(), |acc, s| {
|
||||||
acc + &format!("\n {}", c.error(s))[..]
|
acc + &format!("\n {}", c.error(s))[..]
|
||||||
}),
|
}),
|
||||||
&*self.0.create_current_usage(matcher, extra),
|
&*usage::create_error_usage(self.0, matcher, extra),
|
||||||
self.0.color()))
|
self.0.color()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue