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