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