Repository: clap-rs/clap
Pull request #3395 (2022-02-02 21:49:21)

refactor: Prepare for replacing `info`
Prep for #2628 


Patch:
diff --git a/src/build/app/mod.rs b/src/build/app/mod.rs
index 03336801..3c6928df 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 f0dcb65b..db8f5003 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 87dd42a6..7352c2dd 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 b1604cb0..68733980 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<T> = StdResult<T, Error>;
+pub type Result<T, E = Error> = StdResult<T, E>;
 
 /// 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<ErrorInner>,
     /// 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<String>,
+}
+
+#[derive(Debug)]
+struct ErrorInner {
+    /// The type of error
+    kind: ErrorKind,
+    /// Formatted error message, enhancing the cause message with extra information
+    message: Message,
     source: Option<Box<dyn error::Error + Send + Sync>>,
     wait_on_exit: bool,
     backtrace: Option<Backtrace>,
@@ -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<Message>, 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<dyn error::Error + Send + Sync>) -> 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<dyn error::Error + Send + Sync>,
     ) -> 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<fmt::Error> 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 f2f0d1fd..184f115f 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 8fe36df3..f39dd4eb 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 0e9ae2cc..b56d0b88 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,


Test patch:
diff --git a/tests/builder/app_from_crate.rs b/tests/builder/app_from_crate.rs
index 3aa3990c..dabd836f 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 5c823f20..b9945eaa 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 8617540f..996a9d2f 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 4e8ca383..c96660bd 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 b3dae835..a97c0759 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 c9f198b7..cf29983c 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 8d4378d3..ca22f539 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 f24c0b0a..f031b511 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 77ecd918..bd98c462 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 cd54b89d..11284937 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 4108d202..a52549f8 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:
     <base|--delete>
diff --git a/tests/builder/help.rs b/tests/builder/help.rs
index 1412465f..a2678d8d 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 33df33ec..5c78ada2 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 d0b9eba1..808a5510 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 bd326f6b..4ecb34fc 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 56d19b2f..08d16406 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 f02db9c7..b0a9ad20 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 a23f930e..533e0ebf 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 <option>'
diff --git a/tests/builder/regex.rs b/tests/builder/regex.rs
index 0716b93d..4c8052de 100644
--- a/tests/builder/regex.rs
+++ b/tests/builder/regex.rs
@@ -1,6 +1,6 @@
 #![cfg(feature = "regex")]
 
-use clap::{App, Arg, ErrorKind};
+use clap::{error::ErrorKind, App, Arg};
 use regex::{Regex, RegexSet};
 
 #[test]
diff --git a/tests/builder/require.rs b/tests/builder/require.rs
index 072454b8..e841d8e4 100644
--- a/tests/builder/require.rs
+++ b/tests/builder/require.rs
@@ -1,6 +1,6 @@
 use crate::utils;
 
-use clap::{arg, App, Arg, ArgGroup, ErrorKind};
+use clap::{arg, error::ErrorKind, App, Arg, ArgGroup};
 
 static REQUIRE_EQUALS: &str = "error: The following required arguments were not provided:
     --opt=<FILE>
diff --git a/tests/builder/subcommands.rs b/tests/builder/subcommands.rs
index 6fd721a9..e2ada13a 100644
--- a/tests/builder/subcommands.rs
+++ b/tests/builder/subcommands.rs
@@ -1,6 +1,6 @@
 use crate::utils;
 
-use clap::{arg, App, AppSettings, Arg, ErrorKind};
+use clap::{arg, error::ErrorKind, App, AppSettings, Arg};
 
 static VISIBLE_ALIAS_HELP: &str = "clap-test 2.6
 
diff --git a/tests/builder/utf8.rs b/tests/builder/utf8.rs
index b5d4ba7a..a47171f7 100644
--- a/tests/builder/utf8.rs
+++ b/tests/builder/utf8.rs
@@ -1,6 +1,6 @@
 #![cfg(not(windows))]
 
-use clap::{arg, App, AppSettings, Arg, ErrorKind};
+use clap::{arg, error::ErrorKind, App, AppSettings, Arg};
 use std::ffi::OsString;
 use std::os::unix::ffi::OsStringExt;
 
diff --git a/tests/builder/version.rs b/tests/builder/version.rs
index 29a58ba5..629855bb 100644
--- a/tests/builder/version.rs
+++ b/tests/builder/version.rs
@@ -2,7 +2,7 @@ use crate::utils;
 
 use std::str;
 
-use clap::{App, AppSettings, Arg, ErrorKind};
+use clap::{error::ErrorKind, App, AppSettings, Arg};
 
 fn common() -> App<'static> {
     App::new("foo")
@@ -26,7 +26,7 @@ fn no_version_flag_short() {
 
     assert!(res.is_err());
     let err = res.unwrap_err();
-    assert_eq!(err.kind(), clap::ErrorKind::UnknownArgument);
+    assert_eq!(err.kind(), clap::error::ErrorKind::UnknownArgument);
     assert_eq!(err.info, ["-V"]);
 }
 
@@ -36,7 +36,7 @@ fn no_version_flag_long() {
 
     assert!(res.is_err());
     let err = res.unwrap_err();
-    assert_eq!(err.kind(), clap::ErrorKind::UnknownArgument);
+    assert_eq!(err.kind(), clap::error::ErrorKind::UnknownArgument);
     assert_eq!(err.info, ["--version"]);
 }
 
diff --git a/tests/macros.rs b/tests/macros.rs
index 74b407f5..af1ba7b2 100644
--- a/tests/macros.rs
+++ b/tests/macros.rs
@@ -1,6 +1,6 @@
 // We intentionally don't import `clap_app!` here; not having it in scope protects against the
 // class of errors where the macro refers to itself as `clap_app!` instead of `$crate::clap_app!`
-use clap::ErrorKind;
+use clap::error::ErrorKind;
 
 #[test]
 fn basic() {