119625d8cSopenharmony_ci//! Error reporting 219625d8cSopenharmony_ci 319625d8cSopenharmony_ci#![cfg_attr(not(feature = "error-context"), allow(dead_code))] 419625d8cSopenharmony_ci#![cfg_attr(not(feature = "error-context"), allow(unused_imports))] 519625d8cSopenharmony_ci#![cfg_attr(not(feature = "error-context"), allow(unused_variables))] 619625d8cSopenharmony_ci#![cfg_attr(not(feature = "error-context"), allow(unused_mut))] 719625d8cSopenharmony_ci#![cfg_attr(not(feature = "error-context"), allow(clippy::let_and_return))] 819625d8cSopenharmony_ci 919625d8cSopenharmony_ci// Std 1019625d8cSopenharmony_ciuse std::{ 1119625d8cSopenharmony_ci borrow::Cow, 1219625d8cSopenharmony_ci convert::From, 1319625d8cSopenharmony_ci error, 1419625d8cSopenharmony_ci fmt::{self, Debug, Display, Formatter}, 1519625d8cSopenharmony_ci io::{self}, 1619625d8cSopenharmony_ci result::Result as StdResult, 1719625d8cSopenharmony_ci}; 1819625d8cSopenharmony_ci 1919625d8cSopenharmony_ci// Internal 2019625d8cSopenharmony_ciuse crate::builder::StyledStr; 2119625d8cSopenharmony_ciuse crate::output::fmt::Colorizer; 2219625d8cSopenharmony_ciuse crate::output::fmt::Stream; 2319625d8cSopenharmony_ciuse crate::parser::features::suggestions; 2419625d8cSopenharmony_ciuse crate::util::FlatMap; 2519625d8cSopenharmony_ciuse crate::util::{color::ColorChoice, safe_exit, SUCCESS_CODE, USAGE_CODE}; 2619625d8cSopenharmony_ciuse crate::Command; 2719625d8cSopenharmony_ci 2819625d8cSopenharmony_ci#[cfg(feature = "error-context")] 2919625d8cSopenharmony_cimod context; 3019625d8cSopenharmony_cimod format; 3119625d8cSopenharmony_cimod kind; 3219625d8cSopenharmony_ci 3319625d8cSopenharmony_cipub use format::ErrorFormatter; 3419625d8cSopenharmony_cipub use format::KindFormatter; 3519625d8cSopenharmony_cipub use kind::ErrorKind; 3619625d8cSopenharmony_ci 3719625d8cSopenharmony_ci#[cfg(feature = "error-context")] 3819625d8cSopenharmony_cipub use context::ContextKind; 3919625d8cSopenharmony_ci#[cfg(feature = "error-context")] 4019625d8cSopenharmony_cipub use context::ContextValue; 4119625d8cSopenharmony_ci#[cfg(feature = "error-context")] 4219625d8cSopenharmony_cipub use format::RichFormatter; 4319625d8cSopenharmony_ci 4419625d8cSopenharmony_ci#[cfg(not(feature = "error-context"))] 4519625d8cSopenharmony_cipub use KindFormatter as DefaultFormatter; 4619625d8cSopenharmony_ci#[cfg(feature = "error-context")] 4719625d8cSopenharmony_cipub use RichFormatter as DefaultFormatter; 4819625d8cSopenharmony_ci 4919625d8cSopenharmony_ci/// Short hand for [`Result`] type 5019625d8cSopenharmony_ci/// 5119625d8cSopenharmony_ci/// [`Result`]: std::result::Result 5219625d8cSopenharmony_cipub type Result<T, E = Error> = StdResult<T, E>; 5319625d8cSopenharmony_ci 5419625d8cSopenharmony_ci/// Command Line Argument Parser Error 5519625d8cSopenharmony_ci/// 5619625d8cSopenharmony_ci/// See [`Command::error`] to create an error. 5719625d8cSopenharmony_ci/// 5819625d8cSopenharmony_ci/// [`Command::error`]: crate::Command::error 5919625d8cSopenharmony_cipub struct Error<F: ErrorFormatter = DefaultFormatter> { 6019625d8cSopenharmony_ci inner: Box<ErrorInner>, 6119625d8cSopenharmony_ci phantom: std::marker::PhantomData<F>, 6219625d8cSopenharmony_ci} 6319625d8cSopenharmony_ci 6419625d8cSopenharmony_ci#[derive(Debug)] 6519625d8cSopenharmony_cistruct ErrorInner { 6619625d8cSopenharmony_ci kind: ErrorKind, 6719625d8cSopenharmony_ci #[cfg(feature = "error-context")] 6819625d8cSopenharmony_ci context: FlatMap<ContextKind, ContextValue>, 6919625d8cSopenharmony_ci message: Option<Message>, 7019625d8cSopenharmony_ci source: Option<Box<dyn error::Error + Send + Sync>>, 7119625d8cSopenharmony_ci help_flag: Option<&'static str>, 7219625d8cSopenharmony_ci color_when: ColorChoice, 7319625d8cSopenharmony_ci color_help_when: ColorChoice, 7419625d8cSopenharmony_ci backtrace: Option<Backtrace>, 7519625d8cSopenharmony_ci} 7619625d8cSopenharmony_ci 7719625d8cSopenharmony_ciimpl<F: ErrorFormatter> Error<F> { 7819625d8cSopenharmony_ci /// Create an unformatted error 7919625d8cSopenharmony_ci /// 8019625d8cSopenharmony_ci /// This is for you need to pass the error up to 8119625d8cSopenharmony_ci /// a place that has access to the `Command` at which point you can call [`Error::format`]. 8219625d8cSopenharmony_ci /// 8319625d8cSopenharmony_ci /// Prefer [`Command::error`] for generating errors. 8419625d8cSopenharmony_ci /// 8519625d8cSopenharmony_ci /// [`Command::error`]: crate::Command::error 8619625d8cSopenharmony_ci pub fn raw(kind: ErrorKind, message: impl std::fmt::Display) -> Self { 8719625d8cSopenharmony_ci Self::new(kind).set_message(message.to_string()) 8819625d8cSopenharmony_ci } 8919625d8cSopenharmony_ci 9019625d8cSopenharmony_ci /// Format the existing message with the Command's context 9119625d8cSopenharmony_ci #[must_use] 9219625d8cSopenharmony_ci pub fn format(mut self, cmd: &mut Command) -> Self { 9319625d8cSopenharmony_ci cmd._build_self(false); 9419625d8cSopenharmony_ci let usage = cmd.render_usage_(); 9519625d8cSopenharmony_ci if let Some(message) = self.inner.message.as_mut() { 9619625d8cSopenharmony_ci message.format(cmd, usage); 9719625d8cSopenharmony_ci } 9819625d8cSopenharmony_ci self.with_cmd(cmd) 9919625d8cSopenharmony_ci } 10019625d8cSopenharmony_ci 10119625d8cSopenharmony_ci /// Create an error with a pre-defined message 10219625d8cSopenharmony_ci /// 10319625d8cSopenharmony_ci /// See also 10419625d8cSopenharmony_ci /// - [`Error::insert`] 10519625d8cSopenharmony_ci /// - [`Error::with_cmd`] 10619625d8cSopenharmony_ci /// 10719625d8cSopenharmony_ci /// # Example 10819625d8cSopenharmony_ci /// 10919625d8cSopenharmony_ci #[cfg_attr(not(feature = "error-context"), doc = " ```ignore")] 11019625d8cSopenharmony_ci #[cfg_attr(feature = "error-context", doc = " ```")] 11119625d8cSopenharmony_ci /// # use clap::error::ErrorKind; 11219625d8cSopenharmony_ci /// # use clap::error::ContextKind; 11319625d8cSopenharmony_ci /// # use clap::error::ContextValue; 11419625d8cSopenharmony_ci /// 11519625d8cSopenharmony_ci /// let cmd = clap::Command::new("prog"); 11619625d8cSopenharmony_ci /// 11719625d8cSopenharmony_ci /// let mut err = clap::Error::new(ErrorKind::ValueValidation) 11819625d8cSopenharmony_ci /// .with_cmd(&cmd); 11919625d8cSopenharmony_ci /// err.insert(ContextKind::InvalidArg, ContextValue::String("--foo".to_owned())); 12019625d8cSopenharmony_ci /// err.insert(ContextKind::InvalidValue, ContextValue::String("bar".to_owned())); 12119625d8cSopenharmony_ci /// 12219625d8cSopenharmony_ci /// err.print(); 12319625d8cSopenharmony_ci /// ``` 12419625d8cSopenharmony_ci pub fn new(kind: ErrorKind) -> Self { 12519625d8cSopenharmony_ci Self { 12619625d8cSopenharmony_ci inner: Box::new(ErrorInner { 12719625d8cSopenharmony_ci kind, 12819625d8cSopenharmony_ci #[cfg(feature = "error-context")] 12919625d8cSopenharmony_ci context: FlatMap::new(), 13019625d8cSopenharmony_ci message: None, 13119625d8cSopenharmony_ci source: None, 13219625d8cSopenharmony_ci help_flag: None, 13319625d8cSopenharmony_ci color_when: ColorChoice::Never, 13419625d8cSopenharmony_ci color_help_when: ColorChoice::Never, 13519625d8cSopenharmony_ci backtrace: Backtrace::new(), 13619625d8cSopenharmony_ci }), 13719625d8cSopenharmony_ci phantom: Default::default(), 13819625d8cSopenharmony_ci } 13919625d8cSopenharmony_ci } 14019625d8cSopenharmony_ci 14119625d8cSopenharmony_ci /// Apply [`Command`]'s formatting to the error 14219625d8cSopenharmony_ci /// 14319625d8cSopenharmony_ci /// Generally, this is used with [`Error::new`] 14419625d8cSopenharmony_ci pub fn with_cmd(self, cmd: &Command) -> Self { 14519625d8cSopenharmony_ci self.set_color(cmd.get_color()) 14619625d8cSopenharmony_ci .set_colored_help(cmd.color_help()) 14719625d8cSopenharmony_ci .set_help_flag(format::get_help_flag(cmd)) 14819625d8cSopenharmony_ci } 14919625d8cSopenharmony_ci 15019625d8cSopenharmony_ci /// Apply an alternative formatter to the error 15119625d8cSopenharmony_ci /// 15219625d8cSopenharmony_ci /// # Example 15319625d8cSopenharmony_ci /// 15419625d8cSopenharmony_ci /// ```rust 15519625d8cSopenharmony_ci /// # use clap::Command; 15619625d8cSopenharmony_ci /// # use clap::Arg; 15719625d8cSopenharmony_ci /// # use clap::error::KindFormatter; 15819625d8cSopenharmony_ci /// let cmd = Command::new("foo") 15919625d8cSopenharmony_ci /// .arg(Arg::new("input").required(true)); 16019625d8cSopenharmony_ci /// let matches = cmd 16119625d8cSopenharmony_ci /// .try_get_matches_from(["foo", "input.txt"]) 16219625d8cSopenharmony_ci /// .map_err(|e| e.apply::<KindFormatter>()) 16319625d8cSopenharmony_ci /// .unwrap_or_else(|e| e.exit()); 16419625d8cSopenharmony_ci /// ``` 16519625d8cSopenharmony_ci pub fn apply<EF: ErrorFormatter>(self) -> Error<EF> { 16619625d8cSopenharmony_ci Error { 16719625d8cSopenharmony_ci inner: self.inner, 16819625d8cSopenharmony_ci phantom: Default::default(), 16919625d8cSopenharmony_ci } 17019625d8cSopenharmony_ci } 17119625d8cSopenharmony_ci 17219625d8cSopenharmony_ci /// Type of error for programmatic processing 17319625d8cSopenharmony_ci pub fn kind(&self) -> ErrorKind { 17419625d8cSopenharmony_ci self.inner.kind 17519625d8cSopenharmony_ci } 17619625d8cSopenharmony_ci 17719625d8cSopenharmony_ci /// Additional information to further qualify the error 17819625d8cSopenharmony_ci #[cfg(feature = "error-context")] 17919625d8cSopenharmony_ci pub fn context(&self) -> impl Iterator<Item = (ContextKind, &ContextValue)> { 18019625d8cSopenharmony_ci self.inner.context.iter().map(|(k, v)| (*k, v)) 18119625d8cSopenharmony_ci } 18219625d8cSopenharmony_ci 18319625d8cSopenharmony_ci /// Lookup a piece of context 18419625d8cSopenharmony_ci #[inline(never)] 18519625d8cSopenharmony_ci #[cfg(feature = "error-context")] 18619625d8cSopenharmony_ci pub fn get(&self, kind: ContextKind) -> Option<&ContextValue> { 18719625d8cSopenharmony_ci self.inner.context.get(&kind) 18819625d8cSopenharmony_ci } 18919625d8cSopenharmony_ci 19019625d8cSopenharmony_ci /// Insert a piece of context 19119625d8cSopenharmony_ci #[inline(never)] 19219625d8cSopenharmony_ci #[cfg(feature = "error-context")] 19319625d8cSopenharmony_ci pub fn insert(&mut self, kind: ContextKind, value: ContextValue) -> Option<ContextValue> { 19419625d8cSopenharmony_ci self.inner.context.insert(kind, value) 19519625d8cSopenharmony_ci } 19619625d8cSopenharmony_ci 19719625d8cSopenharmony_ci /// Should the message be written to `stdout` or not? 19819625d8cSopenharmony_ci #[inline] 19919625d8cSopenharmony_ci pub fn use_stderr(&self) -> bool { 20019625d8cSopenharmony_ci self.stream() == Stream::Stderr 20119625d8cSopenharmony_ci } 20219625d8cSopenharmony_ci 20319625d8cSopenharmony_ci pub(crate) fn stream(&self) -> Stream { 20419625d8cSopenharmony_ci match self.kind() { 20519625d8cSopenharmony_ci ErrorKind::DisplayHelp | ErrorKind::DisplayVersion => Stream::Stdout, 20619625d8cSopenharmony_ci _ => Stream::Stderr, 20719625d8cSopenharmony_ci } 20819625d8cSopenharmony_ci } 20919625d8cSopenharmony_ci 21019625d8cSopenharmony_ci /// Prints the error and exits. 21119625d8cSopenharmony_ci /// 21219625d8cSopenharmony_ci /// Depending on the error kind, this either prints to `stderr` and exits with a status of `2` 21319625d8cSopenharmony_ci /// or prints to `stdout` and exits with a status of `0`. 21419625d8cSopenharmony_ci pub fn exit(&self) -> ! { 21519625d8cSopenharmony_ci if self.use_stderr() { 21619625d8cSopenharmony_ci // Swallow broken pipe errors 21719625d8cSopenharmony_ci let _ = self.print(); 21819625d8cSopenharmony_ci 21919625d8cSopenharmony_ci safe_exit(USAGE_CODE); 22019625d8cSopenharmony_ci } 22119625d8cSopenharmony_ci 22219625d8cSopenharmony_ci // Swallow broken pipe errors 22319625d8cSopenharmony_ci let _ = self.print(); 22419625d8cSopenharmony_ci safe_exit(SUCCESS_CODE) 22519625d8cSopenharmony_ci } 22619625d8cSopenharmony_ci 22719625d8cSopenharmony_ci /// Prints formatted and colored error to `stdout` or `stderr` according to its error kind 22819625d8cSopenharmony_ci /// 22919625d8cSopenharmony_ci /// # Example 23019625d8cSopenharmony_ci /// ```no_run 23119625d8cSopenharmony_ci /// use clap::Command; 23219625d8cSopenharmony_ci /// 23319625d8cSopenharmony_ci /// match Command::new("Command").try_get_matches() { 23419625d8cSopenharmony_ci /// Ok(matches) => { 23519625d8cSopenharmony_ci /// // do_something 23619625d8cSopenharmony_ci /// }, 23719625d8cSopenharmony_ci /// Err(err) => { 23819625d8cSopenharmony_ci /// err.print().expect("Error writing Error"); 23919625d8cSopenharmony_ci /// // do_something 24019625d8cSopenharmony_ci /// }, 24119625d8cSopenharmony_ci /// }; 24219625d8cSopenharmony_ci /// ``` 24319625d8cSopenharmony_ci pub fn print(&self) -> io::Result<()> { 24419625d8cSopenharmony_ci let style = self.formatted(); 24519625d8cSopenharmony_ci let color_when = if matches!( 24619625d8cSopenharmony_ci self.kind(), 24719625d8cSopenharmony_ci ErrorKind::DisplayHelp | ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand, 24819625d8cSopenharmony_ci ) { 24919625d8cSopenharmony_ci self.inner.color_help_when 25019625d8cSopenharmony_ci } else { 25119625d8cSopenharmony_ci self.inner.color_when 25219625d8cSopenharmony_ci }; 25319625d8cSopenharmony_ci let c = Colorizer::new(self.stream(), color_when).with_content(style.into_owned()); 25419625d8cSopenharmony_ci c.print() 25519625d8cSopenharmony_ci } 25619625d8cSopenharmony_ci 25719625d8cSopenharmony_ci /// Render the error message to a [`StyledStr`]. 25819625d8cSopenharmony_ci /// 25919625d8cSopenharmony_ci /// # Example 26019625d8cSopenharmony_ci /// ```no_run 26119625d8cSopenharmony_ci /// use clap::Command; 26219625d8cSopenharmony_ci /// 26319625d8cSopenharmony_ci /// match Command::new("Command").try_get_matches() { 26419625d8cSopenharmony_ci /// Ok(matches) => { 26519625d8cSopenharmony_ci /// // do_something 26619625d8cSopenharmony_ci /// }, 26719625d8cSopenharmony_ci /// Err(err) => { 26819625d8cSopenharmony_ci /// let err = err.render(); 26919625d8cSopenharmony_ci /// println!("{}", err); 27019625d8cSopenharmony_ci /// // do_something 27119625d8cSopenharmony_ci /// }, 27219625d8cSopenharmony_ci /// }; 27319625d8cSopenharmony_ci /// ``` 27419625d8cSopenharmony_ci pub fn render(&self) -> StyledStr { 27519625d8cSopenharmony_ci self.formatted().into_owned() 27619625d8cSopenharmony_ci } 27719625d8cSopenharmony_ci 27819625d8cSopenharmony_ci #[inline(never)] 27919625d8cSopenharmony_ci fn for_app(kind: ErrorKind, cmd: &Command, styled: StyledStr) -> Self { 28019625d8cSopenharmony_ci Self::new(kind).set_message(styled).with_cmd(cmd) 28119625d8cSopenharmony_ci } 28219625d8cSopenharmony_ci 28319625d8cSopenharmony_ci pub(crate) fn set_message(mut self, message: impl Into<Message>) -> Self { 28419625d8cSopenharmony_ci self.inner.message = Some(message.into()); 28519625d8cSopenharmony_ci self 28619625d8cSopenharmony_ci } 28719625d8cSopenharmony_ci 28819625d8cSopenharmony_ci pub(crate) fn set_source(mut self, source: Box<dyn error::Error + Send + Sync>) -> Self { 28919625d8cSopenharmony_ci self.inner.source = Some(source); 29019625d8cSopenharmony_ci self 29119625d8cSopenharmony_ci } 29219625d8cSopenharmony_ci 29319625d8cSopenharmony_ci pub(crate) fn set_color(mut self, color_when: ColorChoice) -> Self { 29419625d8cSopenharmony_ci self.inner.color_when = color_when; 29519625d8cSopenharmony_ci self 29619625d8cSopenharmony_ci } 29719625d8cSopenharmony_ci 29819625d8cSopenharmony_ci pub(crate) fn set_colored_help(mut self, color_help_when: ColorChoice) -> Self { 29919625d8cSopenharmony_ci self.inner.color_help_when = color_help_when; 30019625d8cSopenharmony_ci self 30119625d8cSopenharmony_ci } 30219625d8cSopenharmony_ci 30319625d8cSopenharmony_ci pub(crate) fn set_help_flag(mut self, help_flag: Option<&'static str>) -> Self { 30419625d8cSopenharmony_ci self.inner.help_flag = help_flag; 30519625d8cSopenharmony_ci self 30619625d8cSopenharmony_ci } 30719625d8cSopenharmony_ci 30819625d8cSopenharmony_ci /// Does not verify if `ContextKind` is already present 30919625d8cSopenharmony_ci #[inline(never)] 31019625d8cSopenharmony_ci #[cfg(feature = "error-context")] 31119625d8cSopenharmony_ci pub(crate) fn insert_context_unchecked( 31219625d8cSopenharmony_ci mut self, 31319625d8cSopenharmony_ci kind: ContextKind, 31419625d8cSopenharmony_ci value: ContextValue, 31519625d8cSopenharmony_ci ) -> Self { 31619625d8cSopenharmony_ci self.inner.context.insert_unchecked(kind, value); 31719625d8cSopenharmony_ci self 31819625d8cSopenharmony_ci } 31919625d8cSopenharmony_ci 32019625d8cSopenharmony_ci /// Does not verify if `ContextKind` is already present 32119625d8cSopenharmony_ci #[inline(never)] 32219625d8cSopenharmony_ci #[cfg(feature = "error-context")] 32319625d8cSopenharmony_ci pub(crate) fn extend_context_unchecked<const N: usize>( 32419625d8cSopenharmony_ci mut self, 32519625d8cSopenharmony_ci context: [(ContextKind, ContextValue); N], 32619625d8cSopenharmony_ci ) -> Self { 32719625d8cSopenharmony_ci self.inner.context.extend_unchecked(context); 32819625d8cSopenharmony_ci self 32919625d8cSopenharmony_ci } 33019625d8cSopenharmony_ci 33119625d8cSopenharmony_ci pub(crate) fn display_help(cmd: &Command, styled: StyledStr) -> Self { 33219625d8cSopenharmony_ci Self::for_app(ErrorKind::DisplayHelp, cmd, styled) 33319625d8cSopenharmony_ci } 33419625d8cSopenharmony_ci 33519625d8cSopenharmony_ci pub(crate) fn display_help_error(cmd: &Command, styled: StyledStr) -> Self { 33619625d8cSopenharmony_ci Self::for_app( 33719625d8cSopenharmony_ci ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand, 33819625d8cSopenharmony_ci cmd, 33919625d8cSopenharmony_ci styled, 34019625d8cSopenharmony_ci ) 34119625d8cSopenharmony_ci } 34219625d8cSopenharmony_ci 34319625d8cSopenharmony_ci pub(crate) fn display_version(cmd: &Command, styled: StyledStr) -> Self { 34419625d8cSopenharmony_ci Self::for_app(ErrorKind::DisplayVersion, cmd, styled) 34519625d8cSopenharmony_ci } 34619625d8cSopenharmony_ci 34719625d8cSopenharmony_ci pub(crate) fn argument_conflict( 34819625d8cSopenharmony_ci cmd: &Command, 34919625d8cSopenharmony_ci arg: String, 35019625d8cSopenharmony_ci mut others: Vec<String>, 35119625d8cSopenharmony_ci usage: Option<StyledStr>, 35219625d8cSopenharmony_ci ) -> Self { 35319625d8cSopenharmony_ci let mut err = Self::new(ErrorKind::ArgumentConflict).with_cmd(cmd); 35419625d8cSopenharmony_ci 35519625d8cSopenharmony_ci #[cfg(feature = "error-context")] 35619625d8cSopenharmony_ci { 35719625d8cSopenharmony_ci let others = match others.len() { 35819625d8cSopenharmony_ci 0 => ContextValue::None, 35919625d8cSopenharmony_ci 1 => ContextValue::String(others.pop().unwrap()), 36019625d8cSopenharmony_ci _ => ContextValue::Strings(others), 36119625d8cSopenharmony_ci }; 36219625d8cSopenharmony_ci err = err.extend_context_unchecked([ 36319625d8cSopenharmony_ci (ContextKind::InvalidArg, ContextValue::String(arg)), 36419625d8cSopenharmony_ci (ContextKind::PriorArg, others), 36519625d8cSopenharmony_ci ]); 36619625d8cSopenharmony_ci if let Some(usage) = usage { 36719625d8cSopenharmony_ci err = err 36819625d8cSopenharmony_ci .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage)); 36919625d8cSopenharmony_ci } 37019625d8cSopenharmony_ci } 37119625d8cSopenharmony_ci 37219625d8cSopenharmony_ci err 37319625d8cSopenharmony_ci } 37419625d8cSopenharmony_ci 37519625d8cSopenharmony_ci pub(crate) fn empty_value(cmd: &Command, good_vals: &[String], arg: String) -> Self { 37619625d8cSopenharmony_ci Self::invalid_value(cmd, "".to_owned(), good_vals, arg) 37719625d8cSopenharmony_ci } 37819625d8cSopenharmony_ci 37919625d8cSopenharmony_ci pub(crate) fn no_equals(cmd: &Command, arg: String, usage: Option<StyledStr>) -> Self { 38019625d8cSopenharmony_ci let mut err = Self::new(ErrorKind::NoEquals).with_cmd(cmd); 38119625d8cSopenharmony_ci 38219625d8cSopenharmony_ci #[cfg(feature = "error-context")] 38319625d8cSopenharmony_ci { 38419625d8cSopenharmony_ci err = err 38519625d8cSopenharmony_ci .extend_context_unchecked([(ContextKind::InvalidArg, ContextValue::String(arg))]); 38619625d8cSopenharmony_ci if let Some(usage) = usage { 38719625d8cSopenharmony_ci err = err 38819625d8cSopenharmony_ci .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage)); 38919625d8cSopenharmony_ci } 39019625d8cSopenharmony_ci } 39119625d8cSopenharmony_ci 39219625d8cSopenharmony_ci err 39319625d8cSopenharmony_ci } 39419625d8cSopenharmony_ci 39519625d8cSopenharmony_ci pub(crate) fn invalid_value( 39619625d8cSopenharmony_ci cmd: &Command, 39719625d8cSopenharmony_ci bad_val: String, 39819625d8cSopenharmony_ci good_vals: &[String], 39919625d8cSopenharmony_ci arg: String, 40019625d8cSopenharmony_ci ) -> Self { 40119625d8cSopenharmony_ci let suggestion = suggestions::did_you_mean(&bad_val, good_vals.iter()).pop(); 40219625d8cSopenharmony_ci let mut err = Self::new(ErrorKind::InvalidValue).with_cmd(cmd); 40319625d8cSopenharmony_ci 40419625d8cSopenharmony_ci #[cfg(feature = "error-context")] 40519625d8cSopenharmony_ci { 40619625d8cSopenharmony_ci err = err.extend_context_unchecked([ 40719625d8cSopenharmony_ci (ContextKind::InvalidArg, ContextValue::String(arg)), 40819625d8cSopenharmony_ci (ContextKind::InvalidValue, ContextValue::String(bad_val)), 40919625d8cSopenharmony_ci ( 41019625d8cSopenharmony_ci ContextKind::ValidValue, 41119625d8cSopenharmony_ci ContextValue::Strings(good_vals.iter().map(|s| (*s).to_owned()).collect()), 41219625d8cSopenharmony_ci ), 41319625d8cSopenharmony_ci ]); 41419625d8cSopenharmony_ci if let Some(suggestion) = suggestion { 41519625d8cSopenharmony_ci err = err.insert_context_unchecked( 41619625d8cSopenharmony_ci ContextKind::SuggestedValue, 41719625d8cSopenharmony_ci ContextValue::String(suggestion), 41819625d8cSopenharmony_ci ); 41919625d8cSopenharmony_ci } 42019625d8cSopenharmony_ci } 42119625d8cSopenharmony_ci 42219625d8cSopenharmony_ci err 42319625d8cSopenharmony_ci } 42419625d8cSopenharmony_ci 42519625d8cSopenharmony_ci pub(crate) fn invalid_subcommand( 42619625d8cSopenharmony_ci cmd: &Command, 42719625d8cSopenharmony_ci subcmd: String, 42819625d8cSopenharmony_ci did_you_mean: Vec<String>, 42919625d8cSopenharmony_ci name: String, 43019625d8cSopenharmony_ci usage: Option<StyledStr>, 43119625d8cSopenharmony_ci ) -> Self { 43219625d8cSopenharmony_ci let mut err = Self::new(ErrorKind::InvalidSubcommand).with_cmd(cmd); 43319625d8cSopenharmony_ci 43419625d8cSopenharmony_ci #[cfg(feature = "error-context")] 43519625d8cSopenharmony_ci { 43619625d8cSopenharmony_ci let mut styled_suggestion = StyledStr::new(); 43719625d8cSopenharmony_ci styled_suggestion.none("to pass '"); 43819625d8cSopenharmony_ci styled_suggestion.warning(&subcmd); 43919625d8cSopenharmony_ci styled_suggestion.none("' as a value, use '"); 44019625d8cSopenharmony_ci styled_suggestion.good(name); 44119625d8cSopenharmony_ci styled_suggestion.good(" -- "); 44219625d8cSopenharmony_ci styled_suggestion.good(&subcmd); 44319625d8cSopenharmony_ci styled_suggestion.none("'"); 44419625d8cSopenharmony_ci 44519625d8cSopenharmony_ci err = err.extend_context_unchecked([ 44619625d8cSopenharmony_ci (ContextKind::InvalidSubcommand, ContextValue::String(subcmd)), 44719625d8cSopenharmony_ci ( 44819625d8cSopenharmony_ci ContextKind::SuggestedSubcommand, 44919625d8cSopenharmony_ci ContextValue::Strings(did_you_mean), 45019625d8cSopenharmony_ci ), 45119625d8cSopenharmony_ci ( 45219625d8cSopenharmony_ci ContextKind::Suggested, 45319625d8cSopenharmony_ci ContextValue::StyledStrs(vec![styled_suggestion]), 45419625d8cSopenharmony_ci ), 45519625d8cSopenharmony_ci ]); 45619625d8cSopenharmony_ci if let Some(usage) = usage { 45719625d8cSopenharmony_ci err = err 45819625d8cSopenharmony_ci .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage)); 45919625d8cSopenharmony_ci } 46019625d8cSopenharmony_ci } 46119625d8cSopenharmony_ci 46219625d8cSopenharmony_ci err 46319625d8cSopenharmony_ci } 46419625d8cSopenharmony_ci 46519625d8cSopenharmony_ci pub(crate) fn unrecognized_subcommand( 46619625d8cSopenharmony_ci cmd: &Command, 46719625d8cSopenharmony_ci subcmd: String, 46819625d8cSopenharmony_ci usage: Option<StyledStr>, 46919625d8cSopenharmony_ci ) -> Self { 47019625d8cSopenharmony_ci let mut err = Self::new(ErrorKind::InvalidSubcommand).with_cmd(cmd); 47119625d8cSopenharmony_ci 47219625d8cSopenharmony_ci #[cfg(feature = "error-context")] 47319625d8cSopenharmony_ci { 47419625d8cSopenharmony_ci err = err.extend_context_unchecked([( 47519625d8cSopenharmony_ci ContextKind::InvalidSubcommand, 47619625d8cSopenharmony_ci ContextValue::String(subcmd), 47719625d8cSopenharmony_ci )]); 47819625d8cSopenharmony_ci if let Some(usage) = usage { 47919625d8cSopenharmony_ci err = err 48019625d8cSopenharmony_ci .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage)); 48119625d8cSopenharmony_ci } 48219625d8cSopenharmony_ci } 48319625d8cSopenharmony_ci 48419625d8cSopenharmony_ci err 48519625d8cSopenharmony_ci } 48619625d8cSopenharmony_ci 48719625d8cSopenharmony_ci pub(crate) fn missing_required_argument( 48819625d8cSopenharmony_ci cmd: &Command, 48919625d8cSopenharmony_ci required: Vec<String>, 49019625d8cSopenharmony_ci usage: Option<StyledStr>, 49119625d8cSopenharmony_ci ) -> Self { 49219625d8cSopenharmony_ci let mut err = Self::new(ErrorKind::MissingRequiredArgument).with_cmd(cmd); 49319625d8cSopenharmony_ci 49419625d8cSopenharmony_ci #[cfg(feature = "error-context")] 49519625d8cSopenharmony_ci { 49619625d8cSopenharmony_ci err = err.extend_context_unchecked([( 49719625d8cSopenharmony_ci ContextKind::InvalidArg, 49819625d8cSopenharmony_ci ContextValue::Strings(required), 49919625d8cSopenharmony_ci )]); 50019625d8cSopenharmony_ci if let Some(usage) = usage { 50119625d8cSopenharmony_ci err = err 50219625d8cSopenharmony_ci .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage)); 50319625d8cSopenharmony_ci } 50419625d8cSopenharmony_ci } 50519625d8cSopenharmony_ci 50619625d8cSopenharmony_ci err 50719625d8cSopenharmony_ci } 50819625d8cSopenharmony_ci 50919625d8cSopenharmony_ci pub(crate) fn missing_subcommand( 51019625d8cSopenharmony_ci cmd: &Command, 51119625d8cSopenharmony_ci parent: String, 51219625d8cSopenharmony_ci available: Vec<String>, 51319625d8cSopenharmony_ci usage: Option<StyledStr>, 51419625d8cSopenharmony_ci ) -> Self { 51519625d8cSopenharmony_ci let mut err = Self::new(ErrorKind::MissingSubcommand).with_cmd(cmd); 51619625d8cSopenharmony_ci 51719625d8cSopenharmony_ci #[cfg(feature = "error-context")] 51819625d8cSopenharmony_ci { 51919625d8cSopenharmony_ci err = err.extend_context_unchecked([ 52019625d8cSopenharmony_ci (ContextKind::InvalidSubcommand, ContextValue::String(parent)), 52119625d8cSopenharmony_ci ( 52219625d8cSopenharmony_ci ContextKind::ValidSubcommand, 52319625d8cSopenharmony_ci ContextValue::Strings(available), 52419625d8cSopenharmony_ci ), 52519625d8cSopenharmony_ci ]); 52619625d8cSopenharmony_ci if let Some(usage) = usage { 52719625d8cSopenharmony_ci err = err 52819625d8cSopenharmony_ci .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage)); 52919625d8cSopenharmony_ci } 53019625d8cSopenharmony_ci } 53119625d8cSopenharmony_ci 53219625d8cSopenharmony_ci err 53319625d8cSopenharmony_ci } 53419625d8cSopenharmony_ci 53519625d8cSopenharmony_ci pub(crate) fn invalid_utf8(cmd: &Command, usage: Option<StyledStr>) -> Self { 53619625d8cSopenharmony_ci let mut err = Self::new(ErrorKind::InvalidUtf8).with_cmd(cmd); 53719625d8cSopenharmony_ci 53819625d8cSopenharmony_ci #[cfg(feature = "error-context")] 53919625d8cSopenharmony_ci { 54019625d8cSopenharmony_ci if let Some(usage) = usage { 54119625d8cSopenharmony_ci err = err 54219625d8cSopenharmony_ci .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage)); 54319625d8cSopenharmony_ci } 54419625d8cSopenharmony_ci } 54519625d8cSopenharmony_ci 54619625d8cSopenharmony_ci err 54719625d8cSopenharmony_ci } 54819625d8cSopenharmony_ci 54919625d8cSopenharmony_ci pub(crate) fn too_many_values( 55019625d8cSopenharmony_ci cmd: &Command, 55119625d8cSopenharmony_ci val: String, 55219625d8cSopenharmony_ci arg: String, 55319625d8cSopenharmony_ci usage: Option<StyledStr>, 55419625d8cSopenharmony_ci ) -> Self { 55519625d8cSopenharmony_ci let mut err = Self::new(ErrorKind::TooManyValues).with_cmd(cmd); 55619625d8cSopenharmony_ci 55719625d8cSopenharmony_ci #[cfg(feature = "error-context")] 55819625d8cSopenharmony_ci { 55919625d8cSopenharmony_ci err = err.extend_context_unchecked([ 56019625d8cSopenharmony_ci (ContextKind::InvalidArg, ContextValue::String(arg)), 56119625d8cSopenharmony_ci (ContextKind::InvalidValue, ContextValue::String(val)), 56219625d8cSopenharmony_ci ]); 56319625d8cSopenharmony_ci if let Some(usage) = usage { 56419625d8cSopenharmony_ci err = err 56519625d8cSopenharmony_ci .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage)); 56619625d8cSopenharmony_ci } 56719625d8cSopenharmony_ci } 56819625d8cSopenharmony_ci 56919625d8cSopenharmony_ci err 57019625d8cSopenharmony_ci } 57119625d8cSopenharmony_ci 57219625d8cSopenharmony_ci pub(crate) fn too_few_values( 57319625d8cSopenharmony_ci cmd: &Command, 57419625d8cSopenharmony_ci arg: String, 57519625d8cSopenharmony_ci min_vals: usize, 57619625d8cSopenharmony_ci curr_vals: usize, 57719625d8cSopenharmony_ci usage: Option<StyledStr>, 57819625d8cSopenharmony_ci ) -> Self { 57919625d8cSopenharmony_ci let mut err = Self::new(ErrorKind::TooFewValues).with_cmd(cmd); 58019625d8cSopenharmony_ci 58119625d8cSopenharmony_ci #[cfg(feature = "error-context")] 58219625d8cSopenharmony_ci { 58319625d8cSopenharmony_ci err = err.extend_context_unchecked([ 58419625d8cSopenharmony_ci (ContextKind::InvalidArg, ContextValue::String(arg)), 58519625d8cSopenharmony_ci ( 58619625d8cSopenharmony_ci ContextKind::MinValues, 58719625d8cSopenharmony_ci ContextValue::Number(min_vals as isize), 58819625d8cSopenharmony_ci ), 58919625d8cSopenharmony_ci ( 59019625d8cSopenharmony_ci ContextKind::ActualNumValues, 59119625d8cSopenharmony_ci ContextValue::Number(curr_vals as isize), 59219625d8cSopenharmony_ci ), 59319625d8cSopenharmony_ci ]); 59419625d8cSopenharmony_ci if let Some(usage) = usage { 59519625d8cSopenharmony_ci err = err 59619625d8cSopenharmony_ci .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage)); 59719625d8cSopenharmony_ci } 59819625d8cSopenharmony_ci } 59919625d8cSopenharmony_ci 60019625d8cSopenharmony_ci err 60119625d8cSopenharmony_ci } 60219625d8cSopenharmony_ci 60319625d8cSopenharmony_ci pub(crate) fn value_validation( 60419625d8cSopenharmony_ci arg: String, 60519625d8cSopenharmony_ci val: String, 60619625d8cSopenharmony_ci err: Box<dyn error::Error + Send + Sync>, 60719625d8cSopenharmony_ci ) -> Self { 60819625d8cSopenharmony_ci let mut err = Self::new(ErrorKind::ValueValidation).set_source(err); 60919625d8cSopenharmony_ci 61019625d8cSopenharmony_ci #[cfg(feature = "error-context")] 61119625d8cSopenharmony_ci { 61219625d8cSopenharmony_ci err = err.extend_context_unchecked([ 61319625d8cSopenharmony_ci (ContextKind::InvalidArg, ContextValue::String(arg)), 61419625d8cSopenharmony_ci (ContextKind::InvalidValue, ContextValue::String(val)), 61519625d8cSopenharmony_ci ]); 61619625d8cSopenharmony_ci } 61719625d8cSopenharmony_ci 61819625d8cSopenharmony_ci err 61919625d8cSopenharmony_ci } 62019625d8cSopenharmony_ci 62119625d8cSopenharmony_ci pub(crate) fn wrong_number_of_values( 62219625d8cSopenharmony_ci cmd: &Command, 62319625d8cSopenharmony_ci arg: String, 62419625d8cSopenharmony_ci num_vals: usize, 62519625d8cSopenharmony_ci curr_vals: usize, 62619625d8cSopenharmony_ci usage: Option<StyledStr>, 62719625d8cSopenharmony_ci ) -> Self { 62819625d8cSopenharmony_ci let mut err = Self::new(ErrorKind::WrongNumberOfValues).with_cmd(cmd); 62919625d8cSopenharmony_ci 63019625d8cSopenharmony_ci #[cfg(feature = "error-context")] 63119625d8cSopenharmony_ci { 63219625d8cSopenharmony_ci err = err.extend_context_unchecked([ 63319625d8cSopenharmony_ci (ContextKind::InvalidArg, ContextValue::String(arg)), 63419625d8cSopenharmony_ci ( 63519625d8cSopenharmony_ci ContextKind::ExpectedNumValues, 63619625d8cSopenharmony_ci ContextValue::Number(num_vals as isize), 63719625d8cSopenharmony_ci ), 63819625d8cSopenharmony_ci ( 63919625d8cSopenharmony_ci ContextKind::ActualNumValues, 64019625d8cSopenharmony_ci ContextValue::Number(curr_vals as isize), 64119625d8cSopenharmony_ci ), 64219625d8cSopenharmony_ci ]); 64319625d8cSopenharmony_ci if let Some(usage) = usage { 64419625d8cSopenharmony_ci err = err 64519625d8cSopenharmony_ci .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage)); 64619625d8cSopenharmony_ci } 64719625d8cSopenharmony_ci } 64819625d8cSopenharmony_ci 64919625d8cSopenharmony_ci err 65019625d8cSopenharmony_ci } 65119625d8cSopenharmony_ci 65219625d8cSopenharmony_ci pub(crate) fn unknown_argument( 65319625d8cSopenharmony_ci cmd: &Command, 65419625d8cSopenharmony_ci arg: String, 65519625d8cSopenharmony_ci did_you_mean: Option<(String, Option<String>)>, 65619625d8cSopenharmony_ci suggested_trailing_arg: bool, 65719625d8cSopenharmony_ci usage: Option<StyledStr>, 65819625d8cSopenharmony_ci ) -> Self { 65919625d8cSopenharmony_ci let mut err = Self::new(ErrorKind::UnknownArgument).with_cmd(cmd); 66019625d8cSopenharmony_ci 66119625d8cSopenharmony_ci #[cfg(feature = "error-context")] 66219625d8cSopenharmony_ci { 66319625d8cSopenharmony_ci let mut suggestions = vec![]; 66419625d8cSopenharmony_ci if suggested_trailing_arg { 66519625d8cSopenharmony_ci let mut styled_suggestion = StyledStr::new(); 66619625d8cSopenharmony_ci styled_suggestion.none("to pass '"); 66719625d8cSopenharmony_ci styled_suggestion.warning(&arg); 66819625d8cSopenharmony_ci styled_suggestion.none("' as a value, use '"); 66919625d8cSopenharmony_ci styled_suggestion.good("-- "); 67019625d8cSopenharmony_ci styled_suggestion.good(&arg); 67119625d8cSopenharmony_ci styled_suggestion.none("'"); 67219625d8cSopenharmony_ci suggestions.push(styled_suggestion); 67319625d8cSopenharmony_ci } 67419625d8cSopenharmony_ci 67519625d8cSopenharmony_ci err = err 67619625d8cSopenharmony_ci .extend_context_unchecked([(ContextKind::InvalidArg, ContextValue::String(arg))]); 67719625d8cSopenharmony_ci if let Some(usage) = usage { 67819625d8cSopenharmony_ci err = err 67919625d8cSopenharmony_ci .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage)); 68019625d8cSopenharmony_ci } 68119625d8cSopenharmony_ci match did_you_mean { 68219625d8cSopenharmony_ci Some((flag, Some(sub))) => { 68319625d8cSopenharmony_ci let mut styled_suggestion = StyledStr::new(); 68419625d8cSopenharmony_ci styled_suggestion.none("'"); 68519625d8cSopenharmony_ci styled_suggestion.good(sub); 68619625d8cSopenharmony_ci styled_suggestion.none(" "); 68719625d8cSopenharmony_ci styled_suggestion.good("--"); 68819625d8cSopenharmony_ci styled_suggestion.good(flag); 68919625d8cSopenharmony_ci styled_suggestion.none("' exists"); 69019625d8cSopenharmony_ci suggestions.push(styled_suggestion); 69119625d8cSopenharmony_ci } 69219625d8cSopenharmony_ci Some((flag, None)) => { 69319625d8cSopenharmony_ci err = err.insert_context_unchecked( 69419625d8cSopenharmony_ci ContextKind::SuggestedArg, 69519625d8cSopenharmony_ci ContextValue::String(format!("--{flag}")), 69619625d8cSopenharmony_ci ); 69719625d8cSopenharmony_ci } 69819625d8cSopenharmony_ci None => {} 69919625d8cSopenharmony_ci } 70019625d8cSopenharmony_ci if !suggestions.is_empty() { 70119625d8cSopenharmony_ci err = err.insert_context_unchecked( 70219625d8cSopenharmony_ci ContextKind::Suggested, 70319625d8cSopenharmony_ci ContextValue::StyledStrs(suggestions), 70419625d8cSopenharmony_ci ); 70519625d8cSopenharmony_ci } 70619625d8cSopenharmony_ci } 70719625d8cSopenharmony_ci 70819625d8cSopenharmony_ci err 70919625d8cSopenharmony_ci } 71019625d8cSopenharmony_ci 71119625d8cSopenharmony_ci pub(crate) fn unnecessary_double_dash( 71219625d8cSopenharmony_ci cmd: &Command, 71319625d8cSopenharmony_ci arg: String, 71419625d8cSopenharmony_ci usage: Option<StyledStr>, 71519625d8cSopenharmony_ci ) -> Self { 71619625d8cSopenharmony_ci let mut err = Self::new(ErrorKind::UnknownArgument).with_cmd(cmd); 71719625d8cSopenharmony_ci 71819625d8cSopenharmony_ci #[cfg(feature = "error-context")] 71919625d8cSopenharmony_ci { 72019625d8cSopenharmony_ci let mut styled_suggestion = StyledStr::new(); 72119625d8cSopenharmony_ci styled_suggestion.none("subcommand '"); 72219625d8cSopenharmony_ci styled_suggestion.good(&arg); 72319625d8cSopenharmony_ci styled_suggestion.none("' exists; to use it, remove the '"); 72419625d8cSopenharmony_ci styled_suggestion.warning("--"); 72519625d8cSopenharmony_ci styled_suggestion.none("' before it"); 72619625d8cSopenharmony_ci 72719625d8cSopenharmony_ci err = err.extend_context_unchecked([ 72819625d8cSopenharmony_ci (ContextKind::InvalidArg, ContextValue::String(arg)), 72919625d8cSopenharmony_ci ( 73019625d8cSopenharmony_ci ContextKind::Suggested, 73119625d8cSopenharmony_ci ContextValue::StyledStrs(vec![styled_suggestion]), 73219625d8cSopenharmony_ci ), 73319625d8cSopenharmony_ci ]); 73419625d8cSopenharmony_ci if let Some(usage) = usage { 73519625d8cSopenharmony_ci err = err 73619625d8cSopenharmony_ci .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage)); 73719625d8cSopenharmony_ci } 73819625d8cSopenharmony_ci } 73919625d8cSopenharmony_ci 74019625d8cSopenharmony_ci err 74119625d8cSopenharmony_ci } 74219625d8cSopenharmony_ci 74319625d8cSopenharmony_ci fn formatted(&self) -> Cow<'_, StyledStr> { 74419625d8cSopenharmony_ci if let Some(message) = self.inner.message.as_ref() { 74519625d8cSopenharmony_ci message.formatted() 74619625d8cSopenharmony_ci } else { 74719625d8cSopenharmony_ci let styled = F::format_error(self); 74819625d8cSopenharmony_ci Cow::Owned(styled) 74919625d8cSopenharmony_ci } 75019625d8cSopenharmony_ci } 75119625d8cSopenharmony_ci} 75219625d8cSopenharmony_ci 75319625d8cSopenharmony_ciimpl<F: ErrorFormatter> From<io::Error> for Error<F> { 75419625d8cSopenharmony_ci fn from(e: io::Error) -> Self { 75519625d8cSopenharmony_ci Error::raw(ErrorKind::Io, e) 75619625d8cSopenharmony_ci } 75719625d8cSopenharmony_ci} 75819625d8cSopenharmony_ci 75919625d8cSopenharmony_ciimpl<F: ErrorFormatter> From<fmt::Error> for Error<F> { 76019625d8cSopenharmony_ci fn from(e: fmt::Error) -> Self { 76119625d8cSopenharmony_ci Error::raw(ErrorKind::Format, e) 76219625d8cSopenharmony_ci } 76319625d8cSopenharmony_ci} 76419625d8cSopenharmony_ci 76519625d8cSopenharmony_ciimpl<F: ErrorFormatter> std::fmt::Debug for Error<F> { 76619625d8cSopenharmony_ci fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { 76719625d8cSopenharmony_ci self.inner.fmt(f) 76819625d8cSopenharmony_ci } 76919625d8cSopenharmony_ci} 77019625d8cSopenharmony_ci 77119625d8cSopenharmony_ciimpl<F: ErrorFormatter> error::Error for Error<F> { 77219625d8cSopenharmony_ci #[allow(trivial_casts)] 77319625d8cSopenharmony_ci fn source(&self) -> Option<&(dyn error::Error + 'static)> { 77419625d8cSopenharmony_ci self.inner.source.as_ref().map(|e| e.as_ref() as _) 77519625d8cSopenharmony_ci } 77619625d8cSopenharmony_ci} 77719625d8cSopenharmony_ci 77819625d8cSopenharmony_ciimpl<F: ErrorFormatter> Display for Error<F> { 77919625d8cSopenharmony_ci fn fmt(&self, f: &mut Formatter) -> fmt::Result { 78019625d8cSopenharmony_ci // Assuming `self.message` already has a trailing newline, from `try_help` or similar 78119625d8cSopenharmony_ci ok!(write!(f, "{}", self.formatted())); 78219625d8cSopenharmony_ci if let Some(backtrace) = self.inner.backtrace.as_ref() { 78319625d8cSopenharmony_ci ok!(writeln!(f)); 78419625d8cSopenharmony_ci ok!(writeln!(f, "Backtrace:")); 78519625d8cSopenharmony_ci ok!(writeln!(f, "{backtrace}")); 78619625d8cSopenharmony_ci } 78719625d8cSopenharmony_ci Ok(()) 78819625d8cSopenharmony_ci } 78919625d8cSopenharmony_ci} 79019625d8cSopenharmony_ci 79119625d8cSopenharmony_ci#[derive(Clone, Debug)] 79219625d8cSopenharmony_cipub(crate) enum Message { 79319625d8cSopenharmony_ci Raw(String), 79419625d8cSopenharmony_ci Formatted(StyledStr), 79519625d8cSopenharmony_ci} 79619625d8cSopenharmony_ci 79719625d8cSopenharmony_ciimpl Message { 79819625d8cSopenharmony_ci fn format(&mut self, cmd: &Command, usage: Option<StyledStr>) { 79919625d8cSopenharmony_ci match self { 80019625d8cSopenharmony_ci Message::Raw(s) => { 80119625d8cSopenharmony_ci let mut message = String::new(); 80219625d8cSopenharmony_ci std::mem::swap(s, &mut message); 80319625d8cSopenharmony_ci 80419625d8cSopenharmony_ci let styled = format::format_error_message(&message, Some(cmd), usage); 80519625d8cSopenharmony_ci 80619625d8cSopenharmony_ci *self = Self::Formatted(styled); 80719625d8cSopenharmony_ci } 80819625d8cSopenharmony_ci Message::Formatted(_) => {} 80919625d8cSopenharmony_ci } 81019625d8cSopenharmony_ci } 81119625d8cSopenharmony_ci 81219625d8cSopenharmony_ci fn formatted(&self) -> Cow<StyledStr> { 81319625d8cSopenharmony_ci match self { 81419625d8cSopenharmony_ci Message::Raw(s) => { 81519625d8cSopenharmony_ci let styled = format::format_error_message(s, None, None); 81619625d8cSopenharmony_ci 81719625d8cSopenharmony_ci Cow::Owned(styled) 81819625d8cSopenharmony_ci } 81919625d8cSopenharmony_ci Message::Formatted(s) => Cow::Borrowed(s), 82019625d8cSopenharmony_ci } 82119625d8cSopenharmony_ci } 82219625d8cSopenharmony_ci} 82319625d8cSopenharmony_ci 82419625d8cSopenharmony_ciimpl From<String> for Message { 82519625d8cSopenharmony_ci fn from(inner: String) -> Self { 82619625d8cSopenharmony_ci Self::Raw(inner) 82719625d8cSopenharmony_ci } 82819625d8cSopenharmony_ci} 82919625d8cSopenharmony_ci 83019625d8cSopenharmony_ciimpl From<StyledStr> for Message { 83119625d8cSopenharmony_ci fn from(inner: StyledStr) -> Self { 83219625d8cSopenharmony_ci Self::Formatted(inner) 83319625d8cSopenharmony_ci } 83419625d8cSopenharmony_ci} 83519625d8cSopenharmony_ci 83619625d8cSopenharmony_ci#[cfg(feature = "debug")] 83719625d8cSopenharmony_ci#[derive(Debug)] 83819625d8cSopenharmony_cistruct Backtrace(backtrace::Backtrace); 83919625d8cSopenharmony_ci 84019625d8cSopenharmony_ci#[cfg(feature = "debug")] 84119625d8cSopenharmony_ciimpl Backtrace { 84219625d8cSopenharmony_ci fn new() -> Option<Self> { 84319625d8cSopenharmony_ci Some(Self(backtrace::Backtrace::new())) 84419625d8cSopenharmony_ci } 84519625d8cSopenharmony_ci} 84619625d8cSopenharmony_ci 84719625d8cSopenharmony_ci#[cfg(feature = "debug")] 84819625d8cSopenharmony_ciimpl Display for Backtrace { 84919625d8cSopenharmony_ci fn fmt(&self, f: &mut Formatter) -> fmt::Result { 85019625d8cSopenharmony_ci // `backtrace::Backtrace` uses `Debug` instead of `Display` 85119625d8cSopenharmony_ci write!(f, "{:?}", self.0) 85219625d8cSopenharmony_ci } 85319625d8cSopenharmony_ci} 85419625d8cSopenharmony_ci 85519625d8cSopenharmony_ci#[cfg(not(feature = "debug"))] 85619625d8cSopenharmony_ci#[derive(Debug)] 85719625d8cSopenharmony_cistruct Backtrace; 85819625d8cSopenharmony_ci 85919625d8cSopenharmony_ci#[cfg(not(feature = "debug"))] 86019625d8cSopenharmony_ciimpl Backtrace { 86119625d8cSopenharmony_ci fn new() -> Option<Self> { 86219625d8cSopenharmony_ci None 86319625d8cSopenharmony_ci } 86419625d8cSopenharmony_ci} 86519625d8cSopenharmony_ci 86619625d8cSopenharmony_ci#[cfg(not(feature = "debug"))] 86719625d8cSopenharmony_ciimpl Display for Backtrace { 86819625d8cSopenharmony_ci fn fmt(&self, _: &mut Formatter) -> fmt::Result { 86919625d8cSopenharmony_ci Ok(()) 87019625d8cSopenharmony_ci } 87119625d8cSopenharmony_ci} 87219625d8cSopenharmony_ci 87319625d8cSopenharmony_ci#[test] 87419625d8cSopenharmony_cifn check_auto_traits() { 87519625d8cSopenharmony_ci static_assertions::assert_impl_all!(Error: Send, Sync, Unpin); 87619625d8cSopenharmony_ci} 877