diff --git a/src/build/app/mod.rs b/src/build/app/mod.rs index 03336801f45..3c6928dff66 100644 --- a/src/build/app/mod.rs +++ b/src/build/app/mod.rs @@ -23,14 +23,14 @@ use os_str_bytes::RawOsStr; use yaml_rust::Yaml; // Internal -use crate::{ - build::{arg::ArgProvider, Arg, ArgGroup, ArgPredicate, ArgSettings}, - mkeymap::MKeyMap, - output::{fmt::Colorizer, Help, HelpWriter, Usage}, - parse::{ArgMatcher, ArgMatches, Input, Parser}, - util::{color::ColorChoice, Id, Key}, - Error, ErrorKind, Result as ClapResult, INTERNAL_ERROR_MSG, -}; +use crate::build::{arg::ArgProvider, Arg, ArgGroup, ArgPredicate, ArgSettings}; +use crate::error::ErrorKind; +use crate::error::Result as ClapResult; +use crate::mkeymap::MKeyMap; +use crate::output::{fmt::Colorizer, Help, HelpWriter, Usage}; +use crate::parse::{ArgMatcher, ArgMatches, Input, Parser}; +use crate::util::{color::ColorChoice, Id, Key}; +use crate::{Error, INTERNAL_ERROR_MSG}; /// Build a command-line interface. /// diff --git a/src/build/usage_parser.rs b/src/build/usage_parser.rs index f0dcb65b4bf..db8f5003b85 100644 --- a/src/build/usage_parser.rs +++ b/src/build/usage_parser.rs @@ -1260,7 +1260,7 @@ mod test { #[test] fn issue_665() { - use crate::{App, ErrorKind}; + use crate::{error::ErrorKind, App}; // Verify fix for "arg_from_usage(): required values not being enforced when followed by another option" let res = App::new("tester") .arg(Arg::from_usage("-v, --reroll-count=[N] 'Mark the patch series as PATCH vN'")) diff --git a/src/lib.rs b/src/lib.rs index 87dd42a6671..7352c2ddee0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,13 +26,15 @@ #[cfg(not(feature = "std"))] compile_error!("`std` feature is currently required to build `clap`"); +pub use crate::parse::error; +pub use crate::parse::error::{ErrorKind, Result}; #[cfg(feature = "color")] pub use crate::util::color::ColorChoice; pub use crate::{ build::{ App, AppFlags, AppSettings, Arg, ArgFlags, ArgGroup, ArgSettings, PossibleValue, ValueHint, }, - parse::errors::{Error, ErrorKind, Result}, + parse::error::Error, parse::{ArgMatches, Indices, OsValues, Values}, }; diff --git a/src/parse/errors.rs b/src/parse/error.rs similarity index 97% rename from src/parse/errors.rs rename to src/parse/error.rs index b1604cb0346..6873398084f 100644 --- a/src/parse/errors.rs +++ b/src/parse/error.rs @@ -1,3 +1,5 @@ +//! Error reporting + // Std use std::{ borrow::Cow, @@ -20,7 +22,7 @@ use crate::{ /// Short hand for [`Result`] type /// /// [`Result`]: std::result::Result -pub type Result = StdResult; +pub type Result = StdResult; /// Command line argument parser kind of error #[derive(Debug, Copy, Clone, PartialEq)] @@ -431,13 +433,20 @@ pub enum ErrorKind { /// [`App::error`]: crate::App::error #[derive(Debug)] pub struct Error { - /// Formatted error message, enhancing the cause message with extra information - message: Message, + inner: Box, /// The type of error pub kind: ErrorKind, /// Additional information depending on the error kind, like values and argument names. /// Useful when you want to render an error of your own. pub info: Vec, +} + +#[derive(Debug)] +struct ErrorInner { + /// The type of error + kind: ErrorKind, + /// Formatted error message, enhancing the cause message with extra information + message: Message, source: Option>, wait_on_exit: bool, backtrace: Option, @@ -461,14 +470,14 @@ impl Error { pub fn format(mut self, app: &mut App) -> Self { app._build(); let usage = app.render_usage(); - self.message.format(app, usage); - self.wait_on_exit = app.settings.is_set(AppSettings::WaitOnError); + self.inner.message.format(app, usage); + self.inner.wait_on_exit = app.settings.is_set(AppSettings::WaitOnError); self } /// Type of error for programmatic processing pub fn kind(&self) -> ErrorKind { - self.kind + self.inner.kind } /// Should the message be written to `stdout` or not? @@ -489,7 +498,7 @@ impl Error { // Swallow broken pipe errors let _ = self.print(); - if self.wait_on_exit { + if self.inner.wait_on_exit { wlnerr!("\nPress [ENTER] / [RETURN] to continue..."); let mut s = String::new(); let i = io::stdin(); @@ -521,7 +530,7 @@ impl Error { /// }; /// ``` pub fn print(&self) -> io::Result<()> { - self.message.formatted().print() + self.inner.message.formatted().print() } /// Deprecated, replaced with [`App::error`] @@ -534,12 +543,15 @@ impl Error { pub(crate) fn new(message: impl Into, kind: ErrorKind, wait_on_exit: bool) -> Self { Self { - message: message.into(), + inner: Box::new(ErrorInner { + kind, + message: message.into(), + source: None, + wait_on_exit, + backtrace: Backtrace::new(), + }), kind, info: vec![], - source: None, - wait_on_exit, - backtrace: Backtrace::new(), } } @@ -564,7 +576,7 @@ impl Error { } pub(crate) fn set_source(mut self, source: Box) -> Self { - self.source = Some(source); + self.inner.source = Some(source); self } @@ -885,7 +897,7 @@ impl Error { app.get_color(), app.settings.is_set(AppSettings::WaitOnError), ); - match &mut err.message { + match &mut err.inner.message { Message::Raw(_) => { unreachable!("`value_validation_with_color` only deals in formatted errors") } @@ -900,7 +912,7 @@ impl Error { err: Box, ) -> Self { let mut err = Self::value_validation_with_color(arg, val, err, ColorChoice::Never, false); - match &mut err.message { + match &mut err.inner.message { Message::Raw(_) => { unreachable!("`value_validation_with_color` only deals in formatted errors") } @@ -1073,15 +1085,15 @@ impl From for Error { impl error::Error for Error { #[allow(trivial_casts)] fn source(&self) -> Option<&(dyn error::Error + 'static)> { - self.source.as_ref().map(|e| e.as_ref() as _) + self.inner.source.as_ref().map(|e| e.as_ref() as _) } } impl Display for Error { fn fmt(&self, f: &mut Formatter) -> fmt::Result { // Assuming `self.message` already has a trailing newline, from `try_help` or similar - write!(f, "{}", self.message.formatted())?; - if let Some(backtrace) = self.backtrace.as_ref() { + write!(f, "{}", self.inner.message.formatted())?; + if let Some(backtrace) = self.inner.backtrace.as_ref() { writeln!(f)?; writeln!(f, "Backtrace:")?; writeln!(f, "{}", backtrace)?; diff --git a/src/parse/mod.rs b/src/parse/mod.rs index f2f0d1fd034..184f115fd3a 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -1,4 +1,4 @@ -pub mod errors; +pub mod error; pub mod features; mod arg_matcher; diff --git a/src/parse/parser.rs b/src/parse/parser.rs index 8fe36df31fc..f39dd4eb3ab 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -14,9 +14,9 @@ use crate::{ build::{App, Arg, ArgSettings}, mkeymap::KeyType, output::{fmt::Colorizer, Help, HelpWriter, Usage}, - parse::errors::Error as ClapError, - parse::errors::ErrorKind, - parse::errors::Result as ClapResult, + parse::error::Error as ClapError, + parse::error::ErrorKind, + parse::error::Result as ClapResult, parse::features::suggestions, parse::{ArgMatcher, SubCommand}, parse::{Validator, ValueType}, diff --git a/src/parse/validator.rs b/src/parse/validator.rs index 0e9ae2ccad0..b56d0b88e0c 100644 --- a/src/parse/validator.rs +++ b/src/parse/validator.rs @@ -3,7 +3,7 @@ use crate::{ build::{arg::PossibleValue, App, AppSettings as AS, Arg, ArgSettings}, output::Usage, parse::{ - errors::{Error, ErrorKind, Result as ClapResult}, + error::{Error, ErrorKind, Result as ClapResult}, ArgMatcher, MatchedArg, ParseState, Parser, }, util::Id, diff --git a/tests/builder/app_from_crate.rs b/tests/builder/app_from_crate.rs index 3aa3990cff4..dabd836f3a9 100644 --- a/tests/builder/app_from_crate.rs +++ b/tests/builder/app_from_crate.rs @@ -1,6 +1,6 @@ #![cfg(feature = "cargo")] -use clap::{app_from_crate, ErrorKind}; +use clap::{app_from_crate, error::ErrorKind}; static EVERYTHING: &str = "clap {{version}} A simple to use, efficient, and full-featured Command Line Argument Parser diff --git a/tests/builder/app_settings.rs b/tests/builder/app_settings.rs index 5c823f20762..b9945eaa44d 100644 --- a/tests/builder/app_settings.rs +++ b/tests/builder/app_settings.rs @@ -1,6 +1,6 @@ use crate::utils; -use clap::{arg, App, AppSettings, Arg, ErrorKind}; +use clap::{arg, error::ErrorKind, App, AppSettings, Arg}; static ALLOW_EXT_SC: &str = "clap-test v1.4.8 diff --git a/tests/builder/cargo.rs b/tests/builder/cargo.rs index 8617540f381..996a9d2fd5a 100644 --- a/tests/builder/cargo.rs +++ b/tests/builder/cargo.rs @@ -1,6 +1,6 @@ #![cfg(feature = "cargo")] -use clap::{crate_authors, crate_description, crate_name, crate_version, App, ErrorKind}; +use clap::{crate_authors, crate_description, crate_name, crate_version, error::ErrorKind, App}; static DESCRIPTION_ONLY: &str = "prog 1 A simple to use, efficient, and full-featured Command Line Argument Parser diff --git a/tests/builder/conflicts.rs b/tests/builder/conflicts.rs index 4e8ca38344c..c96660bd68b 100644 --- a/tests/builder/conflicts.rs +++ b/tests/builder/conflicts.rs @@ -1,6 +1,6 @@ use crate::utils; -use clap::{arg, App, Arg, ArgGroup, ErrorKind}; +use clap::{arg, error::ErrorKind, App, Arg, ArgGroup}; static CONFLICT_ERR: &str = "error: The argument '--flag' cannot be used with '-F' diff --git a/tests/builder/default_vals.rs b/tests/builder/default_vals.rs index b3dae8355bb..a97c0759d78 100644 --- a/tests/builder/default_vals.rs +++ b/tests/builder/default_vals.rs @@ -1,5 +1,5 @@ use crate::utils; -use clap::{arg, App, Arg, ErrorKind}; +use clap::{arg, error::ErrorKind, App, Arg}; #[test] fn opts() { diff --git a/tests/builder/double_require.rs b/tests/builder/double_require.rs index c9f198b7948..cf29983ccf7 100644 --- a/tests/builder/double_require.rs +++ b/tests/builder/double_require.rs @@ -1,4 +1,4 @@ -use clap::{App, Arg, ErrorKind}; +use clap::{error::ErrorKind, App, Arg}; static HELP: &str = "prog diff --git a/tests/builder/empty_values.rs b/tests/builder/empty_values.rs index 8d4378d3b9f..ca22f539f64 100644 --- a/tests/builder/empty_values.rs +++ b/tests/builder/empty_values.rs @@ -1,6 +1,6 @@ use crate::utils; -use clap::{App, Arg, ErrorKind}; +use clap::{error::ErrorKind, App, Arg}; #[test] fn empty_values() { diff --git a/tests/builder/error.rs b/tests/builder/error.rs index f24c0b0a3b7..f031b51156b 100644 --- a/tests/builder/error.rs +++ b/tests/builder/error.rs @@ -1,6 +1,6 @@ use crate::utils; -use clap::{arg, App, Arg, Error, ErrorKind}; +use clap::{arg, error::ErrorKind, App, Arg, Error}; fn compare_error( err: Error, diff --git a/tests/builder/flag_subcommands.rs b/tests/builder/flag_subcommands.rs index 77ecd918dfb..bd98c462980 100644 --- a/tests/builder/flag_subcommands.rs +++ b/tests/builder/flag_subcommands.rs @@ -1,6 +1,6 @@ use crate::utils; -use clap::{arg, App, AppSettings, Arg, ErrorKind}; +use clap::{arg, error::ErrorKind, App, AppSettings, Arg}; #[test] fn flag_subcommand_normal() { diff --git a/tests/builder/flags.rs b/tests/builder/flags.rs index cd54b89dee4..112849374ea 100644 --- a/tests/builder/flags.rs +++ b/tests/builder/flags.rs @@ -89,7 +89,7 @@ fn flag_using_long() { #[test] fn flag_using_long_with_literals() { - use clap::ErrorKind; + use clap::error::ErrorKind; let m = App::new("flag") .arg(Arg::new("rainbow").long("rainbow")) diff --git a/tests/builder/groups.rs b/tests/builder/groups.rs index 4108d202170..a52549f87de 100644 --- a/tests/builder/groups.rs +++ b/tests/builder/groups.rs @@ -1,6 +1,6 @@ use crate::utils; -use clap::{arg, App, Arg, ArgGroup, ErrorKind}; +use clap::{arg, error::ErrorKind, App, Arg, ArgGroup}; static REQ_GROUP_USAGE: &str = "error: The following required arguments were not provided: diff --git a/tests/builder/help.rs b/tests/builder/help.rs index 1412465f3e6..a2678d8d7ea 100644 --- a/tests/builder/help.rs +++ b/tests/builder/help.rs @@ -1,6 +1,6 @@ use crate::utils; -use clap::{arg, App, AppSettings, Arg, ArgGroup, ErrorKind, PossibleValue}; +use clap::{arg, error::ErrorKind, App, AppSettings, Arg, ArgGroup, PossibleValue}; static REQUIRE_DELIM_HELP: &str = "test 1.3 Kevin K. diff --git a/tests/builder/multiple_occurrences.rs b/tests/builder/multiple_occurrences.rs index 33df33eca2f..5c78ada2ccd 100644 --- a/tests/builder/multiple_occurrences.rs +++ b/tests/builder/multiple_occurrences.rs @@ -1,4 +1,4 @@ -use clap::{arg, App, Arg, ErrorKind}; +use clap::{arg, error::ErrorKind, App, Arg}; #[test] fn multiple_occurrences_of_flags_long() { diff --git a/tests/builder/multiple_values.rs b/tests/builder/multiple_values.rs index d0b9eba136c..808a55103ce 100644 --- a/tests/builder/multiple_values.rs +++ b/tests/builder/multiple_values.rs @@ -1,4 +1,4 @@ -use clap::{App, Arg, ErrorKind}; +use clap::{error::ErrorKind, App, Arg}; #[test] fn option_long() { diff --git a/tests/builder/opts.rs b/tests/builder/opts.rs index bd326f6b7ca..4ecb34fc5db 100644 --- a/tests/builder/opts.rs +++ b/tests/builder/opts.rs @@ -1,6 +1,6 @@ use crate::utils; -use clap::{arg, App, AppSettings, Arg, ArgMatches, ErrorKind}; +use clap::{arg, error::ErrorKind, App, AppSettings, Arg, ArgMatches}; #[cfg(feature = "suggestions")] static DYM: &str = diff --git a/tests/builder/positionals.rs b/tests/builder/positionals.rs index 56d19b2fc7f..08d16406427 100644 --- a/tests/builder/positionals.rs +++ b/tests/builder/positionals.rs @@ -1,4 +1,4 @@ -use clap::{arg, App, Arg, ErrorKind}; +use clap::{arg, error::ErrorKind, App, Arg}; #[test] fn only_pos_follow() { diff --git a/tests/builder/posix_compatible.rs b/tests/builder/posix_compatible.rs index f02db9c79d4..b0a9ad20e45 100644 --- a/tests/builder/posix_compatible.rs +++ b/tests/builder/posix_compatible.rs @@ -1,4 +1,4 @@ -use clap::{arg, App, Arg, ErrorKind}; +use clap::{arg, error::ErrorKind, App, Arg}; #[test] fn flag_overrides_itself() { diff --git a/tests/builder/possible_values.rs b/tests/builder/possible_values.rs index a23f930ee71..533e0ebf782 100644 --- a/tests/builder/possible_values.rs +++ b/tests/builder/possible_values.rs @@ -1,6 +1,6 @@ use crate::utils; -use clap::{App, Arg, ErrorKind, PossibleValue}; +use clap::{error::ErrorKind, App, Arg, PossibleValue}; #[cfg(feature = "suggestions")] static PV_ERROR: &str = "error: \"slo\" isn't a valid value for '-O