1use std::ffi::{OsStr, OsString};
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq)]
5pub enum ColorMode {
6 Auto,
7 Always,
8 Never,
9}
10
11#[derive(Clone, Copy, Debug)]
13pub struct Env {
14 pub wrap_cols: usize,
16 pub color: ColorMode,
18 pub suggest: bool,
20 pub auto_help: bool,
22 pub version: Option<&'static str>,
23 pub author: Option<&'static str>,
24}
25impl Default for Env {
26 fn default() -> Self {
27 Self { wrap_cols: 0, color: ColorMode::Auto, suggest: true, auto_help: true, version: None, author: None }
28 }
29}
30
31#[derive(Clone, Copy, Debug, PartialEq, Eq)]
33pub enum Repeat {
34 Single,
35 Many,
36}
37
38#[derive(Clone, Copy, Debug, PartialEq, Eq)]
40pub enum GroupMode {
41 Xor,
42 ReqOne,
43}
44
45#[derive(Clone, Copy, Debug, PartialEq, Eq)]
47pub enum Source {
48 Cli,
49 Env,
50 Default,
51}
52
53pub type ValueValidatorFn<'a> = dyn Fn(&OsStr) -> crate::Result<()> + 'a;
58
59pub type CmdValidatorFn<'a> = dyn Fn(&crate::Matches) -> crate::Result<()> + 'a;
61
62pub type CmdHandlerFn<'a, Ctx> = dyn Fn(&crate::Matches, &mut Ctx) -> crate::Result<()> + 'a;
64
65pub type OnValueFn<'a, Ctx> = dyn Fn(&OsStr, &mut Ctx) -> crate::Result<()> + 'a;
67pub type OnFlagFn<'a, Ctx> = dyn Fn(&mut Ctx) -> crate::Result<()> + 'a;
68
69pub struct OptSpec<'a, Ctx: ?Sized> {
71 name: &'a str,
72 short: Option<char>,
73 long: Option<&'a str>,
74 metavar: Option<&'a str>,
75 help: Option<&'a str>,
76 env: Option<&'a str>,
77 default: Option<OsString>,
78 group: Option<&'a str>,
79 repeat: Repeat,
80 takes_value: bool,
81 on_value: Option<Box<OnValueFn<'a, Ctx>>>, on_flag: Option<Box<OnFlagFn<'a, Ctx>>>, validator: Option<Box<ValueValidatorFn<'a>>>,
84}
85
86impl<'a, Ctx: ?Sized> OptSpec<'a, Ctx> {
87 pub fn flag<F>(name: &'a str, cb: F) -> Self
89 where
90 F: Fn(&mut Ctx) + 'a,
91 {
92 Self {
93 name,
94 short: None,
95 long: None,
96 metavar: None,
97 help: None,
98 env: None,
99 default: None,
100 group: None,
101 repeat: Repeat::Single,
102 takes_value: false,
103 on_value: None,
104 on_flag: Some(Box::new(move |ctx| {
105 cb(ctx);
106 Ok(())
107 })),
108 validator: None,
109 }
110 }
111
112 pub fn flag_try<F, E>(name: &'a str, cb: F) -> Self
114 where
115 F: Fn(&mut Ctx) -> core::result::Result<(), E> + 'a,
116 E: std::error::Error + Send + Sync + 'static,
117 {
118 Self {
119 name,
120 short: None,
121 long: None,
122 metavar: None,
123 help: None,
124 env: None,
125 default: None,
126 group: None,
127 repeat: Repeat::Single,
128 takes_value: false,
129 on_value: None,
130 on_flag: Some(Box::new(move |ctx| cb(ctx).map_err(crate::Error::user))),
131 validator: None,
132 }
133 }
134
135 pub fn value<F>(name: &'a str, cb: F) -> Self
137 where
138 F: Fn(&OsStr, &mut Ctx) + 'a,
139 {
140 Self {
141 name,
142 short: None,
143 long: None,
144 metavar: None,
145 help: None,
146 env: None,
147 default: None,
148 group: None,
149 repeat: Repeat::Single,
150 takes_value: true,
151 on_value: Some(Box::new(move |v, ctx| {
152 cb(v, ctx);
153 Ok(())
154 })),
155 on_flag: None,
156 validator: None,
157 }
158 }
159
160 pub fn value_try<F, E>(name: &'a str, cb: F) -> Self
162 where
163 F: Fn(&OsStr, &mut Ctx) -> core::result::Result<(), E> + 'a,
164 E: std::error::Error + Send + Sync + 'static,
165 {
166 Self {
167 name,
168 short: None,
169 long: None,
170 metavar: None,
171 help: None,
172 env: None,
173 default: None,
174 group: None,
175 repeat: Repeat::Single,
176 takes_value: true,
177 on_value: Some(Box::new(move |v, ctx| cb(v, ctx).map_err(crate::Error::user))),
178 on_flag: None,
179 validator: None,
180 }
181 }
182
183 #[must_use]
185 pub fn short(mut self, s: char) -> Self {
186 self.short = Some(s);
187 self
188 }
189 #[must_use]
190 pub fn long(mut self, l: &'a str) -> Self {
191 self.long = Some(l);
192 self
193 }
194 #[must_use]
195 pub fn metavar(mut self, mv: &'a str) -> Self {
196 self.metavar = Some(mv);
197 self
198 }
199 #[must_use]
200 pub fn help(mut self, h: &'a str) -> Self {
201 self.help = Some(h);
202 self
203 }
204 #[must_use]
205 pub fn env(mut self, name: &'a str) -> Self {
206 self.env = Some(name);
207 self
208 }
209 #[must_use]
210 pub fn default(mut self, val: impl Into<OsString>) -> Self {
211 self.default = Some(val.into());
212 self
213 }
214 #[must_use]
215 pub fn group(mut self, g: &'a str) -> Self {
216 self.group = Some(g);
217 self
218 }
219 #[must_use]
220 pub fn single(mut self) -> Self {
221 self.repeat = Repeat::Single;
222 self
223 }
224 #[must_use]
225 pub fn repeatable(mut self) -> Self {
226 self.repeat = Repeat::Many;
227 self
228 }
229
230 #[must_use]
232 pub fn validator<F, E>(mut self, v: F) -> Self
233 where
234 F: Fn(&OsStr) -> core::result::Result<(), E> + 'a,
235 E: core::fmt::Display,
236 {
237 self.validator = Some(Box::new(move |s| v(s).map_err(|e| crate::Error::User(e.to_string()))));
238 self
239 }
240
241 #[must_use]
243 pub fn validator_try<F, E>(mut self, v: F) -> Self
244 where
245 F: Fn(&OsStr) -> core::result::Result<(), E> + 'a,
246 E: std::error::Error + Send + Sync + 'static,
247 {
248 self.validator = Some(Box::new(move |s| v(s).map_err(crate::Error::user)));
249 self
250 }
251
252 #[must_use]
254 pub fn get_name(&self) -> &str {
255 self.name
256 }
257 #[must_use]
258 pub fn get_short(&self) -> Option<char> {
259 self.short
260 }
261 #[must_use]
262 pub fn get_long(&self) -> Option<&str> {
263 self.long
264 }
265 #[must_use]
266 pub fn get_metavar(&self) -> Option<&str> {
267 self.metavar
268 }
269 #[must_use]
270 pub fn get_help(&self) -> Option<&str> {
271 self.help
272 }
273 #[must_use]
274 pub fn get_env(&self) -> Option<&str> {
275 self.env
276 }
277 #[must_use]
278 pub fn get_default(&self) -> Option<&OsString> {
279 self.default.as_ref()
280 }
281 #[must_use]
282 pub fn get_group(&self) -> Option<&str> {
283 self.group
284 }
285 #[must_use]
286 pub fn is_value(&self) -> bool {
287 self.takes_value
288 }
289 #[must_use]
290 pub fn get_repeat(&self) -> Repeat {
291 self.repeat
292 }
293 #[must_use]
294 pub fn get_on_value(&self) -> Option<&OnValueFn<'a, Ctx>> {
295 self.on_value.as_deref()
296 }
297 #[must_use]
298 pub fn get_on_flag(&self) -> Option<&OnFlagFn<'a, Ctx>> {
299 self.on_flag.as_deref()
300 }
301 #[must_use]
302 pub fn get_validator(&self) -> Option<&ValueValidatorFn<'a>> {
303 self.validator.as_deref()
304 }
305}
306
307#[derive(Clone, Copy, Debug, PartialEq, Eq)]
309pub enum PosCardinality {
310 One { required: bool },
311 Many,
312 Range { min: usize, max: usize },
313}
314
315pub struct PosSpec<'a, Ctx: ?Sized> {
317 name: &'a str,
318 help: Option<&'a str>,
319 card: PosCardinality,
320 on_value: Box<OnValueFn<'a, Ctx>>,
321 validator: Option<Box<ValueValidatorFn<'a>>>,
322}
323impl<'a, Ctx: ?Sized> PosSpec<'a, Ctx> {
324 pub fn new<F>(name: &'a str, cb: F) -> Self
325 where
326 F: Fn(&OsStr, &mut Ctx) + 'a,
327 {
328 Self {
329 name,
330 help: None,
331 card: PosCardinality::One { required: false },
332 on_value: Box::new(move |v, ctx| {
333 cb(v, ctx);
334 Ok(())
335 }),
336 validator: None,
337 }
338 }
339
340 pub fn new_try<F, E>(name: &'a str, cb: F) -> Self
341 where
342 F: Fn(&OsStr, &mut Ctx) -> core::result::Result<(), E> + 'a,
343 E: std::error::Error + Send + Sync + 'static,
344 {
345 Self {
346 name,
347 help: None,
348 card: PosCardinality::One { required: false },
349 on_value: Box::new(move |v, ctx| cb(v, ctx).map_err(crate::Error::user)),
350 validator: None,
351 }
352 }
353
354 #[must_use]
356 pub fn help(mut self, h: &'a str) -> Self {
357 self.help = Some(h);
358 self
359 }
360 #[must_use]
361 pub fn required(mut self) -> Self {
362 self.card = PosCardinality::One { required: true };
363 self
364 }
365 #[must_use]
366 pub fn many(mut self) -> Self {
367 self.card = PosCardinality::Many;
368 self
369 }
370 #[must_use]
371 pub fn range(mut self, min: usize, max: usize) -> Self {
372 self.card = PosCardinality::Range { min, max };
373 self
374 }
375
376 #[must_use]
378 pub fn validator<F, E>(mut self, v: F) -> Self
379 where
380 F: Fn(&OsStr) -> core::result::Result<(), E> + 'a,
381 E: core::fmt::Display,
382 {
383 self.validator = Some(Box::new(move |s| v(s).map_err(|e| crate::Error::User(e.to_string()))));
384 self
385 }
386
387 #[must_use]
389 pub fn validator_try<F, E>(mut self, v: F) -> Self
390 where
391 F: Fn(&OsStr) -> core::result::Result<(), E> + 'a,
392 E: std::error::Error + Send + Sync + 'static,
393 {
394 self.validator = Some(Box::new(move |s| v(s).map_err(crate::Error::user)));
395 self
396 }
397
398 #[must_use]
400 pub fn get_name(&self) -> &str {
401 self.name
402 }
403 #[must_use]
404 pub fn get_help(&self) -> Option<&str> {
405 self.help
406 }
407 #[must_use]
408 pub fn get_cardinality(&self) -> PosCardinality {
409 self.card
410 }
411 #[must_use]
412 pub fn is_required(&self) -> bool {
413 matches!(self.card, PosCardinality::One { required: true })
414 || matches!(self.card, PosCardinality::Range { min, .. } if min > 0)
415 }
416 #[must_use]
417 pub fn is_multiple(&self) -> bool {
418 !matches!(self.card, PosCardinality::One { .. })
419 }
420 pub fn get_on_value(&self) -> &OnValueFn<'a, Ctx> {
421 &*self.on_value
422 }
423 #[must_use]
424 pub fn get_validator(&self) -> Option<&ValueValidatorFn<'a>> {
425 self.validator.as_deref()
426 }
427}
428
429pub struct GroupDecl<'a> {
431 pub name: &'a str,
432 pub mode: GroupMode,
433}
434
435pub struct CmdSpec<'a, Ctx: ?Sized> {
437 name: &'a str,
438 help: Option<&'a str>,
439 aliases: Vec<&'a str>,
440 opts: Vec<OptSpec<'a, Ctx>>,
441 positionals: Vec<PosSpec<'a, Ctx>>,
442 subcommands: Vec<CmdSpec<'a, Ctx>>,
443 groups: Vec<GroupDecl<'a>>,
444 validate_cmd: Option<Box<CmdValidatorFn<'a>>>,
445 handler: Option<Box<CmdHandlerFn<'a, Ctx>>>, }
447impl<'a, Ctx: ?Sized> CmdSpec<'a, Ctx> {
448 #[must_use]
449 pub fn new(name: &'a str) -> Self {
450 Self {
451 name,
452 help: None,
453 aliases: Vec::new(),
454 opts: Vec::new(),
455 positionals: Vec::new(),
456 subcommands: Vec::new(),
457 groups: Vec::new(),
458 validate_cmd: None,
459 handler: None,
460 }
461 }
462 #[must_use]
464 pub fn help(mut self, s: &'a str) -> Self {
465 self.help = Some(s);
466 self
467 }
468 #[must_use]
469 pub fn alias(mut self, a: &'a str) -> Self {
470 self.aliases.push(a);
471 self
472 }
473 #[must_use]
474 pub fn opt(mut self, o: OptSpec<'a, Ctx>) -> Self {
475 self.opts.push(o);
476 self
477 }
478 #[must_use]
479 pub fn pos(mut self, p: PosSpec<'a, Ctx>) -> Self {
480 self.positionals.push(p);
481 self
482 }
483 #[must_use]
484 pub fn subcmd(mut self, c: Self) -> Self {
485 self.subcommands.push(c);
486 self
487 }
488 #[must_use]
489 pub fn group(mut self, name: &'a str, mode: GroupMode) -> Self {
490 self.groups.push(GroupDecl { name, mode });
491 self
492 }
493
494 #[must_use]
496 pub fn validator<F, E>(mut self, cb: F) -> Self
497 where
498 F: Fn(&crate::Matches) -> core::result::Result<(), E> + 'a,
499 E: core::fmt::Display,
500 {
501 self.validate_cmd = Some(Box::new(move |m| cb(m).map_err(|e| crate::Error::User(e.to_string()))));
502 self
503 }
504
505 #[must_use]
507 pub fn validator_try<F, E>(mut self, cb: F) -> Self
508 where
509 F: Fn(&crate::Matches) -> core::result::Result<(), E> + 'a,
510 E: std::error::Error + Send + Sync + 'static,
511 {
512 self.validate_cmd = Some(Box::new(move |m| cb(m).map_err(crate::Error::user)));
513 self
514 }
515
516 #[must_use]
518 pub fn handler<F>(mut self, cb: F) -> Self
519 where
520 F: Fn(&crate::Matches, &mut Ctx) + 'a,
521 {
522 self.handler = Some(Box::new(move |m, ctx| {
523 cb(m, ctx);
524 Ok(())
525 }));
526 self
527 }
528
529 #[must_use]
531 pub fn handler_try<F, E>(mut self, cb: F) -> Self
532 where
533 F: Fn(&crate::Matches, &mut Ctx) -> core::result::Result<(), E> + 'a,
534 E: std::error::Error + Send + Sync + 'static,
535 {
536 self.handler = Some(Box::new(move |m, ctx| cb(m, ctx).map_err(crate::Error::user)));
537 self
538 }
539
540 #[must_use]
542 pub fn get_name(&self) -> &str {
543 self.name
544 }
545 #[must_use]
546 pub fn get_help(&self) -> Option<&str> {
547 self.help
548 }
549 #[must_use]
550 pub fn get_aliases(&self) -> &[&'a str] {
551 &self.aliases
552 }
553 #[must_use]
554 pub fn get_opts(&self) -> &[OptSpec<'a, Ctx>] {
555 &self.opts
556 }
557 #[must_use]
558 pub fn get_positionals(&self) -> &[PosSpec<'a, Ctx>] {
559 &self.positionals
560 }
561 #[must_use]
562 pub fn get_subcommands(&self) -> &[Self] {
563 &self.subcommands
564 }
565 #[must_use]
566 pub fn get_groups(&self) -> &[GroupDecl<'a>] {
567 &self.groups
568 }
569 #[must_use]
570 pub fn get_validator(&self) -> Option<&CmdValidatorFn<'a>> {
571 self.validate_cmd.as_deref()
572 }
573 #[must_use]
574 pub fn get_handler(&self) -> Option<&CmdHandlerFn<'a, Ctx>> {
575 self.handler.as_deref()
576 }
577 #[must_use]
578 pub fn find_sub(&self, needle: &str) -> Option<&Self> {
579 self.subcommands.iter().find(|c| c.name == needle || c.aliases.iter().any(|a| *a == needle))
580 }
581}