diff --git a/src/build/app/mod.rs b/src/build/app/mod.rs index 0284579eb45..423731bdc0f 100644 --- a/src/build/app/mod.rs +++ b/src/build/app/mod.rs @@ -29,7 +29,7 @@ use crate::{ output::{fmt::Colorizer, Help, HelpWriter, Usage}, parse::{ArgMatcher, ArgMatches, Input, Parser}, util::{color::ColorChoice, safe_exit, Id, Key, USAGE_CODE}, - Result as ClapResult, INTERNAL_ERROR_MSG, + Error, ErrorKind, Result as ClapResult, INTERNAL_ERROR_MSG, }; /// Represents a command line interface which is made up of all possible @@ -1764,6 +1764,21 @@ impl<'help> App<'help> { self } + /// Custom error message for post-parsing validation + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, ErrorKind}; + /// let mut app = App::new("myprog"); + /// let err = app.error(ErrorKind::InvalidValue, "Some failure case"); + /// ``` + pub fn error(&mut self, kind: ErrorKind, message: impl std::fmt::Display) -> Error { + self._build(); + let usage = self.render_usage(); + Error::user_error(self, usage, kind, message) + } + /// Prints the full help message to [`io::stdout()`] using a [`BufWriter`] using the same /// method as if someone ran `-h` to request the help message. /// diff --git a/src/parse/errors.rs b/src/parse/errors.rs index 50e8ca59509..b7f0f650b3e 100644 --- a/src/parse/errors.rs +++ b/src/parse/errors.rs @@ -423,6 +423,10 @@ pub enum ErrorKind { } /// Command Line Argument Parser Error +/// +/// See [`App::error`] to create an error. +/// +/// [`App::error`]: crate::App::value_of_t() #[derive(Debug)] pub struct Error { /// Formatted error message, enhancing the cause message with extra information @@ -540,6 +544,27 @@ impl Error { } } + pub(crate) fn user_error( + app: &App, + usage: String, + kind: ErrorKind, + message: impl std::fmt::Display, + ) -> Self { + let mut c = Colorizer::new(true, app.get_color()); + + start_error(&mut c, message.to_string()); + put_usage(&mut c, usage); + try_help(app, &mut c); + + Self { + message: c, + kind, + info: vec![], + source: None, + backtrace: Backtrace::new(), + } + } + pub(crate) fn argument_conflict( app: &App, arg: &Arg, @@ -1077,34 +1102,31 @@ impl Error { } } - /// Create an error with a custom description. + /// Deprecated, see [`App::error`] /// - /// This can be used in combination with `Error::exit` to exit your program - /// with a custom error message. + /// [`App::error`]: crate::App::value_of_t() + #[deprecated(since = "3.0.0", note = "Replaced with `App::error`")] pub fn with_description(description: String, kind: ErrorKind) -> Self { let mut c = Colorizer::new(true, ColorChoice::Auto); start_error(&mut c, description); - - Error { - message: c, - kind, - info: vec![], - source: None, - backtrace: Backtrace::new(), - } + Error::new(c, kind) } } impl From for Error { fn from(e: io::Error) -> Self { - Error::with_description(e.to_string(), ErrorKind::Io) + let mut c = Colorizer::new(true, ColorChoice::Auto); + start_error(&mut c, e.to_string()); + Error::new(c, ErrorKind::Io) } } impl From for Error { fn from(e: fmt::Error) -> Self { - Error::with_description(e.to_string(), ErrorKind::Format) + let mut c = Colorizer::new(true, ColorChoice::Auto); + start_error(&mut c, e.to_string()); + Error::new(c, ErrorKind::Format) } }