mirror of
https://github.com/clap-rs/clap
synced 2024-12-14 14:52:33 +00:00
Merge pull request #1388 from scampi/issue-861
feat(Error): add a cause field to the Error struct
This commit is contained in:
commit
2a50c2ef80
3 changed files with 140 additions and 44 deletions
|
@ -374,7 +374,9 @@ pub enum ErrorKind {
|
|||
/// Command Line Argument Parser Error
|
||||
#[derive(Debug)]
|
||||
pub struct Error {
|
||||
/// Formatted error message
|
||||
/// The cause of the error
|
||||
pub cause: String,
|
||||
/// Formatted error message, enhancing the cause message with extra information
|
||||
pub message: String,
|
||||
/// The type of error
|
||||
pub kind: ErrorKind,
|
||||
|
@ -383,6 +385,15 @@ pub struct Error {
|
|||
}
|
||||
|
||||
impl Error {
|
||||
/// Returns the singular or plural form on the verb to be based on the argument's value.
|
||||
fn singular_or_plural(n: usize) -> String {
|
||||
if n > 1 {
|
||||
String::from("were")
|
||||
} else {
|
||||
String::from("was")
|
||||
}
|
||||
}
|
||||
|
||||
/// Should the message be written to `stdout` or not
|
||||
pub fn use_stderr(&self) -> bool {
|
||||
match self.kind {
|
||||
|
@ -421,21 +432,37 @@ impl Error {
|
|||
use_stderr: true,
|
||||
when: color,
|
||||
});
|
||||
let (plain_cause, colored_cause) = match other {
|
||||
Some(name) => {
|
||||
let n = name.into();
|
||||
v.push(n.clone());
|
||||
(
|
||||
format!("The argument '{}' cannot be used with '{}'", group.name, n),
|
||||
format!(
|
||||
"The argument '{}' cannot be used with '{}'",
|
||||
group.name,
|
||||
c.warning(n)
|
||||
),
|
||||
)
|
||||
}
|
||||
None => {
|
||||
let n = "one or more of the other specified arguments";
|
||||
(
|
||||
format!("The argument '{}' cannot be used with {}", group.name, n),
|
||||
format!(
|
||||
"The argument '{}' cannot be used with {}",
|
||||
group.name,
|
||||
c.none(n)
|
||||
),
|
||||
)
|
||||
}
|
||||
};
|
||||
Error {
|
||||
cause: plain_cause,
|
||||
message: format!(
|
||||
"{} The argument '{}' cannot be used with {}\n\n\
|
||||
{}\n\n\
|
||||
For more information try {}",
|
||||
"{} {}\n\n{}\n\nFor more information try {}",
|
||||
c.error("error:"),
|
||||
c.warning(group.name),
|
||||
match other {
|
||||
Some(name) => {
|
||||
let n = name.into();
|
||||
v.push(n.clone());
|
||||
c.warning(format!("'{}'", n))
|
||||
}
|
||||
None => c.none("one or more of the other specified arguments".to_owned()),
|
||||
},
|
||||
colored_cause,
|
||||
usage,
|
||||
c.good("--help")
|
||||
),
|
||||
|
@ -443,6 +470,7 @@ impl Error {
|
|||
info: Some(v),
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn argument_conflict<O, U>(arg: &Arg, other: Option<O>, usage: U, color: ColorWhen) -> Self
|
||||
where
|
||||
|
@ -454,21 +482,37 @@ impl Error {
|
|||
use_stderr: true,
|
||||
when: color,
|
||||
});
|
||||
Error {
|
||||
message: format!(
|
||||
"{} The argument '{}' cannot be used with {}\n\n\
|
||||
{}\n\n\
|
||||
For more information try {}",
|
||||
c.error("error:"),
|
||||
c.warning(&*arg.to_string()),
|
||||
match other {
|
||||
Some(name) => {
|
||||
let n = name.into();
|
||||
v.push(n.clone());
|
||||
let (plain_cause, colored_cause) = match other {
|
||||
Some(name) => {
|
||||
let n = name.into();
|
||||
v.push(n.clone());
|
||||
(
|
||||
format!("The argument '{}' cannot be used with '{}'", arg, n),
|
||||
format!(
|
||||
"The argument '{}' cannot be used with {}",
|
||||
c.warning(arg.to_string()),
|
||||
c.warning(format!("'{}'", n))
|
||||
}
|
||||
None => c.none("one or more of the other specified arguments".to_owned()),
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
None => {
|
||||
let n = "one or more of the other specified arguments";
|
||||
(
|
||||
format!("The argument '{}' cannot be used with {}", arg, n),
|
||||
format!(
|
||||
"The argument '{}' cannot be used with {}",
|
||||
c.warning(arg.to_string()),
|
||||
c.none(n)
|
||||
),
|
||||
)
|
||||
}
|
||||
};
|
||||
Error {
|
||||
cause: plain_cause,
|
||||
message: format!(
|
||||
"{} {}\n\n{}\n\nFor more information try {}",
|
||||
c.error("error:"),
|
||||
colored_cause,
|
||||
usage,
|
||||
c.good("--help")
|
||||
),
|
||||
|
@ -487,6 +531,10 @@ impl Error {
|
|||
when: color,
|
||||
});
|
||||
Error {
|
||||
cause: format!(
|
||||
"The argument '{}' requires a value but none was supplied",
|
||||
arg
|
||||
),
|
||||
message: format!(
|
||||
"{} The argument '{}' requires a value but none was supplied\
|
||||
\n\n\
|
||||
|
@ -529,6 +577,13 @@ impl Error {
|
|||
sorted.sort();
|
||||
let valid_values = sorted.join(", ");
|
||||
Error {
|
||||
cause: format!(
|
||||
"'{}' isn't a valid value for '{}'\n\t\
|
||||
[possible values: {}]",
|
||||
bad_val.as_ref(),
|
||||
arg,
|
||||
valid_values
|
||||
),
|
||||
message: format!(
|
||||
"{} '{}' isn't a valid value for '{}'\n\t\
|
||||
[possible values: {}]\n\
|
||||
|
@ -568,6 +623,7 @@ impl Error {
|
|||
when: color,
|
||||
});
|
||||
Error {
|
||||
cause: format!("The subcommand '{}' wasn't recognized", s),
|
||||
message: format!(
|
||||
"{} The subcommand '{}' wasn't recognized\n\t\
|
||||
Did you mean '{}'?\n\n\
|
||||
|
@ -601,6 +657,7 @@ impl Error {
|
|||
when: color,
|
||||
});
|
||||
Error {
|
||||
cause: format!("The subcommand '{}' wasn't recognized", s),
|
||||
message: format!(
|
||||
"{} The subcommand '{}' wasn't recognized\n\n\
|
||||
{}\n\t\
|
||||
|
@ -628,6 +685,10 @@ impl Error {
|
|||
when: color,
|
||||
});
|
||||
Error {
|
||||
cause: format!(
|
||||
"The following required arguments were not provided:{}",
|
||||
required
|
||||
),
|
||||
message: format!(
|
||||
"{} The following required arguments were not provided:{}\n\n\
|
||||
{}\n\n\
|
||||
|
@ -653,6 +714,7 @@ impl Error {
|
|||
when: color,
|
||||
});
|
||||
Error {
|
||||
cause: format!("'{}' requires a subcommand, but one was not provided", name),
|
||||
message: format!(
|
||||
"{} '{}' requires a subcommand, but one was not provided\n\n\
|
||||
{}\n\n\
|
||||
|
@ -677,6 +739,7 @@ impl Error {
|
|||
when: color,
|
||||
});
|
||||
Error {
|
||||
cause: "Invalid UTF-8 was detected in one or more arguments".to_string(),
|
||||
message: format!(
|
||||
"{} Invalid UTF-8 was detected in one or more arguments\n\n\
|
||||
{}\n\n\
|
||||
|
@ -702,6 +765,10 @@ impl Error {
|
|||
when: color,
|
||||
});
|
||||
Error {
|
||||
cause: format!(
|
||||
"The value '{}' was provided to '{}', but it wasn't expecting any more values",
|
||||
v, arg
|
||||
),
|
||||
message: format!(
|
||||
"{} The value '{}' was provided to '{}', but it wasn't expecting \
|
||||
any more values\n\n\
|
||||
|
@ -733,9 +800,14 @@ impl Error {
|
|||
use_stderr: true,
|
||||
when: color,
|
||||
});
|
||||
let verb = Error::singular_or_plural(curr_vals);
|
||||
Error {
|
||||
cause: format!(
|
||||
"The argument '{}' requires at least {} values, but only {} {} provided",
|
||||
arg, min_vals, curr_vals, verb
|
||||
),
|
||||
message: format!(
|
||||
"{} The argument '{}' requires at least {} values, but only {} w{} \
|
||||
"{} The argument '{}' requires at least {} values, but only {} {} \
|
||||
provided\n\n\
|
||||
{}\n\n\
|
||||
For more information try {}",
|
||||
|
@ -743,7 +815,7 @@ impl Error {
|
|||
c.warning(arg.to_string()),
|
||||
c.warning(min_vals.to_string()),
|
||||
c.warning(curr_vals.to_string()),
|
||||
if curr_vals > 1 { "ere" } else { "as" },
|
||||
verb,
|
||||
usage,
|
||||
c.good("--help")
|
||||
),
|
||||
|
@ -759,6 +831,15 @@ impl Error {
|
|||
when: color,
|
||||
});
|
||||
Error {
|
||||
cause: format!(
|
||||
"Invalid value{}: {}",
|
||||
if let Some(a) = arg {
|
||||
format!(" for '{}'", a)
|
||||
} else {
|
||||
String::new()
|
||||
},
|
||||
err
|
||||
),
|
||||
message: format!(
|
||||
"{} Invalid value{}: {}",
|
||||
c.error("error:"),
|
||||
|
@ -781,25 +862,28 @@ impl Error {
|
|||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn wrong_number_of_values<S, U>(
|
||||
pub fn wrong_number_of_values<U>(
|
||||
arg: &Arg,
|
||||
num_vals: u64,
|
||||
curr_vals: usize,
|
||||
suffix: S,
|
||||
usage: U,
|
||||
color: ColorWhen,
|
||||
) -> Self
|
||||
where
|
||||
S: Display,
|
||||
U: Display,
|
||||
{
|
||||
let c = Colorizer::new(&ColorizerOption {
|
||||
use_stderr: true,
|
||||
when: color,
|
||||
});
|
||||
let verb = Error::singular_or_plural(curr_vals);
|
||||
Error {
|
||||
cause: format!(
|
||||
"The argument '{}' requires {} values, but {} {} provided",
|
||||
arg, num_vals, curr_vals, verb
|
||||
),
|
||||
message: format!(
|
||||
"{} The argument '{}' requires {} values, but {} w{} \
|
||||
"{} The argument '{}' requires {} values, but {} {}
|
||||
provided\n\n\
|
||||
{}\n\n\
|
||||
For more information try {}",
|
||||
|
@ -807,7 +891,7 @@ impl Error {
|
|||
c.warning(arg.to_string()),
|
||||
c.warning(num_vals.to_string()),
|
||||
c.warning(curr_vals.to_string()),
|
||||
suffix,
|
||||
verb,
|
||||
usage,
|
||||
c.good("--help")
|
||||
),
|
||||
|
@ -826,6 +910,10 @@ impl Error {
|
|||
when: color,
|
||||
});
|
||||
Error {
|
||||
cause: format!(
|
||||
"The argument '{}' was provided more than once, but cannot be used multiple times",
|
||||
arg
|
||||
),
|
||||
message: format!(
|
||||
"{} The argument '{}' was provided more than once, but cannot \
|
||||
be used multiple times\n\n\
|
||||
|
@ -842,7 +930,12 @@ impl Error {
|
|||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn unknown_argument<A, U>(arg: A, did_you_mean: Option<String>, usage: U, color: ColorWhen) -> Self
|
||||
pub fn unknown_argument<A, U>(
|
||||
arg: A,
|
||||
did_you_mean: Option<String>,
|
||||
usage: U,
|
||||
color: ColorWhen,
|
||||
) -> Self
|
||||
where
|
||||
A: Into<String>,
|
||||
U: Display,
|
||||
|
@ -857,10 +950,14 @@ impl Error {
|
|||
|
||||
let did_you_mean_message = match did_you_mean {
|
||||
Some(s) => format!("{}\n", s),
|
||||
_ => "\n".to_owned()
|
||||
_ => "\n".to_owned(),
|
||||
};
|
||||
|
||||
Error {
|
||||
cause: format!(
|
||||
"Found argument '{}' which wasn't expected, or isn't valid in this context{}",
|
||||
a, did_you_mean_message
|
||||
),
|
||||
message: format!(
|
||||
"{} Found argument '{}' which wasn't expected, or isn't valid in \
|
||||
this context{}\
|
||||
|
@ -886,6 +983,7 @@ impl Error {
|
|||
when: color,
|
||||
});
|
||||
Error {
|
||||
cause: e.description().to_string(),
|
||||
message: format!("{} {}", c.error("error:"), e.description()),
|
||||
kind: ErrorKind::Io,
|
||||
info: None,
|
||||
|
@ -903,6 +1001,7 @@ impl Error {
|
|||
when: ColorWhen::Auto,
|
||||
});
|
||||
Error {
|
||||
cause: format!("The argument '{}' wasn't found", a),
|
||||
message: format!(
|
||||
"{} The argument '{}' wasn't found",
|
||||
c.error("error:"),
|
||||
|
@ -923,6 +1022,7 @@ impl Error {
|
|||
when: ColorWhen::Auto,
|
||||
});
|
||||
Error {
|
||||
cause: description.to_string(),
|
||||
message: format!("{} {}", c.error("error:"), description),
|
||||
kind,
|
||||
info: None,
|
||||
|
|
|
@ -700,6 +700,7 @@ where
|
|||
let mut out = vec![];
|
||||
self.write_help_err(&mut out)?;
|
||||
return Err(ClapError {
|
||||
cause: String::new(),
|
||||
message: String::from_utf8_lossy(&*out).into_owned(),
|
||||
kind: ErrorKind::MissingArgumentOrSubcommand,
|
||||
info: None,
|
||||
|
@ -1534,6 +1535,7 @@ where
|
|||
match Help::new(&mut buf, self, use_long, false).write_help() {
|
||||
Err(e) => e,
|
||||
_ => ClapError {
|
||||
cause: String::new(),
|
||||
message: String::from_utf8(buf).unwrap_or_default(),
|
||||
kind: ErrorKind::HelpDisplayed,
|
||||
info: None,
|
||||
|
@ -1548,6 +1550,7 @@ where
|
|||
match self.print_version(&mut buf_w, use_long) {
|
||||
Err(e) => e,
|
||||
_ => ClapError {
|
||||
cause: String::new(),
|
||||
message: String::new(),
|
||||
kind: ErrorKind::VersionDisplayed,
|
||||
info: None,
|
||||
|
|
|
@ -67,6 +67,7 @@ impl<'b, 'c, 'z> Validator<'b, 'c, 'z> {
|
|||
let mut out = vec![];
|
||||
self.p.write_help_err(&mut out)?;
|
||||
return Err(Error {
|
||||
cause: String::new(),
|
||||
message: String::from_utf8_lossy(&*out).into_owned(),
|
||||
kind: ErrorKind::MissingArgumentOrSubcommand,
|
||||
info: None,
|
||||
|
@ -398,14 +399,6 @@ impl<'b, 'c, 'z> Validator<'b, 'c, 'z> {
|
|||
} else {
|
||||
ma.vals.len()
|
||||
},
|
||||
if ma.vals.len() == 1
|
||||
|| (a.is_set(ArgSettings::MultipleValues)
|
||||
&& (ma.vals.len() % num as usize) == 1)
|
||||
{
|
||||
"as"
|
||||
} else {
|
||||
"ere"
|
||||
},
|
||||
&*Usage::new(self.p).create_usage_with_title(&[]),
|
||||
self.p.app.color(),
|
||||
));
|
||||
|
|
Loading…
Reference in a new issue