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