1 | // Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>, |
2 | // Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and |
3 | // Ana Hobden (@hoverbear) <operator@hoverbear.org> |
4 | // |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
8 | // option. This file may not be copied, modified, or distributed |
9 | // except according to those terms. |
10 | // |
11 | // This work was derived from Structopt (https://github.com/TeXitoi/structopt) |
12 | // commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the |
13 | // MIT/Apache 2.0 license. |
14 | |
15 | use proc_macro2::{Ident, Span, TokenStream}; |
16 | use quote::{format_ident, quote, quote_spanned}; |
17 | use syn::{spanned::Spanned, Data, DeriveInput, FieldsUnnamed, Generics, Variant}; |
18 | |
19 | use crate::derives::args; |
20 | use crate::derives::args::collect_args_fields; |
21 | use crate::item::{Item, Kind, Name}; |
22 | use crate::utils::{is_simple_ty, subty_if_name}; |
23 | |
24 | pub fn derive_subcommand(input: &DeriveInput) -> Result<TokenStream, syn::Error> { |
25 | let ident: &Ident = &input.ident; |
26 | |
27 | match input.data { |
28 | Data::Enum(ref e: &DataEnum) => { |
29 | let name: Name = Name::Derived(ident.clone()); |
30 | let item: Item = Item::from_subcommand_enum(input, name)?; |
31 | let variants: Vec<(&Variant, Item)> = eimpl Iterator- >
|
32 | .variants |
33 | .iter() |
34 | .map(|variant: &Variant| { |
35 | let item: Item = |
36 | Item::from_subcommand_variant(variant, struct_casing:item.casing(), item.env_casing())?; |
37 | Ok((variant, item)) |
38 | }) |
39 | .collect::<Result<Vec<_>, syn::Error>>()?; |
40 | gen_for_enum(&item, item_name:ident, &input.generics, &variants) |
41 | } |
42 | _ => abort_call_site!("`#[derive(Subcommand)]` only supports enums" ), |
43 | } |
44 | } |
45 | |
46 | pub fn gen_for_enum( |
47 | item: &Item, |
48 | item_name: &Ident, |
49 | generics: &Generics, |
50 | variants: &[(&Variant, Item)], |
51 | ) -> Result<TokenStream, syn::Error> { |
52 | if !matches!(&*item.kind(), Kind::Command(_)) { |
53 | abort! { item.kind().span(), |
54 | "` {}` cannot be used with `command`" , |
55 | item.kind().name(), |
56 | } |
57 | } |
58 | |
59 | let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); |
60 | |
61 | let from_arg_matches = gen_from_arg_matches(variants)?; |
62 | let update_from_arg_matches = gen_update_from_arg_matches(variants)?; |
63 | |
64 | let augmentation = gen_augment(variants, item, false)?; |
65 | let augmentation_update = gen_augment(variants, item, true)?; |
66 | let has_subcommand = gen_has_subcommand(variants)?; |
67 | |
68 | Ok(quote! { |
69 | #[allow( |
70 | dead_code, |
71 | unreachable_code, |
72 | unused_variables, |
73 | unused_braces, |
74 | unused_qualifications, |
75 | )] |
76 | #[allow( |
77 | clippy::style, |
78 | clippy::complexity, |
79 | clippy::pedantic, |
80 | clippy::restriction, |
81 | clippy::perf, |
82 | clippy::deprecated, |
83 | clippy::nursery, |
84 | clippy::cargo, |
85 | clippy::suspicious_else_formatting, |
86 | clippy::almost_swapped, |
87 | clippy::redundant_locals, |
88 | )] |
89 | #[automatically_derived] |
90 | impl #impl_generics clap::FromArgMatches for #item_name #ty_generics #where_clause { |
91 | fn from_arg_matches(__clap_arg_matches: &clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> { |
92 | Self::from_arg_matches_mut(&mut __clap_arg_matches.clone()) |
93 | } |
94 | |
95 | #from_arg_matches |
96 | |
97 | fn update_from_arg_matches(&mut self, __clap_arg_matches: &clap::ArgMatches) -> ::std::result::Result<(), clap::Error> { |
98 | self.update_from_arg_matches_mut(&mut __clap_arg_matches.clone()) |
99 | } |
100 | #update_from_arg_matches |
101 | } |
102 | |
103 | #[allow( |
104 | dead_code, |
105 | unreachable_code, |
106 | unused_variables, |
107 | unused_braces, |
108 | unused_qualifications, |
109 | )] |
110 | #[allow( |
111 | clippy::style, |
112 | clippy::complexity, |
113 | clippy::pedantic, |
114 | clippy::restriction, |
115 | clippy::perf, |
116 | clippy::deprecated, |
117 | clippy::nursery, |
118 | clippy::cargo, |
119 | clippy::suspicious_else_formatting, |
120 | clippy::almost_swapped, |
121 | clippy::redundant_locals, |
122 | )] |
123 | #[automatically_derived] |
124 | impl #impl_generics clap::Subcommand for #item_name #ty_generics #where_clause { |
125 | fn augment_subcommands <'b>(__clap_app: clap::Command) -> clap::Command { |
126 | #augmentation |
127 | } |
128 | fn augment_subcommands_for_update <'b>(__clap_app: clap::Command) -> clap::Command { |
129 | #augmentation_update |
130 | } |
131 | fn has_subcommand(__clap_name: &str) -> bool { |
132 | #has_subcommand |
133 | } |
134 | } |
135 | }) |
136 | } |
137 | |
138 | fn gen_augment( |
139 | variants: &[(&Variant, Item)], |
140 | parent_item: &Item, |
141 | override_required: bool, |
142 | ) -> Result<TokenStream, syn::Error> { |
143 | use syn::Fields::*; |
144 | |
145 | let app_var = Ident::new("__clap_app" , Span::call_site()); |
146 | |
147 | let mut subcommands = Vec::new(); |
148 | for (variant, item) in variants { |
149 | let kind = item.kind(); |
150 | |
151 | let genned = match &*kind { |
152 | Kind::Skip(_, _) | Kind::Arg(_) | Kind::FromGlobal(_) | Kind::Value => None, |
153 | |
154 | Kind::ExternalSubcommand => { |
155 | let ty = match variant.fields { |
156 | Unnamed(ref fields) if fields.unnamed.len() == 1 => &fields.unnamed[0].ty, |
157 | |
158 | _ => abort!( |
159 | variant, |
160 | "The enum variant marked with `external_subcommand` must be \ |
161 | a single-typed tuple, and the type must be either `Vec<String>` \ |
162 | or `Vec<OsString>`." |
163 | ), |
164 | }; |
165 | let deprecations = if !override_required { |
166 | item.deprecations() |
167 | } else { |
168 | quote!() |
169 | }; |
170 | let subty = subty_if_name(ty, "Vec" ).ok_or_else(|| { |
171 | format_err!( |
172 | ty.span(), |
173 | "The type must be `Vec<_>` \ |
174 | to be used with `external_subcommand`." |
175 | ) |
176 | })?; |
177 | let subcommand = quote_spanned! { kind.span()=> |
178 | #deprecations |
179 | let #app_var = #app_var |
180 | .external_subcommand_value_parser(clap::value_parser!(#subty)); |
181 | }; |
182 | Some(subcommand) |
183 | } |
184 | |
185 | Kind::Flatten(_) => match variant.fields { |
186 | Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => { |
187 | let ty = &unnamed[0].ty; |
188 | let deprecations = if !override_required { |
189 | item.deprecations() |
190 | } else { |
191 | quote!() |
192 | }; |
193 | let next_help_heading = item.next_help_heading(); |
194 | let next_display_order = item.next_display_order(); |
195 | let subcommand = if override_required { |
196 | quote! { |
197 | #deprecations |
198 | let #app_var = #app_var |
199 | #next_help_heading |
200 | #next_display_order; |
201 | let #app_var = <#ty as clap::Subcommand>::augment_subcommands_for_update(#app_var); |
202 | } |
203 | } else { |
204 | quote! { |
205 | #deprecations |
206 | let #app_var = #app_var |
207 | #next_help_heading |
208 | #next_display_order; |
209 | let #app_var = <#ty as clap::Subcommand>::augment_subcommands(#app_var); |
210 | } |
211 | }; |
212 | Some(subcommand) |
213 | } |
214 | _ => abort!( |
215 | variant, |
216 | "`flatten` is usable only with single-typed tuple variants" |
217 | ), |
218 | }, |
219 | |
220 | Kind::Subcommand(_) => { |
221 | let subcommand_var = Ident::new("__clap_subcommand" , Span::call_site()); |
222 | let arg_block = match variant.fields { |
223 | Named(_) => { |
224 | abort!(variant, "non single-typed tuple enums are not supported" ) |
225 | } |
226 | Unit => quote!( #subcommand_var ), |
227 | Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => { |
228 | let ty = &unnamed[0].ty; |
229 | if override_required { |
230 | quote_spanned! { ty.span()=> |
231 | { |
232 | <#ty as clap::Subcommand>::augment_subcommands_for_update(#subcommand_var) |
233 | } |
234 | } |
235 | } else { |
236 | quote_spanned! { ty.span()=> |
237 | { |
238 | <#ty as clap::Subcommand>::augment_subcommands(#subcommand_var) |
239 | } |
240 | } |
241 | } |
242 | } |
243 | Unnamed(..) => { |
244 | abort!(variant, "non single-typed tuple enums are not supported" ) |
245 | } |
246 | }; |
247 | |
248 | let name = item.cased_name(); |
249 | let deprecations = if !override_required { |
250 | item.deprecations() |
251 | } else { |
252 | quote!() |
253 | }; |
254 | let initial_app_methods = item.initial_top_level_methods(); |
255 | let final_from_attrs = item.final_top_level_methods(); |
256 | let override_methods = if override_required { |
257 | quote_spanned! { kind.span()=> |
258 | .subcommand_required(false) |
259 | .arg_required_else_help(false) |
260 | } |
261 | } else { |
262 | quote!() |
263 | }; |
264 | let subcommand = quote! { |
265 | let #app_var = #app_var.subcommand({ |
266 | #deprecations; |
267 | let #subcommand_var = clap::Command::new(#name); |
268 | let #subcommand_var = #subcommand_var |
269 | .subcommand_required(true) |
270 | .arg_required_else_help(true); |
271 | let #subcommand_var = #subcommand_var #initial_app_methods; |
272 | let #subcommand_var = #arg_block; |
273 | #subcommand_var #final_from_attrs #override_methods |
274 | }); |
275 | }; |
276 | Some(subcommand) |
277 | } |
278 | |
279 | Kind::Command(_) => { |
280 | let subcommand_var = Ident::new("__clap_subcommand" , Span::call_site()); |
281 | let sub_augment = match variant.fields { |
282 | Named(ref fields) => { |
283 | // Defer to `gen_augment` for adding cmd methods |
284 | let fields = collect_args_fields(item, fields)?; |
285 | args::gen_augment(&fields, &subcommand_var, item, override_required)? |
286 | } |
287 | Unit => { |
288 | let arg_block = quote!( #subcommand_var ); |
289 | let initial_app_methods = item.initial_top_level_methods(); |
290 | let final_from_attrs = item.final_top_level_methods(); |
291 | quote! { |
292 | let #subcommand_var = #subcommand_var #initial_app_methods; |
293 | let #subcommand_var = #arg_block; |
294 | #subcommand_var #final_from_attrs |
295 | } |
296 | } |
297 | Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => { |
298 | let ty = &unnamed[0].ty; |
299 | let arg_block = if override_required { |
300 | quote_spanned! { ty.span()=> |
301 | { |
302 | <#ty as clap::Args>::augment_args_for_update(#subcommand_var) |
303 | } |
304 | } |
305 | } else { |
306 | quote_spanned! { ty.span()=> |
307 | { |
308 | <#ty as clap::Args>::augment_args(#subcommand_var) |
309 | } |
310 | } |
311 | }; |
312 | let initial_app_methods = item.initial_top_level_methods(); |
313 | let final_from_attrs = item.final_top_level_methods(); |
314 | quote! { |
315 | let #subcommand_var = #subcommand_var #initial_app_methods; |
316 | let #subcommand_var = #arg_block; |
317 | #subcommand_var #final_from_attrs |
318 | } |
319 | } |
320 | Unnamed(..) => { |
321 | abort!(variant, "non single-typed tuple enums are not supported" ) |
322 | } |
323 | }; |
324 | |
325 | let deprecations = if !override_required { |
326 | item.deprecations() |
327 | } else { |
328 | quote!() |
329 | }; |
330 | let name = item.cased_name(); |
331 | let subcommand = quote! { |
332 | let #app_var = #app_var.subcommand({ |
333 | #deprecations |
334 | let #subcommand_var = clap::Command::new(#name); |
335 | #sub_augment |
336 | }); |
337 | }; |
338 | Some(subcommand) |
339 | } |
340 | }; |
341 | subcommands.push(genned); |
342 | } |
343 | |
344 | let deprecations = if !override_required { |
345 | parent_item.deprecations() |
346 | } else { |
347 | quote!() |
348 | }; |
349 | let initial_app_methods = parent_item.initial_top_level_methods(); |
350 | let final_app_methods = parent_item.final_top_level_methods(); |
351 | Ok(quote! { |
352 | #deprecations; |
353 | let #app_var = #app_var #initial_app_methods; |
354 | #( #subcommands )*; |
355 | #app_var #final_app_methods |
356 | }) |
357 | } |
358 | |
359 | fn gen_has_subcommand(variants: &[(&Variant, Item)]) -> Result<TokenStream, syn::Error> { |
360 | use syn::Fields::*; |
361 | |
362 | let mut ext_subcmd = false; |
363 | |
364 | let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants |
365 | .iter() |
366 | .filter_map(|(variant, item)| { |
367 | let kind = item.kind(); |
368 | match &*kind { |
369 | Kind::Skip(_, _) | Kind::Arg(_) | Kind::FromGlobal(_) | Kind::Value => None, |
370 | |
371 | Kind::ExternalSubcommand => { |
372 | ext_subcmd = true; |
373 | None |
374 | } |
375 | Kind::Flatten(_) | Kind::Subcommand(_) | Kind::Command(_) => Some((variant, item)), |
376 | } |
377 | }) |
378 | .partition(|(_, item)| { |
379 | let kind = item.kind(); |
380 | matches!(&*kind, Kind::Flatten(_)) |
381 | }); |
382 | |
383 | let subcommands = variants.iter().map(|(_variant, item)| { |
384 | let sub_name = item.cased_name(); |
385 | quote! { |
386 | if #sub_name == __clap_name { |
387 | return true |
388 | } |
389 | } |
390 | }); |
391 | let child_subcommands = flatten_variants |
392 | .iter() |
393 | .map(|(variant, _attrs)| match variant.fields { |
394 | Unnamed(ref fields) if fields.unnamed.len() == 1 => { |
395 | let ty = &fields.unnamed[0].ty; |
396 | Ok(quote! { |
397 | if <#ty as clap::Subcommand>::has_subcommand(__clap_name) { |
398 | return true; |
399 | } |
400 | }) |
401 | } |
402 | _ => abort!( |
403 | variant, |
404 | "`flatten` is usable only with single-typed tuple variants" |
405 | ), |
406 | }) |
407 | .collect::<Result<Vec<_>, syn::Error>>()?; |
408 | |
409 | let genned = if ext_subcmd { |
410 | quote! { true } |
411 | } else { |
412 | quote! { |
413 | #( #subcommands )* |
414 | |
415 | #( #child_subcommands )else* |
416 | |
417 | false |
418 | } |
419 | }; |
420 | Ok(genned) |
421 | } |
422 | |
423 | fn gen_from_arg_matches(variants: &[(&Variant, Item)]) -> Result<TokenStream, syn::Error> { |
424 | use syn::Fields::*; |
425 | |
426 | let subcommand_name_var = format_ident!("__clap_name" ); |
427 | let sub_arg_matches_var = format_ident!("__clap_arg_matches" ); |
428 | |
429 | let mut ext_subcmd = None; |
430 | let mut flatten_variants = Vec::new(); |
431 | let mut unflatten_variants = Vec::new(); |
432 | for (variant, item) in variants { |
433 | let kind = item.kind(); |
434 | match &*kind { |
435 | Kind::Skip(_, _) | Kind::Arg(_) | Kind::FromGlobal(_) | Kind::Value => {} |
436 | |
437 | Kind::ExternalSubcommand => { |
438 | if ext_subcmd.is_some() { |
439 | abort!( |
440 | item.kind().span(), |
441 | "Only one variant can be marked with `external_subcommand`, \ |
442 | this is the second" |
443 | ); |
444 | } |
445 | |
446 | let ty = match variant.fields { |
447 | Unnamed(ref fields) if fields.unnamed.len() == 1 => &fields.unnamed[0].ty, |
448 | |
449 | _ => abort!( |
450 | variant, |
451 | "The enum variant marked with `external_subcommand` must be \ |
452 | a single-typed tuple, and the type must be either `Vec<String>` \ |
453 | or `Vec<OsString>`." |
454 | ), |
455 | }; |
456 | |
457 | let (span, str_ty) = match subty_if_name(ty, "Vec" ) { |
458 | Some(subty) => { |
459 | if is_simple_ty(subty, "String" ) { |
460 | (subty.span(), quote!(::std::string::String)) |
461 | } else if is_simple_ty(subty, "OsString" ) { |
462 | (subty.span(), quote!(::std::ffi::OsString)) |
463 | } else { |
464 | abort!( |
465 | ty.span(), |
466 | "The type must be either `Vec<String>` or `Vec<OsString>` \ |
467 | to be used with `external_subcommand`." |
468 | ); |
469 | } |
470 | } |
471 | |
472 | None => abort!( |
473 | ty.span(), |
474 | "The type must be either `Vec<String>` or `Vec<OsString>` \ |
475 | to be used with `external_subcommand`." |
476 | ), |
477 | }; |
478 | |
479 | ext_subcmd = Some((span, &variant.ident, str_ty)); |
480 | } |
481 | Kind::Flatten(_) | Kind::Subcommand(_) | Kind::Command(_) => { |
482 | if matches!(&*item.kind(), Kind::Flatten(_)) { |
483 | flatten_variants.push((variant, item)); |
484 | } else { |
485 | unflatten_variants.push((variant, item)); |
486 | } |
487 | } |
488 | } |
489 | } |
490 | |
491 | let subcommands = unflatten_variants.iter().map(|(variant, item)| { |
492 | let sub_name = item.cased_name(); |
493 | let variant_name = &variant.ident; |
494 | let constructor_block = match variant.fields { |
495 | Named(ref fields) => { |
496 | let fields = collect_args_fields(item, fields)?; |
497 | args::gen_constructor(&fields)? |
498 | }, |
499 | Unit => quote!(), |
500 | Unnamed(ref fields) if fields.unnamed.len() == 1 => { |
501 | let ty = &fields.unnamed[0].ty; |
502 | quote!( ( <#ty as clap::FromArgMatches>::from_arg_matches_mut(__clap_arg_matches)? ) ) |
503 | } |
504 | Unnamed(..) => abort_call_site!(" {}: tuple enums are not supported" , variant.ident), |
505 | }; |
506 | |
507 | Ok(quote! { |
508 | if #subcommand_name_var == #sub_name && !#sub_arg_matches_var.contains_id("" ) { |
509 | return ::std::result::Result::Ok(Self :: #variant_name #constructor_block) |
510 | } |
511 | }) |
512 | }).collect::<Result<Vec<_>, syn::Error>>()?; |
513 | let child_subcommands = flatten_variants.iter().map(|(variant, _attrs)| { |
514 | let variant_name = &variant.ident; |
515 | match variant.fields { |
516 | Unnamed(ref fields) if fields.unnamed.len() == 1 => { |
517 | let ty = &fields.unnamed[0].ty; |
518 | Ok(quote! { |
519 | if __clap_arg_matches |
520 | .subcommand_name() |
521 | .map(|__clap_name| <#ty as clap::Subcommand>::has_subcommand(__clap_name)) |
522 | .unwrap_or_default() |
523 | { |
524 | let __clap_res = <#ty as clap::FromArgMatches>::from_arg_matches_mut(__clap_arg_matches)?; |
525 | return ::std::result::Result::Ok(Self :: #variant_name (__clap_res)); |
526 | } |
527 | }) |
528 | } |
529 | _ => abort!( |
530 | variant, |
531 | "`flatten` is usable only with single-typed tuple variants" |
532 | ), |
533 | } |
534 | }).collect::<Result<Vec<_>, syn::Error>>()?; |
535 | |
536 | let wildcard = match ext_subcmd { |
537 | Some((span, var_name, str_ty)) => quote_spanned! { span=> |
538 | ::std::result::Result::Ok(Self::#var_name( |
539 | ::std::iter::once(#str_ty::from(#subcommand_name_var)) |
540 | .chain( |
541 | #sub_arg_matches_var |
542 | .remove_many::<#str_ty>("" ) |
543 | .unwrap() |
544 | .map(#str_ty::from) |
545 | ) |
546 | .collect::<::std::vec::Vec<_>>() |
547 | )) |
548 | }, |
549 | |
550 | None => quote! { |
551 | ::std::result::Result::Err(clap::Error::raw(clap::error::ErrorKind::InvalidSubcommand, format!("The subcommand '{}' wasn't recognized" , #subcommand_name_var))) |
552 | }, |
553 | }; |
554 | |
555 | let raw_deprecated = args::raw_deprecated(); |
556 | Ok(quote! { |
557 | fn from_arg_matches_mut(__clap_arg_matches: &mut clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> { |
558 | #raw_deprecated |
559 | |
560 | #( #child_subcommands )else* |
561 | |
562 | if let Some((#subcommand_name_var, mut __clap_arg_sub_matches)) = __clap_arg_matches.remove_subcommand() { |
563 | let #sub_arg_matches_var = &mut __clap_arg_sub_matches; |
564 | #( #subcommands )* |
565 | |
566 | #wildcard |
567 | } else { |
568 | ::std::result::Result::Err(clap::Error::raw(clap::error::ErrorKind::MissingSubcommand, "A subcommand is required but one was not provided." )) |
569 | } |
570 | } |
571 | }) |
572 | } |
573 | |
574 | fn gen_update_from_arg_matches(variants: &[(&Variant, Item)]) -> Result<TokenStream, syn::Error> { |
575 | use syn::Fields::*; |
576 | |
577 | let (flatten, variants): (Vec<_>, Vec<_>) = variants |
578 | .iter() |
579 | .filter_map(|(variant, item)| { |
580 | let kind = item.kind(); |
581 | match &*kind { |
582 | // Fallback to `from_arg_matches_mut` |
583 | Kind::Skip(_, _) |
584 | | Kind::Arg(_) |
585 | | Kind::FromGlobal(_) |
586 | | Kind::Value |
587 | | Kind::ExternalSubcommand => None, |
588 | Kind::Flatten(_) | Kind::Subcommand(_) | Kind::Command(_) => Some((variant, item)), |
589 | } |
590 | }) |
591 | .partition(|(_, item)| { |
592 | let kind = item.kind(); |
593 | matches!(&*kind, Kind::Flatten(_)) |
594 | }); |
595 | |
596 | let subcommands = variants.iter().map(|(variant, item)| { |
597 | let sub_name = item.cased_name(); |
598 | let variant_name = &variant.ident; |
599 | let (pattern, updater) = match variant.fields { |
600 | Named(ref fields) => { |
601 | let field_names = fields.named.iter().map(|field| { |
602 | field.ident.as_ref().unwrap() |
603 | }).collect::<Vec<_>>(); |
604 | let fields = collect_args_fields(item, fields)?; |
605 | let update = args::gen_updater(&fields, false)?; |
606 | (quote!( { #( #field_names, )* }), quote!( { #update } )) |
607 | } |
608 | Unit => (quote!(), quote!({})), |
609 | Unnamed(ref fields) => { |
610 | if fields.unnamed.len() == 1 { |
611 | ( |
612 | quote!((ref mut __clap_arg)), |
613 | quote!(clap::FromArgMatches::update_from_arg_matches_mut( |
614 | __clap_arg, |
615 | __clap_arg_matches |
616 | )?), |
617 | ) |
618 | } else { |
619 | abort_call_site!(" {}: tuple enums are not supported" , variant.ident) |
620 | } |
621 | } |
622 | }; |
623 | |
624 | Ok(quote! { |
625 | Self :: #variant_name #pattern if #sub_name == __clap_name => { |
626 | let (_, mut __clap_arg_sub_matches) = __clap_arg_matches.remove_subcommand().unwrap(); |
627 | let __clap_arg_matches = &mut __clap_arg_sub_matches; |
628 | #updater |
629 | } |
630 | }) |
631 | }).collect::<Result<Vec<_>, _>>()?; |
632 | |
633 | let child_subcommands = flatten.iter().map(|(variant, _attrs)| { |
634 | let variant_name = &variant.ident; |
635 | match variant.fields { |
636 | Unnamed(ref fields) if fields.unnamed.len() == 1 => { |
637 | let ty = &fields.unnamed[0].ty; |
638 | Ok(quote! { |
639 | if <#ty as clap::Subcommand>::has_subcommand(__clap_name) { |
640 | if let Self :: #variant_name (child) = s { |
641 | <#ty as clap::FromArgMatches>::update_from_arg_matches_mut(child, __clap_arg_matches)?; |
642 | return ::std::result::Result::Ok(()); |
643 | } |
644 | } |
645 | }) |
646 | } |
647 | _ => abort!( |
648 | variant, |
649 | "`flatten` is usable only with single-typed tuple variants" |
650 | ), |
651 | } |
652 | }).collect::<Result<Vec<_>, _>>()?; |
653 | |
654 | let raw_deprecated = args::raw_deprecated(); |
655 | Ok(quote! { |
656 | fn update_from_arg_matches_mut<'b>( |
657 | &mut self, |
658 | __clap_arg_matches: &mut clap::ArgMatches, |
659 | ) -> ::std::result::Result<(), clap::Error> { |
660 | #raw_deprecated |
661 | |
662 | if let Some(__clap_name) = __clap_arg_matches.subcommand_name() { |
663 | match self { |
664 | #( #subcommands ),* |
665 | s => { |
666 | #( #child_subcommands )* |
667 | *s = <Self as clap::FromArgMatches>::from_arg_matches_mut(__clap_arg_matches)?; |
668 | } |
669 | } |
670 | } |
671 | ::std::result::Result::Ok(()) |
672 | } |
673 | }) |
674 | } |
675 | |