1use miette::{Diagnostic, NamedSource, SourceSpan};
2use thiserror::Error;
3
4#[derive(Error, Diagnostic, Debug)]
11#[non_exhaustive]
12pub enum UsageErr {
13 #[error("Invalid flag `{token}`: {reason}")]
14 InvalidFlag {
15 token: String,
16 reason: String,
17 #[label("{reason}")]
18 span: SourceSpan,
19 #[source_code]
20 input: String,
21 },
22
23 #[error("Missing required flag: --{0} <{0}>")]
24 MissingFlag(String),
25
26 #[error("Flag --{0} cannot be used multiple times")]
27 DuplicateFlag(String),
28
29 #[error("Missing one of the required flags in group {group}: {members}")]
35 MissingGroup { group: String, members: String },
36
37 #[error("Invalid usage config")]
38 InvalidInput(
39 String,
40 #[label = "{0}"] SourceSpan,
41 #[source_code] NamedSource<String>,
42 ),
43
44 #[error("Missing required arg: <{0}>")]
45 MissingArg(String),
46
47 #[error("`{0}` needs a subcommand: one of {1}")]
53 MissingSubcommand(String, String),
54
55 #[error("Argument <{0}> can only be set after a `--` separator")]
56 ArgRequiresDoubleDash(String),
57
58 #[error("{0}")]
59 Help(String),
60
61 #[error("{0}")]
62 Version(String),
63
64 #[error("Invalid usage config")]
65 #[diagnostic(transparent)]
66 Miette(#[from] miette::MietteError),
67
68 #[error(transparent)]
69 IO(#[from] std::io::Error),
70
71 #[error(transparent)]
72 Strum(#[from] strum::ParseError),
73
74 #[error(transparent)]
75 FromUtf8Error(#[from] std::string::FromUtf8Error),
76
77 #[cfg(feature = "tera")]
78 #[error(transparent)]
79 TeraError(#[from] tera::Error),
80
81 #[error(transparent)]
82 #[diagnostic(transparent)]
83 KdlError(#[from] kdl::KdlError),
84
85 #[error("{0}\nFile: {1}")]
90 #[diagnostic(code(usage::file))]
91 FileError(std::io::Error, std::path::PathBuf),
92
93 #[error("{0}")]
96 #[diagnostic(code(usage::shell))]
97 ShellError(String),
98
99 #[error("Variadic argument <{name}> requires at least {min} value(s), got {got}")]
100 VarArgTooFew {
101 name: String,
102 min: usize,
103 got: usize,
104 },
105
106 #[error("Variadic argument <{name}> accepts at most {max} value(s), got {got}")]
107 VarArgTooMany {
108 name: String,
109 max: usize,
110 got: usize,
111 },
112
113 #[error("Variadic flag --{name} requires at least {min} value(s), got {got}")]
114 VarFlagTooFew {
115 name: String,
116 min: usize,
117 got: usize,
118 },
119
120 #[error("Variadic flag --{name} accepts at most {max} value(s), got {got}")]
121 VarFlagTooMany {
122 name: String,
123 max: usize,
124 got: usize,
125 },
126
127 #[error("Invalid file path: {0}")]
128 InvalidPath(String),
129
130 #[error("Invalid spec view: {0}")]
131 InvalidView(String),
132
133 #[error("Invalid value for {name}: {value}: {reason}")]
134 InvalidValue {
135 name: String,
136 value: String,
137 reason: String,
138 },
139
140 #[error("Unsupported shell: {0}")]
141 UnsupportedShell(String),
142
143 #[error("No injected output was provided for mount command: {0}")]
144 MissingMountOutput(String),
145}
146pub type Result<T> = std::result::Result<T, UsageErr>;
147
148#[macro_export]
149macro_rules! bail_parse {
150 ($ctx:expr, $span:expr, $fmt:literal) => {{
151 let span: miette::SourceSpan = ($span.offset(), $span.len()).into();
152 let msg = format!($fmt);
153 let err = $ctx.build_err(msg, span);
154 return std::result::Result::Err(err);
155 }};
156 ($ctx:expr, $span:expr, $fmt:literal, $($arg:tt)*) => {{
157 let span: miette::SourceSpan = ($span.offset(), $span.len()).into();
158 let msg = format!($fmt, $($arg)*);
159 let err = $ctx.build_err(msg, span);
160 return std::result::Result::Err(err);
161 }};
162}