]> git.proxmox.com Git - rustc.git/blame - vendor/clap_complete/src/generator/utils.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / vendor / clap_complete / src / generator / utils.rs
CommitLineData
04454e1e
FG
1//! Helpers for writing generators
2
3use clap::{Arg, Command};
4
5/// Gets all subcommands including child subcommands in the form of `("name", "bin_name")`.
6///
7/// Subcommand `rustup toolchain install` would be converted to
8/// `("install", "rustup toolchain install")`.
9pub fn all_subcommands(cmd: &Command) -> Vec<(String, String)> {
10 let mut subcmds: Vec<_> = subcommands(cmd);
11
12 for sc_v in cmd.get_subcommands().map(all_subcommands) {
13 subcmds.extend(sc_v);
14 }
15
16 subcmds
17}
18
19/// Finds the subcommand [`clap::Command`] from the given [`clap::Command`] with the given path.
20///
21/// **NOTE:** `path` should not contain the root `bin_name`.
f25598a0 22pub fn find_subcommand_with_path<'cmd>(p: &'cmd Command, path: Vec<&str>) -> &'cmd Command {
04454e1e
FG
23 let mut cmd = p;
24
25 for sc in path {
26 cmd = cmd.find_subcommand(sc).unwrap();
27 }
28
29 cmd
30}
31
32/// Gets subcommands of [`clap::Command`] in the form of `("name", "bin_name")`.
33///
34/// Subcommand `rustup toolchain install` would be converted to
35/// `("install", "rustup toolchain install")`.
36pub fn subcommands(p: &Command) -> Vec<(String, String)> {
37 debug!("subcommands: name={}", p.get_name());
38 debug!("subcommands: Has subcommands...{:?}", p.has_subcommands());
39
40 let mut subcmds = vec![];
41
04454e1e
FG
42 for sc in p.get_subcommands() {
43 let sc_bin_name = sc.get_bin_name().unwrap();
44
45 debug!(
46 "subcommands:iter: name={}, bin_name={}",
47 sc.get_name(),
48 sc_bin_name
49 );
50
51 subcmds.push((sc.get_name().to_string(), sc_bin_name.to_string()));
52 }
53
54 subcmds
55}
56
57/// Gets all the short options, their visible aliases and flags of a [`clap::Command`].
f25598a0 58/// Includes `h` and `V` depending on the [`clap::Command`] settings.
04454e1e
FG
59pub fn shorts_and_visible_aliases(p: &Command) -> Vec<char> {
60 debug!("shorts: name={}", p.get_name());
61
62 p.get_arguments()
63 .filter_map(|a| {
64 if !a.is_positional() {
65 if a.get_visible_short_aliases().is_some() && a.get_short().is_some() {
66 let mut shorts_and_visible_aliases = a.get_visible_short_aliases().unwrap();
67 shorts_and_visible_aliases.push(a.get_short().unwrap());
68 Some(shorts_and_visible_aliases)
69 } else if a.get_visible_short_aliases().is_none() && a.get_short().is_some() {
70 Some(vec![a.get_short().unwrap()])
71 } else {
72 None
73 }
74 } else {
75 None
76 }
77 })
78 .flatten()
79 .collect()
80}
81
82/// Gets all the long options, their visible aliases and flags of a [`clap::Command`].
f25598a0 83/// Includes `help` and `version` depending on the [`clap::Command`] settings.
04454e1e
FG
84pub fn longs_and_visible_aliases(p: &Command) -> Vec<String> {
85 debug!("longs: name={}", p.get_name());
86
87 p.get_arguments()
88 .filter_map(|a| {
89 if !a.is_positional() {
90 if a.get_visible_aliases().is_some() && a.get_long().is_some() {
91 let mut visible_aliases: Vec<_> = a
92 .get_visible_aliases()
93 .unwrap()
94 .into_iter()
95 .map(|s| s.to_string())
96 .collect();
97 visible_aliases.push(a.get_long().unwrap().to_string());
98 Some(visible_aliases)
99 } else if a.get_visible_aliases().is_none() && a.get_long().is_some() {
100 Some(vec![a.get_long().unwrap().to_string()])
101 } else {
102 None
103 }
104 } else {
105 None
106 }
107 })
108 .flatten()
109 .collect()
110}
111
112/// Gets all the flags of a [`clap::Command`](Command).
f25598a0
FG
113/// Includes `help` and `version` depending on the [`clap::Command`] settings.
114pub fn flags(p: &Command) -> Vec<Arg> {
04454e1e
FG
115 debug!("flags: name={}", p.get_name());
116 p.get_arguments()
f25598a0 117 .filter(|a| !a.get_num_args().expect("built").takes_values() && !a.is_positional())
04454e1e
FG
118 .cloned()
119 .collect()
120}
121
f25598a0
FG
122/// Get the possible values for completion
123pub fn possible_values(a: &Arg) -> Option<Vec<clap::builder::PossibleValue>> {
124 if !a.get_num_args().expect("built").takes_values() {
125 None
126 } else {
127 a.get_value_parser()
128 .possible_values()
129 .map(|pvs| pvs.collect())
130 }
131}
132
04454e1e
FG
133#[cfg(test)]
134mod tests {
135 use super::*;
136 use clap::Arg;
f25598a0 137 use clap::ArgAction;
04454e1e 138
f25598a0 139 fn common_app() -> Command {
04454e1e
FG
140 Command::new("myapp")
141 .subcommand(
142 Command::new("test").subcommand(Command::new("config")).arg(
143 Arg::new("file")
144 .short('f')
145 .short_alias('c')
146 .visible_short_alias('p')
147 .long("file")
f25598a0 148 .action(ArgAction::SetTrue)
04454e1e
FG
149 .visible_alias("path"),
150 ),
151 )
152 .subcommand(Command::new("hello"))
153 .bin_name("my-cmd")
154 }
155
f25598a0 156 fn built() -> Command {
04454e1e
FG
157 let mut cmd = common_app();
158
f25598a0 159 cmd.build();
04454e1e
FG
160 cmd
161 }
162
f25598a0 163 fn built_with_version() -> Command {
04454e1e
FG
164 let mut cmd = common_app().version("3.0");
165
f25598a0 166 cmd.build();
04454e1e
FG
167 cmd
168 }
169
170 #[test]
171 fn test_subcommands() {
172 let cmd = built_with_version();
173
174 assert_eq!(
175 subcommands(&cmd),
176 vec![
177 ("test".to_string(), "my-cmd test".to_string()),
178 ("hello".to_string(), "my-cmd hello".to_string()),
179 ("help".to_string(), "my-cmd help".to_string()),
180 ]
181 );
182 }
183
184 #[test]
185 fn test_all_subcommands() {
186 let cmd = built_with_version();
187
188 assert_eq!(
189 all_subcommands(&cmd),
190 vec![
191 ("test".to_string(), "my-cmd test".to_string()),
192 ("hello".to_string(), "my-cmd hello".to_string()),
193 ("help".to_string(), "my-cmd help".to_string()),
194 ("config".to_string(), "my-cmd test config".to_string()),
195 ("help".to_string(), "my-cmd test help".to_string()),
f25598a0
FG
196 ("config".to_string(), "my-cmd test help config".to_string()),
197 ("help".to_string(), "my-cmd test help help".to_string()),
198 ("test".to_string(), "my-cmd help test".to_string()),
199 ("hello".to_string(), "my-cmd help hello".to_string()),
200 ("help".to_string(), "my-cmd help help".to_string()),
201 ("config".to_string(), "my-cmd help test config".to_string()),
04454e1e
FG
202 ]
203 );
204 }
205
206 #[test]
207 fn test_find_subcommand_with_path() {
208 let cmd = built_with_version();
209 let sc_app = find_subcommand_with_path(&cmd, "test config".split(' ').collect());
210
211 assert_eq!(sc_app.get_name(), "config");
212 }
213
214 #[test]
215 fn test_flags() {
216 let cmd = built_with_version();
217 let actual_flags = flags(&cmd);
218
219 assert_eq!(actual_flags.len(), 2);
220 assert_eq!(actual_flags[0].get_long(), Some("help"));
221 assert_eq!(actual_flags[1].get_long(), Some("version"));
222
223 let sc_flags = flags(find_subcommand_with_path(&cmd, vec!["test"]));
224
225 assert_eq!(sc_flags.len(), 2);
226 assert_eq!(sc_flags[0].get_long(), Some("file"));
227 assert_eq!(sc_flags[1].get_long(), Some("help"));
228 }
229
230 #[test]
231 fn test_flag_subcommand() {
232 let cmd = built();
233 let actual_flags = flags(&cmd);
234
235 assert_eq!(actual_flags.len(), 1);
236 assert_eq!(actual_flags[0].get_long(), Some("help"));
237
238 let sc_flags = flags(find_subcommand_with_path(&cmd, vec!["test"]));
239
240 assert_eq!(sc_flags.len(), 2);
241 assert_eq!(sc_flags[0].get_long(), Some("file"));
242 assert_eq!(sc_flags[1].get_long(), Some("help"));
243 }
244
245 #[test]
246 fn test_shorts() {
247 let cmd = built_with_version();
248 let shorts = shorts_and_visible_aliases(&cmd);
249
250 assert_eq!(shorts.len(), 2);
251 assert_eq!(shorts[0], 'h');
252 assert_eq!(shorts[1], 'V');
253
254 let sc_shorts = shorts_and_visible_aliases(find_subcommand_with_path(&cmd, vec!["test"]));
255
256 assert_eq!(sc_shorts.len(), 3);
257 assert_eq!(sc_shorts[0], 'p');
258 assert_eq!(sc_shorts[1], 'f');
259 assert_eq!(sc_shorts[2], 'h');
260 }
261
262 #[test]
263 fn test_longs() {
264 let cmd = built_with_version();
265 let longs = longs_and_visible_aliases(&cmd);
266
267 assert_eq!(longs.len(), 2);
268 assert_eq!(longs[0], "help");
269 assert_eq!(longs[1], "version");
270
271 let sc_longs = longs_and_visible_aliases(find_subcommand_with_path(&cmd, vec!["test"]));
272
273 assert_eq!(sc_longs.len(), 3);
274 assert_eq!(sc_longs[0], "path");
275 assert_eq!(sc_longs[1], "file");
276 assert_eq!(sc_longs[2], "help");
277 }
278}