1use crate::Result;
2use std::ffi::{OsStr, OsString};
3
4#[derive(Clone, Copy, Debug)]
6pub enum ColorMode {
7 Auto,
8 Always,
9 Never,
10}
11
12#[derive(Clone, Copy, Debug)]
14pub struct Env {
15 pub wrap_cols: usize,
17 pub color: ColorMode,
19 pub suggest: bool,
21 pub auto_help: bool,
23 pub version: Option<&'static str>,
24 pub author: Option<&'static str>,
25}
26impl Default for Env {
27 fn default() -> Self {
28 Self {
29 wrap_cols: 80,
30 color: ColorMode::Auto,
31 suggest: true,
32 auto_help: true,
33 version: None,
34 author: None,
35 }
36 }
37}
38
39#[derive(Clone, Copy, Debug, PartialEq, Eq)]
41pub enum Repeat {
42 Single,
43 Many,
44}
45
46#[derive(Clone, Copy, Debug, PartialEq, Eq)]
48pub enum GroupMode {
49 Xor,
50 ReqOne,
51}
52
53#[derive(Clone, Copy, Debug, PartialEq, Eq)]
55pub enum Source {
56 Cli,
57 Env,
58 Default,
59}
60
61pub type ValueValidator = fn(&OsStr) -> Result<()>;
63
64pub type CmdValidator = fn(&crate::Matches) -> Result<()>;
66
67pub type CmdHandler<Ctx> = fn(&crate::Matches, &mut Ctx) -> Result<()>;
69
70pub type OnValue<Ctx> = fn(&OsStr, &mut Ctx) -> Result<()>;
72pub type OnFlag<Ctx> = fn(&mut Ctx) -> Result<()>;
73
74pub struct OptSpec<'a, Ctx: ?Sized> {
76 name: &'a str,
77 short: Option<char>,
78 long: Option<&'a str>,
79 metavar: Option<&'a str>,
80 help: Option<&'a str>,
81 env: Option<&'a str>,
82 default: Option<OsString>,
83 group: Option<&'a str>,
84 repeat: Repeat,
85 takes_value: bool,
86 on_value: Option<OnValue<Ctx>>, on_flag: Option<OnFlag<Ctx>>, validator: Option<ValueValidator>,
89}
90
91impl<'a, Ctx: ?Sized> OptSpec<'a, Ctx> {
92 pub fn flag(name: &'a str, cb: OnFlag<Ctx>) -> Self {
94 Self {
95 name,
96 short: None,
97 long: None,
98 metavar: None,
99 help: None,
100 env: None,
101 default: None,
102 group: None,
103 repeat: Repeat::Single,
104 takes_value: false,
105 on_value: None,
106 on_flag: Some(cb),
107 validator: None,
108 }
109 }
110 pub const fn value(name: &'a str, cb: OnValue<Ctx>) -> Self {
112 Self {
113 name,
114 short: None,
115 long: None,
116 metavar: None,
117 help: None,
118 env: None,
119 default: None,
120 group: None,
121 repeat: Repeat::Single,
122 takes_value: true,
123 on_value: Some(cb),
124 on_flag: None,
125 validator: None,
126 }
127 }
128 #[must_use]
130 pub const fn short(mut self, s: char) -> Self {
131 self.short = Some(s);
132 self
133 }
134 #[must_use]
135 pub const fn long(mut self, l: &'a str) -> Self {
136 self.long = Some(l);
137 self
138 }
139 #[must_use]
140 pub const fn metavar(mut self, mv: &'a str) -> Self {
141 self.metavar = Some(mv);
142 self
143 }
144 #[must_use]
145 pub const fn help(mut self, h: &'a str) -> Self {
146 self.help = Some(h);
147 self
148 }
149 #[must_use]
150 pub const fn env(mut self, name: &'a str) -> Self {
151 self.env = Some(name);
152 self
153 }
154 #[must_use]
155 pub fn default(mut self, val: impl Into<OsString>) -> Self {
156 self.default = Some(val.into());
157 self
158 }
159 #[must_use]
160 pub const fn group(mut self, g: &'a str) -> Self {
161 self.group = Some(g);
162 self
163 }
164 #[must_use]
165 pub const fn single(mut self) -> Self {
166 self.repeat = Repeat::Single;
167 self
168 }
169 #[must_use]
170 pub const fn repeatable(mut self) -> Self {
171 self.repeat = Repeat::Many;
172 self
173 }
174 #[must_use]
175 pub const fn validator(mut self, v: ValueValidator) -> Self {
176 self.validator = Some(v);
177 self
178 }
179
180 #[must_use]
182 pub const fn get_name(&self) -> &str {
183 self.name
184 }
185 #[must_use]
186 pub const fn get_short(&self) -> Option<char> {
187 self.short
188 }
189 #[must_use]
190 pub const fn get_long(&self) -> Option<&str> {
191 self.long
192 }
193 #[must_use]
194 pub const fn get_metavar(&self) -> Option<&str> {
195 self.metavar
196 }
197 #[must_use]
198 pub const fn get_help(&self) -> Option<&str> {
199 self.help
200 }
201 #[must_use]
202 pub const fn get_env(&self) -> Option<&str> {
203 self.env
204 }
205 #[must_use]
206 pub const fn get_default(&self) -> Option<&OsString> {
207 self.default.as_ref()
208 }
209 #[must_use]
210 pub const fn get_group(&self) -> Option<&str> {
211 self.group
212 }
213 #[must_use]
214 pub const fn is_value(&self) -> bool {
215 self.takes_value
216 }
217 #[must_use]
218 pub const fn get_repeat(&self) -> Repeat {
219 self.repeat
220 }
221 #[must_use]
222 pub fn get_on_value(&self) -> Option<OnValue<Ctx>> {
223 self.on_value
224 }
225 #[must_use]
226 pub fn get_on_flag(&self) -> Option<OnFlag<Ctx>> {
227 self.on_flag
228 }
229 #[must_use]
230 pub fn get_validator(&self) -> Option<ValueValidator> {
231 self.validator
232 }
233}
234
235#[derive(Clone, Copy, Debug, PartialEq, Eq)]
237pub enum PosCardinality {
238 One { required: bool },
239 Many,
240 Range { min: usize, max: usize },
241}
242
243pub struct PosSpec<'a, Ctx: ?Sized> {
245 name: &'a str,
246 help: Option<&'a str>,
247 card: PosCardinality,
248 on_value: OnValue<Ctx>,
249 validator: Option<ValueValidator>,
250}
251impl<'a, Ctx: ?Sized> PosSpec<'a, Ctx> {
252 pub const fn new(name: &'a str, cb: OnValue<Ctx>) -> Self {
253 Self {
254 name,
255 help: None,
256 card: PosCardinality::One { required: false },
257 on_value: cb,
258 validator: None,
259 }
260 }
261 #[must_use]
263 pub const fn help(mut self, h: &'a str) -> Self {
264 self.help = Some(h);
265 self
266 }
267 #[must_use]
268 pub const fn required(mut self) -> Self {
269 self.card = PosCardinality::One { required: true };
270 self
271 }
272 #[must_use]
273 pub const fn many(mut self) -> Self {
274 self.card = PosCardinality::Many;
275 self
276 }
277 #[must_use]
278 pub const fn range(mut self, min: usize, max: usize) -> Self {
279 self.card = PosCardinality::Range { min, max };
280 self
281 }
282 #[must_use]
283 pub const fn validator(mut self, v: ValueValidator) -> Self {
284 self.validator = Some(v);
285 self
286 }
287 #[must_use]
289 pub const fn get_name(&self) -> &str {
290 self.name
291 }
292 #[must_use]
293 pub const fn get_help(&self) -> Option<&str> {
294 self.help
295 }
296 #[must_use]
297 pub const fn get_cardinality(&self) -> PosCardinality {
298 self.card
299 }
300 #[must_use]
301 pub const fn is_required(&self) -> bool {
302 matches!(self.card, PosCardinality::One { required: true })
303 || matches!(self.card, PosCardinality::Range { min, .. } if min > 0)
304 }
305 #[must_use]
306 pub const fn is_multiple(&self) -> bool {
307 !matches!(self.card, PosCardinality::One { .. })
308 }
309 #[must_use]
310 pub const fn get_on_value(&self) -> OnValue<Ctx> {
311 self.on_value
312 }
313 #[must_use]
314 pub const fn get_validator(&self) -> Option<ValueValidator> {
315 self.validator
316 }
317}
318
319pub struct GroupDecl<'a> {
321 pub name: &'a str,
322 pub mode: GroupMode,
323}
324
325pub struct CmdSpec<'a, Ctx: ?Sized> {
327 name: &'a str,
328 help: Option<&'a str>,
329 aliases: Vec<&'a str>,
330 opts: Vec<OptSpec<'a, Ctx>>,
331 positionals: Vec<PosSpec<'a, Ctx>>,
332 subcommands: Vec<CmdSpec<'a, Ctx>>,
333 groups: Vec<GroupDecl<'a>>,
334 validate_cmd: Option<CmdValidator>,
335 handler: Option<CmdHandler<Ctx>>, }
337impl<'a, Ctx: ?Sized> CmdSpec<'a, Ctx> {
338 #[must_use]
339 pub fn new(name: &'a str) -> Self {
340 Self {
341 name,
342 help: None,
343 aliases: Vec::new(),
344 opts: Vec::new(),
345 positionals: Vec::new(),
346 subcommands: Vec::new(),
347 groups: Vec::new(),
348 validate_cmd: None,
349 handler: None,
350 }
351 }
352 #[must_use]
354 pub const fn help(mut self, s: &'a str) -> Self {
355 self.help = Some(s);
356 self
357 }
358 #[must_use]
359 pub fn alias(mut self, a: &'a str) -> Self {
360 self.aliases.push(a);
361 self
362 }
363 #[must_use]
364 pub fn opt(mut self, o: OptSpec<'a, Ctx>) -> Self {
365 self.opts.push(o);
366 self
367 }
368 #[must_use]
369 pub fn pos(mut self, p: PosSpec<'a, Ctx>) -> Self {
370 self.positionals.push(p);
371 self
372 }
373 #[must_use]
374 pub fn subcmd(mut self, c: Self) -> Self {
375 self.subcommands.push(c);
376 self
377 }
378 #[must_use]
379 pub fn group(mut self, name: &'a str, mode: GroupMode) -> Self {
380 self.groups.push(GroupDecl { name, mode });
381 self
382 }
383 #[must_use]
385 pub fn validator(mut self, cb: CmdValidator) -> Self {
386 self.validate_cmd = Some(cb);
387 self
388 }
389 #[must_use]
391 pub fn handler(mut self, cb: CmdHandler<Ctx>) -> Self {
392 self.handler = Some(cb);
393 self
394 }
395 #[must_use]
397 pub const fn get_name(&self) -> &str {
398 self.name
399 }
400 #[must_use]
401 pub const fn get_help(&self) -> Option<&str> {
402 self.help
403 }
404 #[must_use]
405 #[allow(clippy::missing_const_for_fn)]
406 pub fn get_aliases(&self) -> &[&'a str] {
407 &self.aliases
408 }
409 #[must_use]
410 #[allow(clippy::missing_const_for_fn)]
411 pub fn get_opts(&self) -> &[OptSpec<'a, Ctx>] {
412 &self.opts
413 }
414 #[must_use]
415 #[allow(clippy::missing_const_for_fn)]
416 pub fn get_positionals(&self) -> &[PosSpec<'a, Ctx>] {
417 &self.positionals
418 }
419 #[must_use]
420 #[allow(clippy::missing_const_for_fn)]
421 pub fn get_subcommands(&self) -> &[Self] {
422 &self.subcommands
423 }
424 #[must_use]
425 #[allow(clippy::missing_const_for_fn)]
426 pub fn get_groups(&self) -> &[GroupDecl<'a>] {
427 &self.groups
428 }
429 #[must_use]
430 pub fn get_validator(&self) -> Option<CmdValidator> {
431 self.validate_cmd
432 }
433 #[must_use]
434 pub fn get_handler(&self) -> Option<CmdHandler<Ctx>> {
435 self.handler
436 }
437 #[must_use]
438 pub fn find_sub(&self, needle: &str) -> Option<&Self> {
439 self.subcommands.iter().find(|c| c.name == needle || c.aliases.iter().any(|a| *a == needle))
440 }
441}