Skip to main content

getargs_derive/
command.rs

1/// Compile-time description of a command line interface, implemented by
2/// [`#[derive(GetArgs)]`](derive@crate::GetArgs).
3///
4/// The metadata is `&'static` and available without the `std` feature. It is what the shell
5/// completion and man page generators of the `std` feature read, and can be inspected to build
6/// other tools.
7/// See [Shell Completions and Man Pages][crate::guide::completions].
8pub trait Command {
9    /// The description of the command.
10    const COMMAND: CommandInfo;
11}
12
13/// The description of a command: its name, texts, arguments and subcommands.
14///
15/// Values are built with [`CommandInfo::new`] and the `const` builder methods, so that fields can
16/// be added without breaking existing code.
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18#[non_exhaustive]
19pub struct CommandInfo {
20    /// The name of the command, as typed on the command line.
21    pub name: &'static str,
22    /// The short description, from `about` or the first paragraph of the doc comment. Empty when
23    /// not set.
24    pub about: &'static str,
25    /// The long description, from `long_about` or the full doc comment. Empty when not set.
26    pub long_about: &'static str,
27    /// The version set with `#[command(version)]`.
28    pub version: Option<&'static str>,
29    /// The arguments, flattened structs included, in field order, followed by the generated
30    /// `--help` and `--version` flags.
31    pub args: &'static [ArgInfo],
32    /// The subcommands, from a `#[command(subcommand)]` field, in variant order. Their
33    /// [`args`](Self::args) do not repeat the `global` arguments of their parents.
34    pub commands: &'static [CommandInfo],
35    /// Whether one of the [`commands`](Self::commands) must be given.
36    pub subcommand_required: bool,
37    /// The aliases of a subcommand listed in the help.
38    pub visible_aliases: &'static [&'static str],
39    /// The aliases of a subcommand hidden from the help.
40    pub aliases: &'static [&'static str],
41    /// Whether the subcommand is hidden from the help.
42    pub hidden: bool,
43}
44
45impl CommandInfo {
46    /// A command named `name`, without description, version, arguments or subcommands.
47    pub const fn new(name: &'static str) -> Self {
48        CommandInfo {
49            name,
50            about: "",
51            long_about: "",
52            version: None,
53            args: &[],
54            commands: &[],
55            subcommand_required: false,
56            visible_aliases: &[],
57            aliases: &[],
58            hidden: false,
59        }
60    }
61
62    /// Sets [`subcommand_required`](Self::subcommand_required).
63    pub const fn subcommand_required(mut self, required: bool) -> Self {
64        self.subcommand_required = required;
65        self
66    }
67
68    /// Sets [`visible_aliases`](Self::visible_aliases).
69    pub const fn visible_aliases(mut self, aliases: &'static [&'static str]) -> Self {
70        self.visible_aliases = aliases;
71        self
72    }
73
74    /// Sets [`aliases`](Self::aliases).
75    pub const fn aliases(mut self, aliases: &'static [&'static str]) -> Self {
76        self.aliases = aliases;
77        self
78    }
79
80    /// Sets [`hidden`](Self::hidden).
81    pub const fn hidden(mut self, hidden: bool) -> Self {
82        self.hidden = hidden;
83        self
84    }
85
86    /// Sets [`about`](Self::about).
87    pub const fn about(mut self, about: &'static str) -> Self {
88        self.about = about;
89        self
90    }
91
92    /// Sets [`long_about`](Self::long_about).
93    pub const fn long_about(mut self, long_about: &'static str) -> Self {
94        self.long_about = long_about;
95        self
96    }
97
98    /// Sets [`version`](Self::version).
99    pub const fn version(mut self, version: &'static str) -> Self {
100        self.version = Some(version);
101        self
102    }
103
104    /// Sets [`args`](Self::args).
105    pub const fn args(mut self, args: &'static [ArgInfo]) -> Self {
106        self.args = args;
107        self
108    }
109
110    /// Sets [`commands`](Self::commands).
111    pub const fn commands(mut self, commands: &'static [CommandInfo]) -> Self {
112        self.commands = commands;
113        self
114    }
115}
116
117/// How an argument is given on the command line.
118#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
119#[non_exhaustive]
120pub enum ArgKind {
121    /// A positional argument.
122    Positional,
123    /// A named option taking a value.
124    Option,
125    /// A named flag taking no value.
126    Flag,
127}
128
129/// The description of one argument.
130///
131/// Values are built with [`ArgInfo::new`] and the `const` builder methods, so that fields can be
132/// added without breaking existing code.
133#[derive(Debug, Clone, Copy, PartialEq, Eq)]
134#[non_exhaustive]
135pub struct ArgInfo {
136    /// The name of the field, or `help` and `version` for the generated flags.
137    pub id: &'static str,
138    /// How the argument is given.
139    pub kind: ArgKind,
140    /// The short name, without the leading `-`.
141    pub short: Option<char>,
142    /// The long name, without the leading `--`.
143    pub long: Option<&'static str>,
144    /// The short aliases listed in the help.
145    pub visible_short_aliases: &'static [char],
146    /// The short aliases hidden from the help.
147    pub short_aliases: &'static [char],
148    /// The long aliases listed in the help.
149    pub visible_aliases: &'static [&'static str],
150    /// The long aliases hidden from the help.
151    pub aliases: &'static [&'static str],
152    /// The name of the value, e.g. `FILE`. Empty for flags.
153    pub value_name: &'static str,
154    /// The short help. Empty when not set.
155    pub help: &'static str,
156    /// The long help. Empty when not set.
157    pub long_help: &'static str,
158    /// The accepted values, from `possible_values` or a [`ValueEnum`](crate::ValueEnum). Empty
159    /// when any value is accepted.
160    pub possible_values: &'static [&'static str],
161    /// The environment variable the argument falls back to.
162    pub env: Option<&'static str>,
163    /// Whether the argument is hidden from the help.
164    pub hidden: bool,
165    /// Whether the argument must be given.
166    pub required: bool,
167    /// Whether the argument can be given several times, e.g. a `Count` flag or a field collecting
168    /// [repeated values][crate::guide::collections]. A repeatable positional argument takes every
169    /// remaining positional argument.
170    pub multiple: bool,
171    /// Whether the positional argument is only filled after `--`.
172    pub last: bool,
173    /// Whether the option is `global`: also accepted after the subcommands of its command, and
174    /// listed in their help and completions.
175    pub global: bool,
176}
177
178impl ArgInfo {
179    /// An argument named `id`, without names, help or values.
180    pub const fn new(id: &'static str, kind: ArgKind) -> Self {
181        ArgInfo {
182            id,
183            kind,
184            short: None,
185            long: None,
186            visible_short_aliases: &[],
187            short_aliases: &[],
188            visible_aliases: &[],
189            aliases: &[],
190            value_name: "",
191            help: "",
192            long_help: "",
193            possible_values: &[],
194            env: None,
195            hidden: false,
196            required: false,
197            multiple: false,
198            last: false,
199            global: false,
200        }
201    }
202
203    /// Sets [`short`](Self::short).
204    pub const fn short(mut self, short: char) -> Self {
205        self.short = Some(short);
206        self
207    }
208
209    /// Sets [`long`](Self::long).
210    pub const fn long(mut self, long: &'static str) -> Self {
211        self.long = Some(long);
212        self
213    }
214
215    /// Sets [`visible_short_aliases`](Self::visible_short_aliases).
216    pub const fn visible_short_aliases(mut self, aliases: &'static [char]) -> Self {
217        self.visible_short_aliases = aliases;
218        self
219    }
220
221    /// Sets [`short_aliases`](Self::short_aliases).
222    pub const fn short_aliases(mut self, aliases: &'static [char]) -> Self {
223        self.short_aliases = aliases;
224        self
225    }
226
227    /// Sets [`visible_aliases`](Self::visible_aliases).
228    pub const fn visible_aliases(mut self, aliases: &'static [&'static str]) -> Self {
229        self.visible_aliases = aliases;
230        self
231    }
232
233    /// Sets [`aliases`](Self::aliases).
234    pub const fn aliases(mut self, aliases: &'static [&'static str]) -> Self {
235        self.aliases = aliases;
236        self
237    }
238
239    /// Sets [`value_name`](Self::value_name).
240    pub const fn value_name(mut self, value_name: &'static str) -> Self {
241        self.value_name = value_name;
242        self
243    }
244
245    /// Sets [`help`](Self::help).
246    pub const fn help(mut self, help: &'static str) -> Self {
247        self.help = help;
248        self
249    }
250
251    /// Sets [`long_help`](Self::long_help).
252    pub const fn long_help(mut self, long_help: &'static str) -> Self {
253        self.long_help = long_help;
254        self
255    }
256
257    /// Sets [`possible_values`](Self::possible_values).
258    pub const fn possible_values(mut self, values: &'static [&'static str]) -> Self {
259        self.possible_values = values;
260        self
261    }
262
263    /// Sets [`env`](Self::env).
264    pub const fn env(mut self, env: &'static str) -> Self {
265        self.env = Some(env);
266        self
267    }
268
269    /// Sets [`hidden`](Self::hidden).
270    pub const fn hidden(mut self, hidden: bool) -> Self {
271        self.hidden = hidden;
272        self
273    }
274
275    /// Sets [`required`](Self::required).
276    pub const fn required(mut self, required: bool) -> Self {
277        self.required = required;
278        self
279    }
280
281    /// Sets [`multiple`](Self::multiple).
282    pub const fn multiple(mut self, multiple: bool) -> Self {
283        self.multiple = multiple;
284        self
285    }
286
287    /// Sets [`last`](Self::last).
288    pub const fn last(mut self, last: bool) -> Self {
289        self.last = last;
290        self
291    }
292
293    /// Sets [`global`](Self::global).
294    pub const fn global(mut self, global: bool) -> Self {
295        self.global = global;
296        self
297    }
298
299    /// Whether the argument takes a value: options and positional arguments.
300    pub const fn takes_value(&self) -> bool {
301        matches!(self.kind, ArgKind::Positional | ArgKind::Option)
302    }
303
304    /// Whether the argument is positional.
305    pub const fn is_positional(&self) -> bool {
306        matches!(self.kind, ArgKind::Positional)
307    }
308
309    /// The long help, or the short help when there is no long help.
310    pub const fn long_or_short_help(&self) -> &'static str {
311        if self.long_help.is_empty() {
312            self.help
313        } else {
314            self.long_help
315        }
316    }
317}