depr(ArgMatches::usage): deprecates ArgMatches::usage in favor of App::generage_usage

This commit is contained in:
Kevin K 2018-07-24 15:27:36 -04:00
parent 8715ac268c
commit a9cbf3e5b9
No known key found for this signature in database
GPG key ID: 2E39D46AABC94DDD
7 changed files with 204 additions and 160 deletions

View file

@ -19,7 +19,7 @@ use yaml_rust::Yaml;
use build::{Arg, ArgGroup, ArgSettings};
use completions::{ComplGen, Shell};
use output::fmt::ColorWhen;
use output::Help;
use output::{Help, Usage};
use parse::errors::Result as ClapResult;
use parse::{ArgMatcher, ArgMatches, Parser};
@ -1149,6 +1149,19 @@ impl<'a, 'b> App<'a, 'b> {
self._write_version(w, true).map_err(From::from)
}
/// @TODO-v3-alpha @docs @p2: write docs
pub fn generate_usage(&mut self) -> String {
// If there are global arguments, or settings we need to propgate them down to subcommands
// before parsing incase we run into a subcommand
if !self.settings.is_set(AppSettings::Propagated) {
self._build(Propagation::NextLevel);
}
let mut parser = Parser::new(self);
parser._build();
Usage::new(&parser).create_usage_with_title(&[])
}
/// Starts the parsing process, upon a failed parse an error will be displayed to the user and
/// the process will exit with the appropriate error code. By default this method gets all user
/// provided arguments from [`env::args_os`] in order to allow for invalid UTF-8 code points,

View file

