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