Skip to main content

cli_forge/
error.rs

1//! Parse errors.
2//!
3//! Every way command-line input can be malformed maps to a [`ParseError`]
4//! variant — never a panic. The error carries enough context to tell the user
5//! what was wrong (which flag, which argument), and it renders through the same
6//! output system as everything else: [`App::parse`](crate::App::parse) prints it
7//! to standard error and exits, while
8//! [`App::try_parse_from`](crate::App::try_parse_from) hands it back for the
9//! caller to handle.
10
11use std::error::Error;
12use std::fmt;
13
14/// A failure to parse command-line arguments.
15///
16/// Returned by [`App::try_parse_from`](crate::App::try_parse_from). The variants
17/// are marked `#[non_exhaustive]` so future versions can add cases (for example,
18/// as the help and auth seams land) without a breaking change.
19#[derive(Debug, Clone, PartialEq, Eq)]
20#[non_exhaustive]
21pub enum ParseError {
22    /// A `-x` / `--name` flag was given that no argument at this level declares.
23    UnknownFlag {
24        /// The flag as the user wrote it, e.g. `--verbsoe`.
25        flag: String,
26    },
27    /// An option that takes a value was given without one (it was the last
28    /// token, or followed only by another option).
29    MissingValue {
30        /// The option's name.
31        option: String,
32    },
33    /// A required argument was not provided.
34    MissingRequired {
35        /// The missing argument's name.
36        arg: String,
37    },
38    /// A subcommand name was expected but the token matched no registered
39    /// command.
40    UnknownCommand {
41        /// The unrecognized command name.
42        name: String,
43    },
44    /// A bare value was given that no positional argument or subcommand can
45    /// accept.
46    UnexpectedArgument {
47        /// The surplus value.
48        value: String,
49    },
50    /// Not an error: `-h` / `--help` was requested. Carries the rendered help
51    /// text. [`App::parse`](crate::App::parse) prints it to standard output and
52    /// exits `0`; callers of
53    /// [`App::try_parse_from`](crate::App::try_parse_from) should do the same.
54    HelpRequested(String),
55    /// Not an error: `-V` / `--version` was requested. Carries the version
56    /// string. Handled like [`HelpRequested`](ParseError::HelpRequested).
57    VersionRequested(String),
58}
59
60impl fmt::Display for ParseError {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        match self {
63            ParseError::UnknownFlag { flag } => write!(f, "unknown flag: {flag}"),
64            ParseError::MissingValue { option } => {
65                write!(f, "missing value for option: {option}")
66            }
67            ParseError::MissingRequired { arg } => {
68                write!(f, "missing required argument: {arg}")
69            }
70            ParseError::UnknownCommand { name } => write!(f, "unknown command: {name}"),
71            ParseError::UnexpectedArgument { value } => {
72                write!(f, "unexpected argument: {value}")
73            }
74            ParseError::HelpRequested(text) | ParseError::VersionRequested(text) => {
75                write!(f, "{text}")
76            }
77        }
78    }
79}
80
81impl Error for ParseError {}