Merge pull request #3378 from blyxxyz/size

Optimize code size further
This commit is contained in:
Ed Page 2022-02-01 11:13:18 -06:00 committed by GitHub
commit ba582e77b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 204 additions and 283 deletions

View file

@ -116,27 +116,33 @@ impl<'help> App<'help> {
/// # ;
/// ```
pub fn new<S: Into<String>>(name: S) -> Self {
let name = name.into();
App {
id: Id::from(&*name),
name,
..Default::default()
/// The actual implementation of `new`, non-generic to save code size.
///
/// If we don't do this rustc will unnecessarily generate multiple versions
/// of this code.
fn new_inner<'help>(name: String) -> App<'help> {
App {
id: Id::from(&*name),
name,
..Default::default()
}
.arg(
Arg::new("help")
.long("help")
.help("Print help information")
.global(true)
.generated(),
)
.arg(
Arg::new("version")
.long("version")
.help("Print version information")
.global(true)
.generated(),
)
}
.arg(
Arg::new("help")
.long("help")
.help("Print help information")
.global(true)
.generated(),
)
.arg(
Arg::new("version")
.long("version")
.help("Print version information")
.global(true)
.generated(),
)
new_inner(name.into())
}
/// Adds an [argument] to the list of valid possibilities.
@ -2214,7 +2220,7 @@ impl<'help> App<'help> {
}
/// Should we color the output?
#[inline]
#[inline(never)]
pub fn get_color(&self) -> ColorChoice {
debug!("App::color: Color setting...");
@ -3015,7 +3021,7 @@ impl<'help> App<'help> {
debug!("No");
let bin_name = format!(
"{}{}{}",
self.bin_name.as_ref().unwrap_or(&self.name.clone()),
self.bin_name.as_ref().unwrap_or(&self.name),
if self.bin_name.is_some() { " " } else { "" },
&*sc.name
);
@ -3043,11 +3049,9 @@ impl<'help> App<'help> {
debug!("App::_render_version");
let ver = if use_long {
self.long_version
.unwrap_or_else(|| self.version.unwrap_or(""))
self.long_version.or(self.version).unwrap_or("")
} else {
self.version
.unwrap_or_else(|| self.long_version.unwrap_or(""))
self.version.or(self.long_version).unwrap_or("")
};
if let Some(bn) = self.bin_name.as_ref() {
if bn.contains(' ') {

View file

@ -17,7 +17,7 @@ use std::{
error::Error,
ffi::OsStr,
fmt::{self, Display, Formatter},
iter, str,
str,
sync::{Arc, Mutex},
};
#[cfg(feature = "env")]
@ -4335,7 +4335,7 @@ impl<'help> Arg<'help> {
/// [`Arg::exclusive(true)`]: Arg::exclusive()
#[must_use]
pub fn conflicts_with_all(mut self, names: &[&str]) -> Self {
self.blacklist.extend(names.iter().map(Id::from));
self.blacklist.extend(names.iter().copied().map(Id::from));
self
}
@ -4943,12 +4943,12 @@ impl<'help> Arg<'help> {
// Used for positionals when printing
pub(crate) fn name_no_brackets(&self) -> Cow<str> {
debug!("Arg::name_no_brackets:{}", self.name);
let mut delim = String::new();
delim.push(if self.is_set(ArgSettings::RequireDelimiter) {
let delim = if self.is_set(ArgSettings::RequireDelimiter) {
self.val_delim.expect(INTERNAL_ERROR_MSG)
} else {
' '
});
}
.to_string();
if !self.val_names.is_empty() {
debug!("Arg::name_no_brackets: val_names={:#?}", self.val_names);
@ -5029,13 +5029,13 @@ impl<'help> Display for Arg<'help> {
} else {
" "
};
write!(f, "{}", sep)?;
f.write_str(sep)?;
}
if self.is_set(ArgSettings::TakesValue) || self.is_positional() {
display_arg_val(self, |s, _| write!(f, "{}", s))?;
display_arg_val(self, |s, _| f.write_str(s))?;
}
if need_closing_bracket {
write!(f, "]")?;
f.write_str("]")?;
}
Ok(())
@ -5123,7 +5123,8 @@ where
arg.val_delim.expect(INTERNAL_ERROR_MSG)
} else {
' '
};
}
.to_string();
if !arg.val_names.is_empty() {
// If have val_name.
match (arg.val_names.len(), arg.num_vals) {
@ -5131,11 +5132,10 @@ where
// If single value name with multiple num_of_vals, display all
// the values with the single value name.
let arg_name = format!("<{}>", arg.val_names.get(0).unwrap());
let mut it = iter::repeat(arg_name).take(num_vals).peekable();
while let Some(arg_name) = it.next() {
for n in 1..=num_vals {
write(&arg_name, true)?;
if it.peek().is_some() {
write(&delim.to_string(), false)?;
if n != num_vals {
write(&delim, false)?;
}
}
}
@ -5145,7 +5145,7 @@ where
while let Some(val) = it.next() {
write(&format!("<{}>", val), true)?;
if it.peek().is_some() {
write(&delim.to_string(), false)?;
write(&delim, false)?;
}
}
if (num_val_names == 1 && mult_val) || (arg.is_positional() && mult_occ) {
@ -5156,11 +5156,10 @@ where
} else if let Some(num_vals) = arg.num_vals {
// If number_of_values is specified, display the value multiple times.
let arg_name = format!("<{}>", arg.name);
let mut it = iter::repeat(&arg_name).take(num_vals).peekable();
while let Some(arg_name) = it.next() {
write(arg_name, true)?;
if it.peek().is_some() {
write(&delim.to_string(), false)?;
for n in 1..=num_vals {
write(&arg_name, true)?;
if n != num_vals {
write(&delim, false)?;
}
}
} else if arg.is_positional() {
@ -5190,12 +5189,12 @@ mod test {
let mut f = Arg::new("flg").multiple_occurrences(true);
f.long = Some("flag");
assert_eq!(&*format!("{}", f), "--flag");
assert_eq!(f.to_string(), "--flag");
let mut f2 = Arg::new("flg");
f2.short = Some('f');
assert_eq!(&*format!("{}", f2), "-f");
assert_eq!(f2.to_string(), "-f");
}
#[test]
@ -5204,7 +5203,7 @@ mod test {
f.long = Some("flag");
f.aliases = vec![("als", true)];
assert_eq!(&*format!("{}", f), "--flag")
assert_eq!(f.to_string(), "--flag")
}
#[test]
@ -5217,7 +5216,7 @@ mod test {
("f3", true),
("f4", true),
];
assert_eq!(&*format!("{}", f), "-f");
assert_eq!(f.to_string(), "-f");
}
#[test]
@ -5226,7 +5225,7 @@ mod test {
f.short = Some('a');
f.short_aliases = vec![('b', true)];
assert_eq!(&*format!("{}", f), "-a")
assert_eq!(f.to_string(), "-a")
}
#[test]
@ -5234,7 +5233,7 @@ mod test {
let mut f = Arg::new("flg");
f.short = Some('a');
f.short_aliases = vec![('b', false), ('c', true), ('d', true), ('e', true)];
assert_eq!(&*format!("{}", f), "-a");
assert_eq!(f.to_string(), "-a");
}
// Options
@ -5246,7 +5245,7 @@ mod test {
.takes_value(true)
.multiple_occurrences(true);
assert_eq!(&*format!("{}", o), "--option <opt>");
assert_eq!(o.to_string(), "--option <opt>");
}
#[test]
@ -5256,14 +5255,14 @@ mod test {
.takes_value(true)
.multiple_values(true);
assert_eq!(&*format!("{}", o), "--option <opt>...");
assert_eq!(o.to_string(), "--option <opt>...");
}
#[test]
fn option_display2() {
let o2 = Arg::new("opt").short('o').value_names(&["file", "name"]);
assert_eq!(&*format!("{}", o2), "-o <file> <name>");
assert_eq!(o2.to_string(), "-o <file> <name>");
}
#[test]
@ -5274,7 +5273,7 @@ mod test {
.multiple_values(true)
.value_names(&["file", "name"]);
assert_eq!(&*format!("{}", o2), "-o <file> <name>");
assert_eq!(o2.to_string(), "-o <file> <name>");
}
#[test]
@ -5284,7 +5283,7 @@ mod test {
.long("option")
.visible_alias("als");
assert_eq!(&*format!("{}", o), "--option <opt>");
assert_eq!(o.to_string(), "--option <opt>");
}
#[test]
@ -5295,7 +5294,7 @@ mod test {
.visible_aliases(&["als2", "als3", "als4"])
.alias("als_not_visible");
assert_eq!(&*format!("{}", o), "--option <opt>");
assert_eq!(o.to_string(), "--option <opt>");
}
#[test]
@ -5305,7 +5304,7 @@ mod test {
.short('a')
.visible_short_alias('b');
assert_eq!(&*format!("{}", o), "-a <opt>");
assert_eq!(o.to_string(), "-a <opt>");
}
#[test]
@ -5316,7 +5315,7 @@ mod test {
.visible_short_aliases(&['b', 'c', 'd'])
.short_alias('e');
assert_eq!(&*format!("{}", o), "-a <opt>");
assert_eq!(o.to_string(), "-a <opt>");
}
// Positionals
@ -5328,7 +5327,7 @@ mod test {
.takes_value(true)
.multiple_values(true);
assert_eq!(&*format!("{}", p), "<pos>...");
assert_eq!(p.to_string(), "<pos>...");
}
#[test]
@ -5338,21 +5337,21 @@ mod test {
.takes_value(true)
.multiple_occurrences(true);
assert_eq!(&*format!("{}", p), "<pos>...");
assert_eq!(p.to_string(), "<pos>...");
}
#[test]
fn positional_display_required() {
let p2 = Arg::new("pos").index(1).required(true);
assert_eq!(&*format!("{}", p2), "<pos>");
assert_eq!(p2.to_string(), "<pos>");
}
#[test]
fn positional_display_val_names() {
let p2 = Arg::new("pos").index(1).value_names(&["file1", "file2"]);
assert_eq!(&*format!("{}", p2), "<file1> <file2>");
assert_eq!(p2.to_string(), "<file1> <file2>");
}
#[test]
@ -5362,6 +5361,6 @@ mod test {
.required(true)
.value_names(&["file1", "file2"]);
assert_eq!(&*format!("{}", p2), "<file1> <file2>");
assert_eq!(p2.to_string(), "<file1> <file2>");
}
}

View file

@ -124,7 +124,7 @@ impl<'help> ArgGroup<'help> {
#[must_use]
pub fn name<S: Into<&'help str>>(mut self, n: S) -> Self {
self.name = n.into();
self.id = Id::from(&self.name);
self.id = Id::from(self.name);
self
}

View file

@ -2,6 +2,7 @@
use std::{
borrow::Cow,
cmp,
fmt::Write as _,
io::{self, Write},
usize,
};
@ -139,6 +140,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
write_method!(self, msg, none)
}
#[inline(never)]
fn spaces(&mut self, n: usize) -> io::Result<()> {
// A string with 64 consecutive spaces.
const SHORT_SPACE: &str =
@ -157,7 +159,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
let mut longest = 2;
let mut arg_v = Vec::with_capacity(10);
for arg in args
for &arg in args
.iter()
.filter(|arg| should_show_arg(self.use_long, *arg))
{
@ -184,7 +186,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
let mut ord_v = Vec::new();
// Determine the longest
for arg in args.iter().filter(|arg| {
for &arg in args.iter().filter(|arg| {
// If it's NextLineHelp we don't care to compute how long it is because it may be
// NextLineHelp on purpose simply *because* it's so long and would throw off all other
// args alignment
@ -256,7 +258,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
self.none(TAB)?;
if let Some(s) = arg.short {
self.good(&format!("-{}", s))
self.good(format!("-{}", s))
} else if !arg.is_positional() {
self.none(TAB)
} else {
@ -271,7 +273,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
if arg.short.is_some() {
self.none(", ")?;
}
self.good(&format!("--{}", long))?;
self.good(format!("--{}", long))?;
}
Ok(())
}
@ -408,7 +410,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
// Is help on next line, if so then indent
if next_line_help {
self.none(&format!("\n{}{}{}", TAB, TAB, TAB))?;
self.none(format!("\n{}{}{}", TAB, TAB, TAB))?;
}
debug!("Help::help: Too long...");
@ -429,7 +431,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
for part in help.lines().skip(1) {
self.none("\n")?;
if next_line_help {
self.none(&format!("{}{}{}", TAB, TAB, TAB))?;
self.none(format!("{}{}{}", TAB, TAB, TAB))?;
} else if is_not_positional {
self.spaces(longest + 12)?;
} else {
@ -454,9 +456,9 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
self.align_to_about(arg, next_line_help, longest)?;
let about = if self.use_long {
arg.long_help.unwrap_or_else(|| arg.help.unwrap_or(""))
arg.long_help.or(arg.help).unwrap_or("")
} else {
arg.help.unwrap_or_else(|| arg.long_help.unwrap_or(""))
arg.help.or(arg.long_help).unwrap_or("")
};
self.help(
@ -667,7 +669,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
let spec_vals = &self.sc_spec_vals(app);
let about = app.about.unwrap_or_else(|| app.long_about.unwrap_or(""));
let about = app.about.or(app.long_about).unwrap_or("");
self.subcmd(sc_str, next_line_help, longest)?;
self.help(false, about, spec_vals, next_line_help, longest)
@ -793,8 +795,8 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
if !first {
self.none("\n\n")?;
}
self.warning(&*format!("{}:\n", heading))?;
self.write_args(&*args)?;
self.warning(format!("{}:\n", heading))?;
self.write_args(&args)?;
first = false
}
}
@ -837,19 +839,15 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
.filter(|subcommand| should_show_subcommand(subcommand))
{
let mut sc_str = String::new();
sc_str.push_str(
&subcommand
.short_flag
.map_or(String::new(), |c| format!("-{}, ", c)),
);
sc_str.push_str(
&subcommand
.long_flag
.map_or(String::new(), |c| format!("--{}, ", c)),
);
if let Some(short) = subcommand.short_flag {
write!(sc_str, "-{}", short).unwrap();
}
if let Some(long) = subcommand.long_flag {
write!(sc_str, "--{}", long).unwrap();
}
sc_str.push_str(&subcommand.name);
longest = longest.max(display_width(&sc_str));
ord_v.push((subcommand.get_display_order(), sc_str, subcommand.clone()));
ord_v.push((subcommand.get_display_order(), sc_str, subcommand));
}
ord_v.sort_by(|a, b| (a.0, &a.1).cmp(&(b.0, &b.1)));

View file

@ -1,6 +1,3 @@
// std
use std::collections::BTreeMap;
use indexmap::IndexSet;
// Internal
@ -52,12 +49,13 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
.app
.usage
.as_ref()
.unwrap_or_else(|| self.p.app.bin_name.as_ref().unwrap_or(&self.p.app.name));
.or_else(|| self.p.app.bin_name.as_ref())
.unwrap_or(&self.p.app.name);
usage.push_str(&*name);
let req_string = if incl_reqs {
self.get_required_usage_from(&[], None, false)
.iter()
.fold(String::new(), |a, s| a + &format!(" {}", s)[..])
.fold(String::new(), |a, s| a + " " + s)
} else {
String::new()
};
@ -181,7 +179,7 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
let r_string = self
.get_required_usage_from(used, None, true)
.iter()
.fold(String::new(), |acc, s| acc + &format!(" {}", s)[..]);
.fold(String::new(), |acc, s| acc + " " + s);
usage.push_str(
&self
@ -189,7 +187,8 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
.app
.usage
.as_ref()
.unwrap_or_else(|| self.p.app.bin_name.as_ref().unwrap_or(&self.p.app.name))[..],
.or_else(|| self.p.app.bin_name.as_ref())
.unwrap_or(&self.p.app.name)[..],
);
usage.push_str(&*r_string);
if self.p.is_set(AS::SubcommandRequired) {
@ -442,7 +441,7 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
}
ret_val.extend_from_slice(&g_vec);
let pmap = unrolled_reqs
let mut pvec = unrolled_reqs
.iter()
.chain(incls.iter())
.filter(|a| self.p.app.get_positionals().any(|p| &&p.id == a))
@ -451,9 +450,10 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
.filter(|&pos| incl_last || !pos.is_set(ArgSettings::Last))
.filter(|pos| !args_in_groups.contains(&pos.id))
.map(|pos| (pos.index.unwrap(), pos))
.collect::<BTreeMap<usize, &Arg>>(); // sort by index
.collect::<Vec<(usize, &Arg)>>();
pvec.sort_by_key(|(ind, _)| *ind); // sort by index
for p in pmap.values() {
for (_, p) in pvec {
debug!("Usage::get_required_usage_from:iter:{:?}", p.id);
if !args_in_groups.contains(&p.id) {
ret_val.push(p.to_string());

View file

@ -63,13 +63,14 @@ impl ArgMatcher {
// --global-arg where the value is `other`, however the occurs will be 0.
let to_update = if let Some(parent_ma) = vals_map.get(global_arg) {
if parent_ma.occurs > 0 && ma.occurs == 0 {
parent_ma.clone()
parent_ma
} else {
ma.clone()
ma
}
} else {
ma.clone()
};
ma
}
.clone();
vals_map.insert(global_arg.clone(), to_update);
}
}

View file

@ -538,6 +538,21 @@ impl Error {
}
}
#[inline(never)]
pub(crate) fn for_app(
app: &App,
colorizer: Colorizer,
kind: ErrorKind,
info: Vec<String>,
) -> Self {
Self::new(
colorizer,
kind,
app.settings.is_set(AppSettings::WaitOnError),
)
.set_info(info)
}
pub(crate) fn set_info(mut self, info: Vec<String>) -> Self {
self.info = info;
self
@ -561,24 +576,20 @@ impl Error {
c.warning(arg);
c.none("' cannot be used with");
let mut info = vec![];
match others.len() {
0 => {
c.none(" one or more of the other specified arguments");
}
1 => {
let v = &others[0];
c.none(" '");
c.warning(v.clone());
c.warning(&*others[0]);
c.none("'");
info.push(v.clone());
}
_ => {
c.none(":");
for v in others {
for v in &others {
c.none("\n ");
c.warning(v.to_string());
info.push(v.to_string());
c.warning(&**v);
}
}
}
@ -586,12 +597,7 @@ impl Error {
put_usage(&mut c, usage);
try_help(app, &mut c);
Self::new(
c,
ErrorKind::ArgumentConflict,
app.settings.is_set(AppSettings::WaitOnError),
)
.set_info(info)
Self::for_app(app, c, ErrorKind::ArgumentConflict, others)
}
pub(crate) fn empty_value(app: &App, arg: &Arg, usage: String) -> Self {
@ -599,58 +605,45 @@ impl Error {
let arg = arg.to_string();
start_error(&mut c, "The argument '");
c.warning(arg.clone());
c.warning(&*arg);
c.none("' requires a value but none was supplied");
put_usage(&mut c, usage);
try_help(app, &mut c);
Self::new(
c,
ErrorKind::EmptyValue,
app.settings.is_set(AppSettings::WaitOnError),
)
.set_info(vec![arg])
Self::for_app(app, c, ErrorKind::EmptyValue, vec![arg])
}
pub(crate) fn no_equals(app: &App, arg: String, usage: String) -> Self {
let mut c = Colorizer::new(true, app.get_color());
start_error(&mut c, "Equal sign is needed when assigning values to '");
c.warning(&arg);
c.warning(&*arg);
c.none("'.");
put_usage(&mut c, usage);
try_help(app, &mut c);
Self::new(
c,
ErrorKind::NoEquals,
app.settings.is_set(AppSettings::WaitOnError),
)
.set_info(vec![arg])
Self::for_app(app, c, ErrorKind::NoEquals, vec![arg])
}
pub(crate) fn invalid_value<G>(
pub(crate) fn invalid_value(
app: &App,
bad_val: String,
good_vals: &[G],
good_vals: &[&str],
arg: &Arg,
usage: String,
) -> Self
where
G: AsRef<str> + Display,
{
) -> Self {
let mut c = Colorizer::new(true, app.get_color());
let suffix = suggestions::did_you_mean(&bad_val, good_vals.iter()).pop();
let arg = arg.to_string();
let mut sorted: Vec<String> = good_vals
.iter()
.map(|v| v.to_string())
.map(|v| {
.map(|&v| {
if v.contains(char::is_whitespace) {
format!("{:?}", v)
} else {
v
v.to_owned()
}
})
.collect();
@ -659,7 +652,7 @@ impl Error {
start_error(&mut c, "");
c.warning(format!("{:?}", bad_val));
c.none(" isn't a valid value for '");
c.warning(arg.to_string());
c.warning(&*arg);
c.none("'\n\t[possible values: ");
if let Some((last, elements)) = sorted.split_last() {
@ -682,15 +675,10 @@ impl Error {
put_usage(&mut c, usage);
try_help(app, &mut c);
let mut info = vec![arg.to_string(), bad_val];
let mut info = vec![arg, bad_val];
info.extend(sorted);
Self::new(
c,
ErrorKind::InvalidValue,
app.settings.is_set(AppSettings::WaitOnError),
)
.set_info(info)
Self::for_app(app, c, ErrorKind::InvalidValue, info)
}
pub(crate) fn invalid_subcommand(
@ -703,7 +691,7 @@ impl Error {
let mut c = Colorizer::new(true, app.get_color());
start_error(&mut c, "The subcommand '");
c.warning(subcmd.clone());
c.warning(&*subcmd);
c.none("' wasn't recognized\n\n\tDid you mean ");
c.good(did_you_mean);
c.none("");
@ -716,30 +704,20 @@ impl Error {
put_usage(&mut c, usage);
try_help(app, &mut c);
Self::new(
c,
ErrorKind::InvalidSubcommand,
app.settings.is_set(AppSettings::WaitOnError),
)
.set_info(vec![subcmd])
Self::for_app(app, c, ErrorKind::InvalidSubcommand, vec![subcmd])
}
pub(crate) fn unrecognized_subcommand(app: &App, subcmd: String, name: String) -> Self {
let mut c = Colorizer::new(true, app.get_color());
start_error(&mut c, " The subcommand '");
c.warning(subcmd.clone());
c.warning(&*subcmd);
c.none("' wasn't recognized\n\n");
c.warning("USAGE:");
c.none(format!("\n {} <subcommands>", name));
try_help(app, &mut c);
Self::new(
c,
ErrorKind::UnrecognizedSubcommand,
app.settings.is_set(AppSettings::WaitOnError),
)
.set_info(vec![subcmd])
Self::for_app(app, c, ErrorKind::UnrecognizedSubcommand, vec![subcmd])
}
pub(crate) fn missing_required_argument(
@ -754,22 +732,15 @@ impl Error {
"The following required arguments were not provided:",
);
let mut info = vec![];
for v in required {
for v in &required {
c.none("\n ");
c.good(v.to_string());
info.push(v.to_string());
c.good(&**v);
}
put_usage(&mut c, usage);
try_help(app, &mut c);
Self::new(
c,
ErrorKind::MissingRequiredArgument,
app.settings.is_set(AppSettings::WaitOnError),
)
.set_info(info)
Self::for_app(app, c, ErrorKind::MissingRequiredArgument, required)
}
pub(crate) fn missing_subcommand(app: &App, name: String, usage: String) -> Self {
@ -781,11 +752,7 @@ impl Error {
put_usage(&mut c, usage);
try_help(app, &mut c);
Self::new(
c,
ErrorKind::MissingSubcommand,
app.settings.is_set(AppSettings::WaitOnError),
)
Self::for_app(app, c, ErrorKind::MissingSubcommand, vec![])
}
pub(crate) fn invalid_utf8(app: &App, usage: String) -> Self {
@ -798,11 +765,7 @@ impl Error {
put_usage(&mut c, usage);
try_help(app, &mut c);
Self::new(
c,
ErrorKind::InvalidUtf8,
app.settings.is_set(AppSettings::WaitOnError),
)
Self::for_app(app, c, ErrorKind::InvalidUtf8, vec![])
}
pub(crate) fn too_many_occurrences(
@ -813,47 +776,41 @@ impl Error {
usage: String,
) -> Self {
let mut c = Colorizer::new(true, app.get_color());
let verb = Error::singular_or_plural(curr_occurs);
let were_provided = Error::singular_or_plural(curr_occurs);
let arg = arg.to_string();
let max_occurs = max_occurs.to_string();
let curr_occurs = curr_occurs.to_string();
start_error(&mut c, "The argument '");
c.warning(arg.to_string());
c.warning(&*arg);
c.none("' allows at most ");
c.warning(max_occurs.to_string());
c.warning(&*max_occurs);
c.none(" occurrences, but ");
c.warning(curr_occurs.to_string());
c.none(format!(" {} provided", verb));
c.warning(&*curr_occurs);
c.none(were_provided);
put_usage(&mut c, usage);
try_help(app, &mut c);
Self::new(
Self::for_app(
app,
c,
ErrorKind::TooManyOccurrences,
app.settings.is_set(AppSettings::WaitOnError),
vec![arg, curr_occurs, max_occurs],
)
.set_info(vec![
arg.to_string(),
curr_occurs.to_string(),
max_occurs.to_string(),
])
}
pub(crate) fn too_many_values(app: &App, val: String, arg: String, usage: String) -> Self {
let mut c = Colorizer::new(true, app.get_color());
start_error(&mut c, "The value '");
c.warning(val.clone());
c.warning(&*val);
c.none("' was provided to '");
c.warning(&arg);
c.warning(&*arg);
c.none("' but it wasn't expecting any more values");
put_usage(&mut c, usage);
try_help(app, &mut c);
Self::new(
c,
ErrorKind::TooManyValues,
app.settings.is_set(AppSettings::WaitOnError),
)
.set_info(vec![arg, val])
Self::for_app(app, c, ErrorKind::TooManyValues, vec![arg, val])
}
pub(crate) fn too_few_values(
@ -864,28 +821,27 @@ impl Error {
usage: String,
) -> Self {
let mut c = Colorizer::new(true, app.get_color());
let verb = Error::singular_or_plural(curr_vals);
let were_provided = Error::singular_or_plural(curr_vals);
let arg = arg.to_string();
let min_vals = min_vals.to_string();
let curr_vals = curr_vals.to_string();
start_error(&mut c, "The argument '");
c.warning(arg.to_string());
c.warning(&*arg);
c.none("' requires at least ");
c.warning(min_vals.to_string());
c.warning(&*min_vals);
c.none(" values, but only ");
c.warning(curr_vals.to_string());
c.none(format!(" {} provided", verb));
c.warning(&*curr_vals);
c.none(were_provided);
put_usage(&mut c, usage);
try_help(app, &mut c);
Self::new(
Self::for_app(
app,
c,
ErrorKind::TooFewValues,
app.settings.is_set(AppSettings::WaitOnError),
vec![arg, curr_vals, min_vals],
)
.set_info(vec![
arg.to_string(),
curr_vals.to_string(),
min_vals.to_string(),
])
}
pub(crate) fn value_validation(
@ -939,7 +895,7 @@ impl Error {
start_error(&mut c, "Invalid value");
c.none(" for '");
c.warning(arg.clone());
c.warning(&*arg);
c.none("'");
c.none(format!(": {}", err));
@ -957,28 +913,27 @@ impl Error {
usage: String,
) -> Self {
let mut c = Colorizer::new(true, app.get_color());
let verb = Error::singular_or_plural(curr_vals);
let were_provided = Error::singular_or_plural(curr_vals);
let arg = arg.to_string();
let num_vals = num_vals.to_string();
let curr_vals = curr_vals.to_string();
start_error(&mut c, "The argument '");
c.warning(arg.to_string());
c.warning(&*arg);
c.none("' requires ");
c.warning(num_vals.to_string());
c.warning(&*num_vals);
c.none(" values, but ");
c.warning(curr_vals.to_string());
c.none(format!(" {} provided", verb));
c.warning(&*curr_vals);
c.none(were_provided);
put_usage(&mut c, usage);
try_help(app, &mut c);
Self::new(
Self::for_app(
app,
c,
ErrorKind::WrongNumberOfValues,
app.settings.is_set(AppSettings::WaitOnError),
vec![arg, curr_vals, num_vals],
)
.set_info(vec![
arg.to_string(),
curr_vals.to_string(),
num_vals.to_string(),
])
}
pub(crate) fn unexpected_multiple_usage(app: &App, arg: &Arg, usage: String) -> Self {
@ -986,17 +941,12 @@ impl Error {
let arg = arg.to_string();
start_error(&mut c, "The argument '");
c.warning(arg.clone());
c.warning(&*arg);
c.none("' was provided more than once, but cannot be used multiple times");
put_usage(&mut c, usage);
try_help(app, &mut c);
Self::new(
c,
ErrorKind::UnexpectedMultipleUsage,
app.settings.is_set(AppSettings::WaitOnError),
)
.set_info(vec![arg])
Self::for_app(app, c, ErrorKind::UnexpectedMultipleUsage, vec![arg])
}
pub(crate) fn unknown_argument(
@ -1008,7 +958,7 @@ impl Error {
let mut c = Colorizer::new(true, app.get_color());
start_error(&mut c, "Found argument '");
c.warning(arg.clone());
c.warning(&*arg);
c.none("' which wasn't expected, or isn't valid in this context");
if let Some((flag, subcmd)) = did_you_mean {
@ -1040,19 +990,14 @@ impl Error {
put_usage(&mut c, usage);
try_help(app, &mut c);
Self::new(
c,
ErrorKind::UnknownArgument,
app.settings.is_set(AppSettings::WaitOnError),
)
.set_info(vec![arg])
Self::for_app(app, c, ErrorKind::UnknownArgument, vec![arg])
}
pub(crate) fn unnecessary_double_dash(app: &App, arg: String, usage: String) -> Self {
let mut c = Colorizer::new(true, app.get_color());
start_error(&mut c, "Found argument '");
c.warning(arg.clone());
c.warning(&*arg);
c.none("' which wasn't expected, or isn't valid in this context");
c.none(format!(
@ -1062,30 +1007,25 @@ impl Error {
put_usage(&mut c, usage);
try_help(app, &mut c);
Self::new(
c,
ErrorKind::UnknownArgument,
app.settings.is_set(AppSettings::WaitOnError),
)
.set_info(vec![arg])
Self::for_app(app, c, ErrorKind::UnknownArgument, vec![arg])
}
pub(crate) fn argument_not_found_auto(arg: String) -> Self {
let mut c = Colorizer::new(true, ColorChoice::Never);
start_error(&mut c, "The argument '");
c.warning(arg.clone());
c.warning(&*arg);
c.none("' wasn't found\n");
Self::new(c, ErrorKind::ArgumentNotFound, false).set_info(vec![arg])
}
/// Returns the singular or plural form on the verb to be based on the argument's value.
fn singular_or_plural(n: usize) -> String {
fn singular_or_plural(n: usize) -> &'static str {
if n > 1 {
String::from("were")
" were provided"
} else {
String::from("was")
" was provided"
}
}
}

View file

@ -2,6 +2,7 @@
use std::{
cell::{Cell, RefCell},
ffi::{OsStr, OsString},
fmt::Write as _,
};
// Third Party
@ -475,8 +476,8 @@ impl<'help, 'app> Parser<'help, 'app> {
}
matcher.subcommand(SubCommand {
name: sc_name.clone(),
id: sc_name.into(),
id: Id::from(&*sc_name),
name: sc_name,
matches: sc_m.into_inner(),
});
@ -735,11 +736,11 @@ impl<'help, 'app> Parser<'help, 'app> {
let mut sc_names = sc.name.clone();
let mut flag_subcmd = false;
if let Some(l) = sc.long_flag {
sc_names.push_str(&format!(", --{}", l));
write!(sc_names, ", --{}", l).unwrap();
flag_subcmd = true;
}
if let Some(s) = sc.short_flag {
sc_names.push_str(&format!(", -{}", s));
write!(sc_names, ", -{}", s).unwrap();
flag_subcmd = true;
}
@ -1189,26 +1190,12 @@ impl<'help, 'app> Parser<'help, 'app> {
);
if !(trailing_values && self.is_set(AS::DontDelimitTrailingValues)) {
if let Some(delim) = arg.val_delim {
let arg_split = val.split(delim);
let vals = if let Some(t) = arg.terminator {
let mut vals = vec![];
for val in arg_split {
if t == val {
break;
}
vals.push(val);
}
vals
} else {
arg_split.collect()
};
self.add_multiple_vals_to_arg(
arg,
vals.into_iter().map(|x| x.to_os_str().into_owned()),
matcher,
ty,
append,
);
let terminator = arg.terminator.map(OsStr::new);
let vals = val
.split(delim)
.map(|x| x.to_os_str().into_owned())
.take_while(|val| Some(val.as_os_str()) != terminator);
self.add_multiple_vals_to_arg(arg, vals, matcher, ty, append);
// If there was a delimiter used or we must use the delimiter to
// separate the values or no more vals is needed, we're not
// looking for more values.
@ -1594,11 +1581,7 @@ impl<'help, 'app> Parser<'help, 'app> {
match Help::new(HelpWriter::Buffer(&mut c), self, use_long).write_help() {
Err(e) => e.into(),
_ => ClapError::new(
c,
ErrorKind::DisplayHelp,
self.app.settings.is_set(AS::WaitOnError),
),
_ => ClapError::for_app(self.app, c, ErrorKind::DisplayHelp, vec![]),
}
}
@ -1608,11 +1591,7 @@ impl<'help, 'app> Parser<'help, 'app> {
let msg = self.app._render_version(use_long);
let mut c = Colorizer::new(false, self.color_help());
c.none(msg);
ClapError::new(
c,
ErrorKind::DisplayVersion,
self.app.settings.is_set(AS::WaitOnError),
)
ClapError::for_app(self.app, c, ErrorKind::DisplayVersion, vec![])
}
}