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 /// An auth-gated command ([`Command::requires_auth`](crate::Command::requires_auth))
59 /// was invoked but the app's auth hook did not authorize it (or no hook was
60 /// set). Produced only with the `auth` feature enabled; the command's handler
61 /// does not run.
62 Unauthorized {
63 /// The command that was refused.
64 command: String,
65 },
66}
67
68impl fmt::Display for ParseError {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 match self {
71 ParseError::UnknownFlag { flag } => write!(f, "unknown flag: {flag}"),
72 ParseError::MissingValue { option } => {
73 write!(f, "missing value for option: {option}")
74 }
75 ParseError::MissingRequired { arg } => {
76 write!(f, "missing required argument: {arg}")
77 }
78 ParseError::UnknownCommand { name } => write!(f, "unknown command: {name}"),
79 ParseError::UnexpectedArgument { value } => {
80 write!(f, "unexpected argument: {value}")
81 }
82 ParseError::HelpRequested(text) | ParseError::VersionRequested(text) => {
83 write!(f, "{text}")
84 }
85 ParseError::Unauthorized { command } => {
86 write!(f, "not authorized to run: {command}")
87 }
88 }
89 }
90}
91
92impl Error for ParseError {}