From 7497dbb6cced17bff2deab3b568332ce07c014e3 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 4 Feb 2022 14:35:52 -0600 Subject: [PATCH] feat(error: Expose value-validation context --- src/error/mod.rs | 82 +++++++++++++------------------- src/parse/matches/arg_matches.rs | 4 +- src/parse/validator.rs | 8 ++-- tests/builder/validators.rs | 2 +- 4 files changed, 39 insertions(+), 57 deletions(-) diff --git a/src/error/mod.rs b/src/error/mod.rs index 0934a334..217d37dd 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -178,7 +178,7 @@ impl Error { .set_info(info) } - fn with_app(self, app: &App) -> Self { + pub(crate) fn with_app(self, app: &App) -> Self { self.set_wait_on_exit(app.settings.is_set(AppSettings::WaitOnError)) .set_color(app.get_color()) .set_help_flag(get_help_flag(app)) @@ -488,60 +488,21 @@ impl Error { } pub(crate) fn value_validation( - app: &App, arg: String, val: String, err: Box, ) -> Self { - let mut err = - Self::value_validation_with_color(arg, val, err, app.get_color()).with_app(app); - match err.inner.message.as_mut() { - Some(Message::Formatted(c)) => try_help(c, get_help_flag(app)), - _ => { - unreachable!("`value_validation_with_color` only deals in formatted errors") - } - } - err - } - - pub(crate) fn value_validation_without_app( - arg: String, - val: String, - err: Box, - ) -> Self { - let mut err = Self::value_validation_with_color(arg, val, err, ColorChoice::Never); - match err.inner.message.as_mut() { - Some(Message::Formatted(c)) => { - c.none("\n"); - } - _ => { - unreachable!("`value_validation_with_color` only deals in formatted errors") - } - } - err - } - - fn value_validation_with_color( - arg: String, - val: String, - err: Box, - color: ColorChoice, - ) -> Self { - let mut c = Colorizer::new(true, color); - - start_error(&mut c); - c.none("Invalid value"); - - c.none(" for '"); - c.warning(&*arg); - c.none("'"); - - c.none(format!(": {}", err)); - + let info = vec![arg.to_string(), val.to_string(), err.to_string()]; Self::new(ErrorKind::ValueValidation) - .set_message(c) - .set_info(vec![arg, val, err.to_string()]) + .set_info(info) .set_source(err) + .extend_context_unchecked([ + ( + ContextKind::InvalidArg, + ContextValue::String(arg.to_string()), + ), + (ContextKind::InvalidValue, ContextValue::String(val)), + ]) } pub(crate) fn wrong_number_of_values( @@ -904,8 +865,29 @@ impl Error { c.none(self.kind().as_str().unwrap()); } } + ErrorKind::ValueValidation => { + let invalid_arg = self.get_context(ContextKind::InvalidArg); + let invalid_value = self.get_context(ContextKind::InvalidValue); + if let ( + Some(ContextValue::String(invalid_arg)), + Some(ContextValue::String(invalid_value)), + ) = (invalid_arg, invalid_value) + { + c.none("Invalid value "); + c.warning(quote(invalid_value)); + c.none(" for '"); + c.warning(invalid_arg); + if let Some(source) = self.inner.source.as_deref() { + c.none("': "); + c.none(source.to_string()); + } else { + c.none("'"); + } + } else { + c.none(self.kind().as_str().unwrap()); + } + } ErrorKind::UnknownArgument - | ErrorKind::ValueValidation | ErrorKind::WrongNumberOfValues | ErrorKind::UnexpectedMultipleUsage | ErrorKind::DisplayHelp diff --git a/src/parse/matches/arg_matches.rs b/src/parse/matches/arg_matches.rs index 4f4b25b5..de66e9e1 100644 --- a/src/parse/matches/arg_matches.rs +++ b/src/parse/matches/arg_matches.rs @@ -463,7 +463,7 @@ impl ArgMatches { v, name, e ); - Error::value_validation_without_app(name.to_string(), v.to_string(), message.into()) + Error::value_validation(name.to_string(), v.to_string(), message.into()) }) } @@ -551,7 +551,7 @@ impl ArgMatches { v.parse::().map_err(|e| { let message = format!("The argument '{}' isn't a valid value: {}", v, e); - Error::value_validation_without_app(name.to_string(), v.to_string(), message.into()) + Error::value_validation(name.to_string(), v.to_string(), message.into()) }) }) .collect() diff --git a/src/parse/validator.rs b/src/parse/validator.rs index eef61577..4828d36e 100644 --- a/src/parse/validator.rs +++ b/src/parse/validator.rs @@ -144,11 +144,11 @@ impl<'help, 'app, 'parser> Validator<'help, 'app, 'parser> { if let Err(e) = vtor(&*val.to_string_lossy()) { debug!("error"); return Err(Error::value_validation( - self.p.app, arg.to_string(), val.to_string_lossy().into_owned(), e, - )); + ) + .with_app(self.p.app)); } else { debug!("good"); } @@ -159,11 +159,11 @@ impl<'help, 'app, 'parser> Validator<'help, 'app, 'parser> { if let Err(e) = vtor(val) { debug!("error"); return Err(Error::value_validation( - self.p.app, arg.to_string(), val.to_string_lossy().into(), e, - )); + ) + .with_app(self.p.app)); } else { debug!("good"); } diff --git a/tests/builder/validators.rs b/tests/builder/validators.rs index 7c9e71d7..04885707 100644 --- a/tests/builder/validators.rs +++ b/tests/builder/validators.rs @@ -41,7 +41,7 @@ fn test_validator_msg_newline() { assert!( err.to_string() - .contains("Invalid value for '': invalid digit found in string"), + .contains("Invalid value \"f\" for '': invalid digit found in string"), "{}", err );