@ -2,10 +2,10 @@
use std::collections::{BTreeMap, VecDeque};
// Internal
use INTERNAL_ERROR_MSG;
use build::{Arg, ArgSettings};
use build::AppSettings as AS;
use parse::{Parser, ArgMatcher};
use build::{Arg, ArgSettings};
use parse::{ArgMatcher, Parser};
use INTERNAL_ERROR_MSG;
pub struct Usage<'a, 'b, 'c, 'z>(&'z Parser<'a, 'b, 'c>)
where
@ -59,8 +59,10 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
// Creates a usage string for display in help messages (i.e. not for errors)
pub fn create_help_usage(&self, incl_reqs: bool) -> String {
debugln!("Usage::create_help_usage; incl_reqs={:?}", incl_reqs);
let mut usage = String::with_capacity(75);
let name = self.0
let name = self
.0
.app
.usage
.as_ref()
@ -116,7 +118,7 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
let pos = positionals!(self.0.app)
.find(|p| p.is_set(ArgSettings::Last))
.expect(INTERNAL_ERROR_MSG);
debugln!("usage::create_help_usage: '{}' has .last(true)", pos.name);
debugln!("Usage::create_help_usage: '{}' has .last(true)", pos.name);
let req = pos.is_set(ArgSettings::Required);
if req && positionals!(self.0.app).any(|p| !p.is_set(ArgSettings::Required)) {
usage.push_str(" -- <");
@ -170,12 +172,14 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
let mut hs: Vec<&str> = self.0.required().map(|s| &**s).collect();
hs.extend_from_slice(used);
let r_string = self.get_required_usage_from(&hs, None, None, false)
let r_string = self
.get_required_usage_from(&hs, None, None, false)
.iter()
.fold(String::new(), |acc, s| acc + &format!(" {}", s)[..]);
usage.push_str(
&self.0
&self
.0
.app
.usage
.as_ref()
@ -220,7 +224,8 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
} else if count == 1 && incl_reqs {
let pos = positionals!(self.0.app)
.find(|pos| {
!pos.is_set(ArgSettings::Required) && !pos.is_set(ArgSettings::Hidden)
!pos.is_set(ArgSettings::Required)
&& !pos.is_set(ArgSettings::Hidden)
&& !pos.is_set(ArgSettings::Last)
})
.expect(INTERNAL_ERROR_MSG);
@ -233,7 +238,8 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
pos.name_no_brackets(),
pos.multiple_str()
));
} else if self.0.is_set(AS::DontCollapseArgsInUsage) && self.0.has_positionals()
} else if self.0.is_set(AS::DontCollapseArgsInUsage)
&& self.0.has_positionals()
&& incl_reqs
{
debugln!("usage::get_args_tag:iter: Don't collapse returning all");
@ -318,7 +324,7 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
incl_last: bool,
) -> VecDeque<String> {
debugln!(
"usage::get_required_usage_from: reqs={:?}, extra={:?}",
"Usage::get_required_usage_from: reqs={:?}, extra={:?}",
reqs,
extra
);
@ -326,15 +332,19 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
desc_reqs.extend(extra);
let mut new_reqs: Vec<&str> = vec![];
macro_rules! get_requires {
(@group $a: ident, $v:ident, $p:ident) => {{
(@group $a:ident, $v:ident, $p:ident) => {{
if let Some(rl) = groups!(self.0.app)
.filter(|g| g.requires.is_some())
.find(|g| &g.name == $a)
.map(|g| g.requires.as_ref().unwrap()) {
.filter(|g| g.requires.is_some())
.find(|g| &g.name == $a)
.map(|g| g.requires.as_ref().unwrap())
{
for r in rl {
if !$p.contains(&r) {
debugln!("usage::get_required_usage_from:iter:{}: adding group req={:?}",
$a, r);
debugln!(
"Usage::get_required_usage_from:iter:{}: adding group req={:?}",
$a,
r
);
$v.push(r);
}
}
@ -342,13 +352,17 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
}};
($a:ident, $what:ident, $how:ident, $v:ident, $p:ident) => {{
if let Some(rl) = $what!(self.0.app)
.filter(|a| a.requires.is_some())
.find(|arg| &arg.name == $a)
.map(|a| a.requires.as_ref().unwrap()) {
.filter(|a| a.requires.is_some())
.find(|arg| &arg.name == $a)
.map(|a| a.requires.as_ref().unwrap())
{
for &(_, r) in rl.iter() {
if !$p.contains(&r) {
debugln!("usage::get_required_usage_from:iter:{}: adding arg req={:?}",
$a, r);
debugln!(
"usage::get_required_usage_from:iter:{}: adding arg req={:?}",
$a,
r
);
$v.push(r);
}
}
@ -388,7 +402,7 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
new_reqs.clear();
new_reqs.extend_from_slice(&*tmp);
debugln!(
"usage::get_required_usage_from: after iter desc_reqs={:?}",
"Usage::get_required_usage_from: after iter desc_reqs={:?}",
desc_reqs
);
}
@ -397,7 +411,7 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
desc_reqs.sort();
desc_reqs.dedup();
debugln!(
"usage::get_required_usage_from: final desc_reqs={:?}",
"Usage::get_required_usage_from: final desc_reqs={:?}",
desc_reqs
);
let mut ret_val = VecDeque::new();
@ -427,10 +441,11 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
.collect::<BTreeMap<u64, &Arg>>() // sort by index
};
debugln!(
"usage::get_required_usage_from: args_in_groups={:?}",
"Usage::get_required_usage_from: args_in_groups={:?}",
args_in_groups
);
for &p in pmap.values() {
debugln!("Usage::get_required_usage_from:iter:{}", p.to_string());
let s = p.to_string();
if args_in_groups.is_empty() || !args_in_groups.contains(&&*s) {
ret_val.push_back(s);
@ -443,7 +458,7 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
.filter(|name| !args_in_groups.contains(name))
.filter(|name| !(matcher.is_some() && matcher.as_ref().unwrap().contains(name)))
{
debugln!("usage::get_required_usage_from:iter:{}:", a);
debugln!("Usage::get_required_usage_from:iter:{}:", a);
let arg = find!(self.0.app, a)
.map(|f| f.to_string())
.expect(INTERNAL_ERROR_MSG);
@ -464,6 +479,7 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
ret_val.push_back(g);
}
debugln!("Usage::get_required_usage_from: ret_val={:?}", ret_val);
ret_val
}
}

View file

@ -1,6 +1,6 @@
// Std
use std::ffi::OsStr;
use std::collections::HashMap;
use std::ffi::OsStr;
use std::mem;
// Third Party
@ -88,8 +88,6 @@ impl<'a> ArgMatcher<'a> {
pub fn is_empty(&self) -> bool { self.0.args.is_empty() }
pub fn usage(&mut self, usage: String) { self.0.usage = Some(usage); }
pub fn arg_names(&'a self) -> indexmap::map::Keys<&'a str, MatchedArg> { self.0.args.keys() }
pub fn entry(&mut self, arg: &'a str) -> indexmap::map::Entry<&'a str, MatchedArg> {
@ -130,14 +128,14 @@ impl<'a> ArgMatcher<'a> {
}
pub fn add_index_to(&mut self, arg: &'a str, idx: usize) {
let ma = self.entry(arg).or_insert(MatchedArg {
occurs: 0,
indices: Vec::with_capacity(1),
vals: Vec::new(),
});
ma.indices.push(idx);
let ma = self.entry(arg).or_insert(MatchedArg {
occurs: 0,
indices: Vec::with_capacity(1),
vals: Vec::new(),
});
ma.indices.push(idx);
}
pub fn needs_more_vals<'b>(&self, o: &Arg) -> bool {
debugln!("ArgMatcher::needs_more_vals: o={}", o.name);
if let Some(ma) = self.get(o.name) {

View file

@ -8,8 +8,8 @@ use std::slice::Iter;
use indexmap::IndexMap;
// Internal
use INVALID_UTF8;
use parse::{MatchedArg, SubCommand};
use INVALID_UTF8;
/// Used to get information about the arguments that where supplied to the program at runtime by
/// the user. New instances of this struct are obtained by using the [`App::get_matches`] family of
@ -64,8 +64,6 @@ pub struct ArgMatches<'a> {
pub args: IndexMap<&'a str, MatchedArg>,
#[doc(hidden)]
pub subcommand: Option<Box<SubCommand<'a>>>,
#[doc(hidden)]
pub usage: Option<String>,
}
impl<'a> Default for ArgMatches<'a> {
@ -73,7 +71,6 @@ impl<'a> Default for ArgMatches<'a> {
ArgMatches {
args: IndexMap::new(),
subcommand: None,
usage: None,
}
}
}
@ -746,21 +743,13 @@ impl<'a> ArgMatches<'a> {
.map_or(("", None), |sc| (&sc.name[..], Some(&sc.matches)))
}
/// Returns a string slice of the usage statement for the [`App`] or [`SubCommand`]
///
/// # Examples
///
/// ```no_run
/// # use clap::{App, Arg, SubCommand};
/// let app_m = App::new("myprog")
/// .subcommand(SubCommand::with_name("test"))
/// .get_matches();
///
/// println!("{}", app_m.usage());
/// ```
/// [`Subcommand`]: ./struct.SubCommand.html
/// [`App`]: ./struct.App.html
pub fn usage(&self) -> &str { self.usage.as_ref().map_or("", |u| &u[..]) }
// @TODO @v3-beta: remove
/// **Deprecated**
#[deprecated(
since = "2.32.0",
note = "Use App::usage instead. Will be removed in v3-beta"
)]
pub fn usage(&self) -> &str { panic!("Use App::usage instead. Will be removed in v3-beta") }
}
// The following were taken and adapated from vec_map source
@ -895,7 +884,8 @@ impl<'a> Default for OsValues<'a> {
/// [`ArgMatches::indices_of`]: ./struct.ArgMatches.html#method.indices_of
#[derive(Clone)]
#[allow(missing_debug_implementations)]
pub struct Indices<'a> { // would rather use '_, but: https://github.com/rust-lang/rust/issues/48469
pub struct Indices<'a> {
// would rather use '_, but: https://github.com/rust-lang/rust/issues/48469
iter: Map<Iter<'a, usize>, fn(&'a usize) -> usize>,
}

View file

@ -1,33 +1,43 @@
// Std
#[cfg(
all(
feature = "debug",
any(target_os = "windows", target_arch = "wasm32")
)
)]
use osstringext::OsStrExt3;
use std::cell::Cell;
use std::ffi::{OsStr, OsString};
use std::io::{self, BufWriter, Write};
#[cfg(all(feature = "debug", not(any(target_os = "windows", target_arch = "wasm32"))))]
use std::os::unix::ffi::OsStrExt;
#[cfg(all(feature = "debug", any(target_os = "windows", target_arch = "wasm32")))]
use osstringext::OsStrExt3;
use std::slice::Iter;
use std::iter::Peekable;
use std::mem;
use std::cell::Cell;
#[cfg(
all(
feature = "debug",
not(any(target_os = "windows", target_arch = "wasm32"))
)
)]
use std::os::unix::ffi::OsStrExt;
use std::slice::Iter;
// Third party facade
use util::VecMap;
// Internal
use INTERNAL_ERROR_MSG;
use INVALID_UTF8;
use build::{App, Arg, ArgSettings};
use build::app::Propagation;
use build::AppSettings as AS;
use parse::{ArgMatcher, SubCommand};
use build::{App, Arg, ArgSettings};
use output::Help;
use parse::errors::ErrorKind;
use parse::errors::Error as ClapError;
use parse::errors::Result as ClapResult;
use parse::Validator;
use util::OsStrExt2;
use parse::features::suggestions;
use output::Usage;
use parse::errors::Error as ClapError;
use parse::errors::ErrorKind;
use parse::errors::Result as ClapResult;
use parse::features::suggestions;
use parse::Validator;
use parse::{ArgMatcher, SubCommand};
use util::OsStrExt2;
use INVALID_UTF8;
use INTERNAL_ERROR_MSG;
#[derive(Debug, PartialEq, Copy, Clone)]
#[doc(hidden)]
@ -92,7 +102,8 @@ where
'b: 'c,
{
pub fn new(app: &'c mut App<'a, 'b>) -> Self {
let reqs = app.args
let reqs = app
.args
.iter()
.filter(|a| a.settings.is_set(ArgSettings::Required))
.map(|a| a.name)
@ -112,7 +123,6 @@ where
}
}
#[cfg_attr(feature = "lints", allow(block_in_if_condition_stmt))]
fn _verify_positionals(&mut self) -> bool {
debugln!("Parser::_verify_positionals;");
@ -123,14 +133,10 @@ where
// positional arguments to verify there are no gaps (i.e. supplying an index of 1 and 3
// but no 2)
#[cfg(feature = "vec_map")]
fn _highest_idx(map: &VecMap<&str>) -> usize {
map.keys().last().unwrap_or(0)
}
fn _highest_idx(map: &VecMap<&str>) -> usize { map.keys().last().unwrap_or(0) }
#[cfg(not(feature = "vec_map"))]
fn _highest_idx(map: &VecMap<&str>) -> usize {
*map.keys().last().unwrap_or(&0)
}
fn _highest_idx(map: &VecMap<&str>) -> usize { *map.keys().last().unwrap_or(&0) }
let highest_idx = _highest_idx(&self.positionals);
@ -192,7 +198,8 @@ where
}
});
let ok = count <= 1
|| (last.is_set(ArgSettings::Last) && last.is_set(ArgSettings::MultipleValues)
|| (last.is_set(ArgSettings::Last)
&& last.is_set(ArgSettings::MultipleValues)
&& second_to_last.is_set(ArgSettings::MultipleValues)
&& count == 2);
assert!(
@ -207,7 +214,8 @@ where
// index are also required.
let mut found = false;
let mut foundx2 = false;
for p in self.positionals
for p in self
.positionals
.values()
.rev()
.map(|p_name| find!(self.app, p_name).expect(INTERNAL_ERROR_MSG))
@ -242,7 +250,8 @@ where
// Check that if a required positional argument is found, all positions with a lower
// index are also required
let mut found = false;
for p in self.positionals
for p in self
.positionals
.values()
.rev()
.map(|p_name| find!(self.app, p_name).expect(INTERNAL_ERROR_MSG))
@ -268,10 +277,12 @@ where
}
}
assert!(
positionals!(self.app).fold(0, |acc, p| if p.is_set(ArgSettings::Last) {
acc + 1
} else {
acc
positionals!(self.app).fold(0, |acc, p| {
if p.is_set(ArgSettings::Last) {
acc + 1
} else {
acc
}
}) < 2,
"Only one positional argument may have last(true) set. Found two."
);
@ -289,7 +300,7 @@ where
}
// Does all the initializing and prepares the parser
fn _build(&mut self) {
pub(crate) fn _build(&mut self) {
debugln!("Parser::_build;");
for a in &mut self.app.args {
@ -354,7 +365,10 @@ where
'b: 'c,
{
// The actual parsing function
#[cfg_attr(feature = "lints", allow(while_let_on_iterator, collapsible_if))]
#[cfg_attr(
feature = "lints",
allow(while_let_on_iterator, collapsible_if)
)]
pub fn get_matches_with<I, T>(
&mut self,
matcher: &mut ArgMatcher<'a>,
@ -384,7 +398,9 @@ where
self.unset(AS::ValidNegNumFound);
// Is this a new argument, or values from a previous option?
let starts_new_arg = self.is_new_arg(&arg_os, needs_val_of);
if !self.is_set(AS::TrailingValues) && arg_os.starts_with(b"--") && arg_os.len() == 2
if !self.is_set(AS::TrailingValues)
&& arg_os.starts_with(b"--")
&& arg_os.len() == 2
&& starts_new_arg
{
debugln!("Parser::get_matches_with: setting TrailingVals=true");
@ -473,7 +489,8 @@ where
}
if !(self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound))
&& !self.is_set(AS::InferSubcommands) && !self.is_set(AS::AllowExternalSubcommands)
&& !self.is_set(AS::InferSubcommands)
&& !self.is_set(AS::AllowExternalSubcommands)
{
if let Some(cdate) =
suggestions::did_you_mean(&*arg_os.to_string_lossy(), sc_names!(self.app))
@ -555,7 +572,8 @@ where
let _ = self.add_val_to_arg(p, &arg_os, matcher)?;
matcher.inc_occurrence_of(p.name);
let _ = self.groups_for_arg(p.name)
let _ = self
.groups_for_arg(p.name)
.and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));
self.app.settings.set(AS::ValidArgFound);
@ -673,10 +691,10 @@ where
fn possible_subcommand(&self, arg_os: &OsStr) -> (bool, Option<&str>) {
debugln!("Parser::possible_subcommand: arg={:?}", arg_os);
fn starts(h: &str, n: &OsStr) -> bool {
#[cfg(not(target_os = "windows"))]
use std::os::unix::ffi::OsStrExt;
#[cfg(target_os = "windows")]
use osstringext::OsStrExt3;
#[cfg(not(target_os = "windows"))]
use std::os::unix::ffi::OsStrExt;
let n_bytes = n.as_bytes();
let h_bytes = OsStr::new(h).as_bytes();
@ -934,9 +952,9 @@ where
// specified by the user is sent through. If HiddenShortHelp is not included,
// then items specified with hidden_short_help will also be hidden.
let should_long = |v: &Arg| {
v.long_help.is_some() ||
v.is_set(ArgSettings::HiddenLongHelp) ||
v.is_set(ArgSettings::HiddenShortHelp)
v.long_help.is_some()
|| v.is_set(ArgSettings::HiddenLongHelp)
|| v.is_set(ArgSettings::HiddenShortHelp)
};
self.app.long_about.is_some()
@ -944,33 +962,33 @@ where
|| subcommands!(self.app).any(|s| s.long_about.is_some())
}
// fn _help(&self, mut use_long: bool) -> ClapError {
// debugln!("Parser::_help: use_long={:?}", use_long && self.use_long_help());
// use_long = use_long && self.use_long_help();
// let mut buf = vec![];
// match Help::write_parser_help(&mut buf, self, use_long) {
// Err(e) => e,
// _ => ClapError {
// message: String::from_utf8(buf).unwrap_or_default(),
// kind: ErrorKind::HelpDisplayed,
// info: None,
// },
// }
// }
//
// fn _version(&self, use_long: bool) -> ClapError {
// debugln!("Parser::_version: ");
// let out = io::stdout();
// let mut buf_w = BufWriter::new(out.lock());
// match self.print_version(&mut buf_w, use_long) {
// Err(e) => e,
// _ => ClapError {
// message: String::new(),
// kind: ErrorKind::VersionDisplayed,
// info: None,
// },
// }
// }
// fn _help(&self, mut use_long: bool) -> ClapError {
// debugln!("Parser::_help: use_long={:?}", use_long && self.use_long_help());
// use_long = use_long && self.use_long_help();
// let mut buf = vec![];
// match Help::write_parser_help(&mut buf, self, use_long) {
// Err(e) => e,
// _ => ClapError {
// message: String::from_utf8(buf).unwrap_or_default(),
// kind: ErrorKind::HelpDisplayed,
// info: None,
// },
// }
// }
//
// fn _version(&self, use_long: bool) -> ClapError {
// debugln!("Parser::_version: ");
// let out = io::stdout();
// let mut buf_w = BufWriter::new(out.lock());
// match self.print_version(&mut buf_w, use_long) {
// Err(e) => e,
// _ => ClapError {
// message: String::new(),
// kind: ErrorKind::VersionDisplayed,
// info: None,
// },
// }
// }
fn parse_long_arg(
&mut self,
@ -1365,16 +1383,26 @@ where
(@default $_self:ident, $a:ident, $m:ident) => {
if let Some(ref val) = $a.default_val {
debugln!("Parser::add_defaults:iter:{}: has default vals", $a.name);
if $m.get($a.name).map(|ma| ma.vals.len())
.map(|len| len == 0).unwrap_or(false) {
debugln!("Parser::add_defaults:iter:{}: has no user defined vals", $a.name);
if $m
.get($a.name)
.map(|ma| ma.vals.len())
.map(|len| len == 0)
.unwrap_or(false)
{
debugln!(
"Parser::add_defaults:iter:{}: has no user defined vals",
$a.name
);
$_self.add_val_to_arg($a, OsStr::new(val), $m)?;
if $_self.cache.map_or(true, |name| name != $a.name) {
$_self.cache = Some($a.name);
}
} else if $m.get($a.name).is_some() {
debugln!("Parser::add_defaults:iter:{}: has user defined vals", $a.name);
debugln!(
"Parser::add_defaults:iter:{}: has user defined vals",
$a.name
);
} else {
debugln!("Parser::add_defaults:iter:{}: wasn't used", $a.name);
@ -1385,7 +1413,10 @@ where
}
}
} else {
debugln!("Parser::add_defaults:iter:{}: doesn't have default vals", $a.name);
debugln!(
"Parser::add_defaults:iter:{}: doesn't have default vals",
$a.name
);
}
};
($_self:ident, $a:ident, $m:ident) => {
@ -1510,7 +1541,10 @@ where
}
fn help_err(&self, mut use_long: bool) -> ClapError {
debugln!("Parser::help_err: use_long={:?}", use_long && self.use_long_help());
debugln!(
"Parser::help_err: use_long={:?}",
use_long && self.use_long_help()
);
use_long = use_long && self.use_long_help();
let mut buf = vec![];
match Help::write_parser_help(&mut buf, self, use_long) {

View file

@ -3,15 +3,15 @@
use std::ascii::AsciiExt;
// Internal
use INTERNAL_ERROR_MSG;
use INVALID_UTF8;
use build::{Arg, ArgSettings};
use build::app::AppSettings as AS;
use parse::{ArgMatcher, MatchedArg, ParseResult, Parser};
use parse::errors::{Error, ErrorKind};
use parse::errors::Result as ClapResult;
use build::{Arg, ArgSettings};
use output::fmt::{Colorizer, ColorizerOption};
use output::Usage;
use parse::errors::Result as ClapResult;
use parse::errors::{Error, ErrorKind};
use parse::{ArgMatcher, MatchedArg, ParseResult, Parser};
use INVALID_UTF8;
use INTERNAL_ERROR_MSG;
pub struct Validator<'a, 'b, 'c, 'z>(&'z mut Parser<'a, 'b, 'c>)
where
@ -51,7 +51,8 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
}
}
if matcher.is_empty() && matcher.subcommand_name().is_none()
if matcher.is_empty()
&& matcher.subcommand_name().is_none()
&& self.0.is_set(AS::ArgRequiredElseHelp)
{
let mut out = vec![];
@ -67,7 +68,6 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
self.validate_required(matcher)?;
}
self.validate_matched_args(matcher)?;
matcher.usage(Usage::new(self.0).create_usage_with_title(&[]));
Ok(())
}
@ -108,7 +108,8 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
));
}
}
if !arg.is_set(ArgSettings::AllowEmptyValues) && val.is_empty()
if !arg.is_set(ArgSettings::AllowEmptyValues)
&& val.is_empty()
&& matcher.contains(&*arg.name)
{
debugln!("Validator::validate_arg_values: illegal empty val found");
@ -463,7 +464,7 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
ru.iter().$how(|n| {
$m.contains(n) || {
if let Some(grp) = find!($_self.app, n, groups) {
grp.args.iter().any(|arg| $m.contains(arg))
grp.args.iter().any(|arg| $m.contains(arg))
} else {
false
}

View file

@ -186,44 +186,36 @@ fn positional_hyphen_does_not_panic() {
#[test]
fn single_positional_usage_string() {
let m = App::new("test")
.arg_from_usage("[FILE] 'some file'")
.get_matches_from(vec!["test"]);
assert_eq!(m.usage(), "USAGE:\n test [FILE]");
let mut app = App::new("test").arg_from_usage("[FILE] 'some file'");
assert_eq!(app.generate_usage(), "USAGE:\n test [FILE]");
}
#[test]
fn single_positional_multiple_usage_string() {
let m = App::new("test")
.arg_from_usage("[FILE]... 'some file'")
.get_matches_from(vec!["test"]);
assert_eq!(m.usage(), "USAGE:\n test [FILE]...");
let mut app = App::new("test").arg_from_usage("[FILE]... 'some file'");
assert_eq!(app.generate_usage(), "USAGE:\n test [FILE]...");
}
#[test]
fn multiple_positional_usage_string() {
let m = App::new("test")
let mut app = App::new("test")
.arg_from_usage("[FILE] 'some file'")
.arg_from_usage("[FILES]... 'some file'")
.get_matches_from(vec!["test"]);
assert_eq!(m.usage(), "USAGE:\n test [ARGS]");
.arg_from_usage("[FILES]... 'some file'");
assert_eq!(app.generate_usage(), "USAGE:\n test [ARGS]");
}
#[test]
fn multiple_positional_one_required_usage_string() {
let m = App::new("test")
let mut app = App::new("test")
.arg_from_usage("<FILE> 'some file'")
.arg_from_usage("[FILES]... 'some file'")
.get_matches_from(vec!["test", "file"]);
assert_eq!(m.usage(), "USAGE:\n test <FILE> [FILES]...");
.arg_from_usage("[FILES]... 'some file'");
assert_eq!(app.generate_usage(), "USAGE:\n test <FILE> [FILES]...");
}
#[test]
fn single_positional_required_usage_string() {
let m = App::new("test")
.arg_from_usage("<FILE> 'some file'")
.get_matches_from(vec!["test", "file"]);
assert_eq!(m.usage(), "USAGE:\n test <FILE>");
let mut app = App::new("test").arg_from_usage("<FILE> 'some file'");
assert_eq!(app.generate_usage(), "USAGE:\n test <FILE>");
}
#[test]