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