1use std::fmt;
2
3#[derive(Clone, Debug, PartialEq, Eq)]
4pub struct CliSpec {
5 name: String,
6 about: String,
7 version: Option<String>,
8 commands: Vec<CommandSpec>,
9 options: Vec<OptionSpec>,
10 arguments: Vec<ArgumentSpec>,
11 command_required: bool,
12}
13
14#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct CommandSpec {
16 name: String,
17 aliases: Vec<String>,
18 about: String,
19 commands: Vec<CommandSpec>,
20 options: Vec<OptionSpec>,
21 arguments: Vec<ArgumentSpec>,
22 command_required: bool,
23 hidden: bool,
24}
25
26#[derive(Clone, Debug, PartialEq, Eq)]
27pub struct OptionSpec {
28 long: String,
29 short: Option<char>,
30 value: ValueMode,
31 value_name: String,
32 value_type: ValueType,
33 possible_values: Vec<String>,
34 about: String,
35 required: bool,
36 repeatable: bool,
37 terminal: bool,
38 hidden: bool,
39 conflicts_with: Vec<String>,
40 requires: Vec<String>,
41}
42
43#[derive(Clone, Debug, PartialEq, Eq)]
44pub struct ArgumentSpec {
45 name: String,
46 about: String,
47 value_type: ValueType,
48 possible_values: Vec<String>,
49 required: bool,
50 multiple: bool,
51}
52
53#[derive(Clone, Copy, Debug, PartialEq, Eq)]
54pub enum ValueMode {
55 Forbidden,
56 Required,
57 Optional,
58}
59
60#[derive(Clone, Copy, Debug, PartialEq, Eq)]
61pub enum ValueType {
62 String,
63 Bool,
64 I64,
65 U64,
66}
67
68#[derive(Clone, Debug, PartialEq, Eq)]
69pub struct SpecError {
70 message: String,
71}
72
73impl CliSpec {
74 pub fn new(name: impl Into<String>) -> Self {
75 Self {
76 name: name.into(),
77 about: String::new(),
78 version: None,
79 commands: Vec::new(),
80 options: Vec::new(),
81 arguments: Vec::new(),
82 command_required: false,
83 }
84 }
85 pub fn about(mut self, about: impl Into<String>) -> Self {
86 self.about = about.into();
87 self
88 }
89 pub fn version(mut self, version: impl Into<String>) -> Self {
90 self.version = Some(version.into());
91 self
92 }
93 pub fn command(mut self, command: CommandSpec) -> Self {
94 self.commands.push(command);
95 self
96 }
97 pub fn option(mut self, option: OptionSpec) -> Self {
98 self.options.push(option);
99 self
100 }
101 pub fn argument(mut self, argument: ArgumentSpec) -> Self {
102 self.arguments.push(argument);
103 self
104 }
105 pub fn command_required(mut self, required: bool) -> Self {
106 self.command_required = required;
107 self
108 }
109 pub fn validate(&self) -> Result<(), SpecError> {
110 crate::spec_validation::validate_spec(self)
111 }
112 pub fn name(&self) -> &str {
113 &self.name
114 }
115 pub fn about_text(&self) -> &str {
116 &self.about
117 }
118 pub fn version_text(&self) -> Option<&str> {
119 self.version.as_deref()
120 }
121 pub fn commands(&self) -> &[CommandSpec] {
122 &self.commands
123 }
124 pub fn options(&self) -> &[OptionSpec] {
125 &self.options
126 }
127 pub fn arguments(&self) -> &[ArgumentSpec] {
128 &self.arguments
129 }
130 pub fn is_command_required(&self) -> bool {
131 self.command_required
132 }
133}
134
135impl CommandSpec {
136 pub fn new(name: impl Into<String>) -> Self {
137 Self {
138 name: name.into(),
139 aliases: Vec::new(),
140 about: String::new(),
141 commands: Vec::new(),
142 options: Vec::new(),
143 arguments: Vec::new(),
144 command_required: false,
145 hidden: false,
146 }
147 }
148 pub fn alias(mut self, alias: impl Into<String>) -> Self {
149 self.aliases.push(alias.into());
150 self
151 }
152 pub fn about(mut self, about: impl Into<String>) -> Self {
153 self.about = about.into();
154 self
155 }
156 pub fn command(mut self, command: CommandSpec) -> Self {
157 self.commands.push(command);
158 self
159 }
160 pub fn option(mut self, option: OptionSpec) -> Self {
161 self.options.push(option);
162 self
163 }
164 pub fn argument(mut self, argument: ArgumentSpec) -> Self {
165 self.arguments.push(argument);
166 self
167 }
168 pub fn command_required(mut self, required: bool) -> Self {
169 self.command_required = required;
170 self
171 }
172 pub fn hidden(mut self, hidden: bool) -> Self {
173 self.hidden = hidden;
174 self
175 }
176 pub fn name(&self) -> &str {
177 &self.name
178 }
179 pub fn aliases(&self) -> &[String] {
180 &self.aliases
181 }
182 pub fn matches(&self, value: &str) -> bool {
183 self.name == value || self.aliases.iter().any(|alias| alias == value)
184 }
185 pub fn about_text(&self) -> &str {
186 &self.about
187 }
188 pub fn commands(&self) -> &[CommandSpec] {
189 &self.commands
190 }
191 pub fn options(&self) -> &[OptionSpec] {
192 &self.options
193 }
194 pub fn arguments(&self) -> &[ArgumentSpec] {
195 &self.arguments
196 }
197 pub fn is_command_required(&self) -> bool {
198 self.command_required
199 }
200 pub fn is_hidden(&self) -> bool {
201 self.hidden
202 }
203}
204
205impl OptionSpec {
206 pub fn flag(long: impl Into<String>) -> Self {
207 Self::new(long, ValueMode::Forbidden)
208 }
209 pub fn value(long: impl Into<String>) -> Self {
210 Self::new(long, ValueMode::Required)
211 }
212 fn new(long: impl Into<String>, value: ValueMode) -> Self {
213 Self {
214 long: long.into(),
215 short: None,
216 value,
217 value_name: "VALUE".into(),
218 value_type: ValueType::String,
219 possible_values: Vec::new(),
220 about: String::new(),
221 required: false,
222 repeatable: false,
223 terminal: false,
224 hidden: false,
225 conflicts_with: Vec::new(),
226 requires: Vec::new(),
227 }
228 }
229 pub fn short(mut self, short: char) -> Self {
230 self.short = Some(short);
231 self
232 }
233 pub fn optional_value(mut self) -> Self {
234 self.value = ValueMode::Optional;
235 self
236 }
237 pub fn value_name(mut self, name: impl Into<String>) -> Self {
238 self.value_name = name.into();
239 self
240 }
241 pub fn value_type(mut self, value_type: ValueType) -> Self {
242 self.value_type = value_type;
243 self
244 }
245 pub fn possible_value(mut self, value: impl Into<String>) -> Self {
246 self.possible_values.push(value.into());
247 self
248 }
249 pub fn about(mut self, about: impl Into<String>) -> Self {
250 self.about = about.into();
251 self
252 }
253 pub fn required(mut self, required: bool) -> Self {
254 self.required = required;
255 self
256 }
257 pub fn repeatable(mut self, repeatable: bool) -> Self {
258 self.repeatable = repeatable;
259 self
260 }
261 pub fn terminal(mut self, terminal: bool) -> Self {
262 self.terminal = terminal;
263 self
264 }
265 pub fn hidden(mut self, hidden: bool) -> Self {
266 self.hidden = hidden;
267 self
268 }
269 pub fn conflicts_with(mut self, long: impl Into<String>) -> Self {
270 self.conflicts_with.push(long.into());
271 self
272 }
273 pub fn requires(mut self, long: impl Into<String>) -> Self {
274 self.requires.push(long.into());
275 self
276 }
277 pub fn long(&self) -> &str {
278 &self.long
279 }
280 pub fn short_name(&self) -> Option<char> {
281 self.short
282 }
283 pub fn value_mode(&self) -> ValueMode {
284 self.value
285 }
286 pub fn value_name_text(&self) -> &str {
287 &self.value_name
288 }
289 pub fn value_type_kind(&self) -> ValueType {
290 self.value_type
291 }
292 pub fn possible_values(&self) -> &[String] {
293 &self.possible_values
294 }
295 pub fn about_text(&self) -> &str {
296 &self.about
297 }
298 pub fn is_required(&self) -> bool {
299 self.required
300 }
301 pub fn is_repeatable(&self) -> bool {
302 self.repeatable
303 }
304 pub fn is_terminal(&self) -> bool {
305 self.terminal
306 }
307 pub fn is_hidden(&self) -> bool {
308 self.hidden
309 }
310 pub fn conflicts(&self) -> &[String] {
311 &self.conflicts_with
312 }
313 pub fn requirements(&self) -> &[String] {
314 &self.requires
315 }
316}
317
318impl ArgumentSpec {
319 pub fn new(name: impl Into<String>) -> Self {
320 Self {
321 name: name.into(),
322 about: String::new(),
323 value_type: ValueType::String,
324 possible_values: Vec::new(),
325 required: false,
326 multiple: false,
327 }
328 }
329 pub fn about(mut self, about: impl Into<String>) -> Self {
330 self.about = about.into();
331 self
332 }
333 pub fn value_type(mut self, value_type: ValueType) -> Self {
334 self.value_type = value_type;
335 self
336 }
337 pub fn possible_value(mut self, value: impl Into<String>) -> Self {
338 self.possible_values.push(value.into());
339 self
340 }
341 pub fn required(mut self, required: bool) -> Self {
342 self.required = required;
343 self
344 }
345 pub fn multiple(mut self, multiple: bool) -> Self {
346 self.multiple = multiple;
347 self
348 }
349 pub fn name(&self) -> &str {
350 &self.name
351 }
352 pub fn about_text(&self) -> &str {
353 &self.about
354 }
355 pub fn value_type_kind(&self) -> ValueType {
356 self.value_type
357 }
358 pub fn possible_values(&self) -> &[String] {
359 &self.possible_values
360 }
361 pub fn is_required(&self) -> bool {
362 self.required
363 }
364 pub fn is_multiple(&self) -> bool {
365 self.multiple
366 }
367}
368
369impl SpecError {
370 fn new(message: impl Into<String>) -> Self {
371 Self {
372 message: message.into(),
373 }
374 }
375 pub(crate) fn new_internal(message: impl Into<String>) -> Self {
376 Self::new(message)
377 }
378}
379impl fmt::Display for SpecError {
380 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
381 f.write_str(&self.message)
382 }
383}
384impl std::error::Error for SpecError {}