119625d8cSopenharmony_ci// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>, 219625d8cSopenharmony_ci// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and 319625d8cSopenharmony_ci// Ana Hobden (@hoverbear) <operator@hoverbear.org> 419625d8cSopenharmony_ci// 519625d8cSopenharmony_ci// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 619625d8cSopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 719625d8cSopenharmony_ci// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 819625d8cSopenharmony_ci// option. This file may not be copied, modified, or distributed 919625d8cSopenharmony_ci// except according to those terms. 1019625d8cSopenharmony_ci// 1119625d8cSopenharmony_ci// This work was derived from Structopt (https://github.com/TeXitoi/structopt) 1219625d8cSopenharmony_ci// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the 1319625d8cSopenharmony_ci// MIT/Apache 2.0 license. 1419625d8cSopenharmony_ci 1519625d8cSopenharmony_ciuse proc_macro2::{Ident, Span, TokenStream}; 1619625d8cSopenharmony_ciuse quote::{format_ident, quote, quote_spanned}; 1719625d8cSopenharmony_ciuse syn::{spanned::Spanned, Data, DeriveInput, FieldsUnnamed, Generics, Variant}; 1819625d8cSopenharmony_ci 1919625d8cSopenharmony_ciuse crate::derives::args; 2019625d8cSopenharmony_ciuse crate::item::{Item, Kind, Name}; 2119625d8cSopenharmony_ciuse crate::utils::{is_simple_ty, subty_if_name}; 2219625d8cSopenharmony_ci 2319625d8cSopenharmony_cipub fn derive_subcommand(input: &DeriveInput) -> Result<TokenStream, syn::Error> { 2419625d8cSopenharmony_ci let ident = &input.ident; 2519625d8cSopenharmony_ci 2619625d8cSopenharmony_ci match input.data { 2719625d8cSopenharmony_ci Data::Enum(ref e) => { 2819625d8cSopenharmony_ci let name = Name::Derived(ident.clone()); 2919625d8cSopenharmony_ci let item = Item::from_subcommand_enum(input, name)?; 3019625d8cSopenharmony_ci let variants = e 3119625d8cSopenharmony_ci .variants 3219625d8cSopenharmony_ci .iter() 3319625d8cSopenharmony_ci .map(|variant| { 3419625d8cSopenharmony_ci let item = 3519625d8cSopenharmony_ci Item::from_subcommand_variant(variant, item.casing(), item.env_casing())?; 3619625d8cSopenharmony_ci Ok((variant, item)) 3719625d8cSopenharmony_ci }) 3819625d8cSopenharmony_ci .collect::<Result<Vec<_>, syn::Error>>()?; 3919625d8cSopenharmony_ci gen_for_enum(&item, ident, &input.generics, &variants) 4019625d8cSopenharmony_ci } 4119625d8cSopenharmony_ci _ => abort_call_site!("`#[derive(Subcommand)]` only supports enums"), 4219625d8cSopenharmony_ci } 4319625d8cSopenharmony_ci} 4419625d8cSopenharmony_ci 4519625d8cSopenharmony_cipub fn gen_for_enum( 4619625d8cSopenharmony_ci item: &Item, 4719625d8cSopenharmony_ci item_name: &Ident, 4819625d8cSopenharmony_ci generics: &Generics, 4919625d8cSopenharmony_ci variants: &[(&Variant, Item)], 5019625d8cSopenharmony_ci) -> Result<TokenStream, syn::Error> { 5119625d8cSopenharmony_ci if !matches!(&*item.kind(), Kind::Command(_)) { 5219625d8cSopenharmony_ci abort! { item.kind().span(), 5319625d8cSopenharmony_ci "`{}` cannot be used with `command`", 5419625d8cSopenharmony_ci item.kind().name(), 5519625d8cSopenharmony_ci } 5619625d8cSopenharmony_ci } 5719625d8cSopenharmony_ci 5819625d8cSopenharmony_ci let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 5919625d8cSopenharmony_ci 6019625d8cSopenharmony_ci let from_arg_matches = gen_from_arg_matches(variants)?; 6119625d8cSopenharmony_ci let update_from_arg_matches = gen_update_from_arg_matches(variants)?; 6219625d8cSopenharmony_ci 6319625d8cSopenharmony_ci let augmentation = gen_augment(variants, item, false)?; 6419625d8cSopenharmony_ci let augmentation_update = gen_augment(variants, item, true)?; 6519625d8cSopenharmony_ci let has_subcommand = gen_has_subcommand(variants)?; 6619625d8cSopenharmony_ci 6719625d8cSopenharmony_ci Ok(quote! { 6819625d8cSopenharmony_ci #[allow(dead_code, unreachable_code, unused_variables, unused_braces)] 6919625d8cSopenharmony_ci #[allow( 7019625d8cSopenharmony_ci clippy::style, 7119625d8cSopenharmony_ci clippy::complexity, 7219625d8cSopenharmony_ci clippy::pedantic, 7319625d8cSopenharmony_ci clippy::restriction, 7419625d8cSopenharmony_ci clippy::perf, 7519625d8cSopenharmony_ci clippy::deprecated, 7619625d8cSopenharmony_ci clippy::nursery, 7719625d8cSopenharmony_ci clippy::cargo, 7819625d8cSopenharmony_ci clippy::suspicious_else_formatting, 7919625d8cSopenharmony_ci clippy::almost_swapped, 8019625d8cSopenharmony_ci )] 8119625d8cSopenharmony_ci impl #impl_generics clap::FromArgMatches for #item_name #ty_generics #where_clause { 8219625d8cSopenharmony_ci fn from_arg_matches(__clap_arg_matches: &clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> { 8319625d8cSopenharmony_ci Self::from_arg_matches_mut(&mut __clap_arg_matches.clone()) 8419625d8cSopenharmony_ci } 8519625d8cSopenharmony_ci 8619625d8cSopenharmony_ci #from_arg_matches 8719625d8cSopenharmony_ci 8819625d8cSopenharmony_ci fn update_from_arg_matches(&mut self, __clap_arg_matches: &clap::ArgMatches) -> ::std::result::Result<(), clap::Error> { 8919625d8cSopenharmony_ci self.update_from_arg_matches_mut(&mut __clap_arg_matches.clone()) 9019625d8cSopenharmony_ci } 9119625d8cSopenharmony_ci #update_from_arg_matches 9219625d8cSopenharmony_ci } 9319625d8cSopenharmony_ci 9419625d8cSopenharmony_ci #[allow(dead_code, unreachable_code, unused_variables, unused_braces)] 9519625d8cSopenharmony_ci #[allow( 9619625d8cSopenharmony_ci clippy::style, 9719625d8cSopenharmony_ci clippy::complexity, 9819625d8cSopenharmony_ci clippy::pedantic, 9919625d8cSopenharmony_ci clippy::restriction, 10019625d8cSopenharmony_ci clippy::perf, 10119625d8cSopenharmony_ci clippy::deprecated, 10219625d8cSopenharmony_ci clippy::nursery, 10319625d8cSopenharmony_ci clippy::cargo, 10419625d8cSopenharmony_ci clippy::suspicious_else_formatting, 10519625d8cSopenharmony_ci clippy::almost_swapped, 10619625d8cSopenharmony_ci )] 10719625d8cSopenharmony_ci impl #impl_generics clap::Subcommand for #item_name #ty_generics #where_clause { 10819625d8cSopenharmony_ci fn augment_subcommands <'b>(__clap_app: clap::Command) -> clap::Command { 10919625d8cSopenharmony_ci #augmentation 11019625d8cSopenharmony_ci } 11119625d8cSopenharmony_ci fn augment_subcommands_for_update <'b>(__clap_app: clap::Command) -> clap::Command { 11219625d8cSopenharmony_ci #augmentation_update 11319625d8cSopenharmony_ci } 11419625d8cSopenharmony_ci fn has_subcommand(__clap_name: &str) -> bool { 11519625d8cSopenharmony_ci #has_subcommand 11619625d8cSopenharmony_ci } 11719625d8cSopenharmony_ci } 11819625d8cSopenharmony_ci }) 11919625d8cSopenharmony_ci} 12019625d8cSopenharmony_ci 12119625d8cSopenharmony_cifn gen_augment( 12219625d8cSopenharmony_ci variants: &[(&Variant, Item)], 12319625d8cSopenharmony_ci parent_item: &Item, 12419625d8cSopenharmony_ci override_required: bool, 12519625d8cSopenharmony_ci) -> Result<TokenStream, syn::Error> { 12619625d8cSopenharmony_ci use syn::Fields::*; 12719625d8cSopenharmony_ci 12819625d8cSopenharmony_ci let app_var = Ident::new("__clap_app", Span::call_site()); 12919625d8cSopenharmony_ci 13019625d8cSopenharmony_ci let mut subcommands = Vec::new(); 13119625d8cSopenharmony_ci for (variant, item) in variants { 13219625d8cSopenharmony_ci let kind = item.kind(); 13319625d8cSopenharmony_ci 13419625d8cSopenharmony_ci let genned = match &*kind { 13519625d8cSopenharmony_ci Kind::Skip(_, _) | Kind::Arg(_) | Kind::FromGlobal(_) | Kind::Value => None, 13619625d8cSopenharmony_ci 13719625d8cSopenharmony_ci Kind::ExternalSubcommand => { 13819625d8cSopenharmony_ci let ty = match variant.fields { 13919625d8cSopenharmony_ci Unnamed(ref fields) if fields.unnamed.len() == 1 => &fields.unnamed[0].ty, 14019625d8cSopenharmony_ci 14119625d8cSopenharmony_ci _ => abort!( 14219625d8cSopenharmony_ci variant, 14319625d8cSopenharmony_ci "The enum variant marked with `external_subcommand` must be \ 14419625d8cSopenharmony_ci a single-typed tuple, and the type must be either `Vec<String>` \ 14519625d8cSopenharmony_ci or `Vec<OsString>`." 14619625d8cSopenharmony_ci ), 14719625d8cSopenharmony_ci }; 14819625d8cSopenharmony_ci let deprecations = if !override_required { 14919625d8cSopenharmony_ci item.deprecations() 15019625d8cSopenharmony_ci } else { 15119625d8cSopenharmony_ci quote!() 15219625d8cSopenharmony_ci }; 15319625d8cSopenharmony_ci let subty = subty_if_name(ty, "Vec").ok_or_else(|| { 15419625d8cSopenharmony_ci format_err!( 15519625d8cSopenharmony_ci ty.span(), 15619625d8cSopenharmony_ci "The type must be `Vec<_>` \ 15719625d8cSopenharmony_ci to be used with `external_subcommand`." 15819625d8cSopenharmony_ci ) 15919625d8cSopenharmony_ci })?; 16019625d8cSopenharmony_ci let subcommand = quote_spanned! { kind.span()=> 16119625d8cSopenharmony_ci #deprecations 16219625d8cSopenharmony_ci let #app_var = #app_var 16319625d8cSopenharmony_ci .external_subcommand_value_parser(clap::value_parser!(#subty)); 16419625d8cSopenharmony_ci }; 16519625d8cSopenharmony_ci Some(subcommand) 16619625d8cSopenharmony_ci } 16719625d8cSopenharmony_ci 16819625d8cSopenharmony_ci Kind::Flatten(_) => match variant.fields { 16919625d8cSopenharmony_ci Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => { 17019625d8cSopenharmony_ci let ty = &unnamed[0]; 17119625d8cSopenharmony_ci let deprecations = if !override_required { 17219625d8cSopenharmony_ci item.deprecations() 17319625d8cSopenharmony_ci } else { 17419625d8cSopenharmony_ci quote!() 17519625d8cSopenharmony_ci }; 17619625d8cSopenharmony_ci let next_help_heading = item.next_help_heading(); 17719625d8cSopenharmony_ci let next_display_order = item.next_display_order(); 17819625d8cSopenharmony_ci let subcommand = if override_required { 17919625d8cSopenharmony_ci quote! { 18019625d8cSopenharmony_ci #deprecations 18119625d8cSopenharmony_ci let #app_var = #app_var 18219625d8cSopenharmony_ci #next_help_heading 18319625d8cSopenharmony_ci #next_display_order; 18419625d8cSopenharmony_ci let #app_var = <#ty as clap::Subcommand>::augment_subcommands_for_update(#app_var); 18519625d8cSopenharmony_ci } 18619625d8cSopenharmony_ci } else { 18719625d8cSopenharmony_ci quote! { 18819625d8cSopenharmony_ci #deprecations 18919625d8cSopenharmony_ci let #app_var = #app_var 19019625d8cSopenharmony_ci #next_help_heading 19119625d8cSopenharmony_ci #next_display_order; 19219625d8cSopenharmony_ci let #app_var = <#ty as clap::Subcommand>::augment_subcommands(#app_var); 19319625d8cSopenharmony_ci } 19419625d8cSopenharmony_ci }; 19519625d8cSopenharmony_ci Some(subcommand) 19619625d8cSopenharmony_ci } 19719625d8cSopenharmony_ci _ => abort!( 19819625d8cSopenharmony_ci variant, 19919625d8cSopenharmony_ci "`flatten` is usable only with single-typed tuple variants" 20019625d8cSopenharmony_ci ), 20119625d8cSopenharmony_ci }, 20219625d8cSopenharmony_ci 20319625d8cSopenharmony_ci Kind::Subcommand(_) => { 20419625d8cSopenharmony_ci let subcommand_var = Ident::new("__clap_subcommand", Span::call_site()); 20519625d8cSopenharmony_ci let arg_block = match variant.fields { 20619625d8cSopenharmony_ci Named(_) => { 20719625d8cSopenharmony_ci abort!(variant, "non single-typed tuple enums are not supported") 20819625d8cSopenharmony_ci } 20919625d8cSopenharmony_ci Unit => quote!( #subcommand_var ), 21019625d8cSopenharmony_ci Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => { 21119625d8cSopenharmony_ci let ty = &unnamed[0]; 21219625d8cSopenharmony_ci if override_required { 21319625d8cSopenharmony_ci quote_spanned! { ty.span()=> 21419625d8cSopenharmony_ci { 21519625d8cSopenharmony_ci <#ty as clap::Subcommand>::augment_subcommands_for_update(#subcommand_var) 21619625d8cSopenharmony_ci } 21719625d8cSopenharmony_ci } 21819625d8cSopenharmony_ci } else { 21919625d8cSopenharmony_ci quote_spanned! { ty.span()=> 22019625d8cSopenharmony_ci { 22119625d8cSopenharmony_ci <#ty as clap::Subcommand>::augment_subcommands(#subcommand_var) 22219625d8cSopenharmony_ci } 22319625d8cSopenharmony_ci } 22419625d8cSopenharmony_ci } 22519625d8cSopenharmony_ci } 22619625d8cSopenharmony_ci Unnamed(..) => { 22719625d8cSopenharmony_ci abort!(variant, "non single-typed tuple enums are not supported") 22819625d8cSopenharmony_ci } 22919625d8cSopenharmony_ci }; 23019625d8cSopenharmony_ci 23119625d8cSopenharmony_ci let name = item.cased_name(); 23219625d8cSopenharmony_ci let deprecations = if !override_required { 23319625d8cSopenharmony_ci item.deprecations() 23419625d8cSopenharmony_ci } else { 23519625d8cSopenharmony_ci quote!() 23619625d8cSopenharmony_ci }; 23719625d8cSopenharmony_ci let initial_app_methods = item.initial_top_level_methods(); 23819625d8cSopenharmony_ci let final_from_attrs = item.final_top_level_methods(); 23919625d8cSopenharmony_ci let override_methods = if override_required { 24019625d8cSopenharmony_ci quote_spanned! { kind.span()=> 24119625d8cSopenharmony_ci .subcommand_required(false) 24219625d8cSopenharmony_ci .arg_required_else_help(false) 24319625d8cSopenharmony_ci } 24419625d8cSopenharmony_ci } else { 24519625d8cSopenharmony_ci quote!() 24619625d8cSopenharmony_ci }; 24719625d8cSopenharmony_ci let subcommand = quote! { 24819625d8cSopenharmony_ci let #app_var = #app_var.subcommand({ 24919625d8cSopenharmony_ci #deprecations; 25019625d8cSopenharmony_ci let #subcommand_var = clap::Command::new(#name); 25119625d8cSopenharmony_ci let #subcommand_var = #subcommand_var 25219625d8cSopenharmony_ci .subcommand_required(true) 25319625d8cSopenharmony_ci .arg_required_else_help(true); 25419625d8cSopenharmony_ci let #subcommand_var = #subcommand_var #initial_app_methods; 25519625d8cSopenharmony_ci let #subcommand_var = #arg_block; 25619625d8cSopenharmony_ci #subcommand_var #final_from_attrs #override_methods 25719625d8cSopenharmony_ci }); 25819625d8cSopenharmony_ci }; 25919625d8cSopenharmony_ci Some(subcommand) 26019625d8cSopenharmony_ci } 26119625d8cSopenharmony_ci 26219625d8cSopenharmony_ci Kind::Command(_) => { 26319625d8cSopenharmony_ci let subcommand_var = Ident::new("__clap_subcommand", Span::call_site()); 26419625d8cSopenharmony_ci let sub_augment = match variant.fields { 26519625d8cSopenharmony_ci Named(ref fields) => { 26619625d8cSopenharmony_ci // Defer to `gen_augment` for adding cmd methods 26719625d8cSopenharmony_ci let fields = fields 26819625d8cSopenharmony_ci .named 26919625d8cSopenharmony_ci .iter() 27019625d8cSopenharmony_ci .map(|field| { 27119625d8cSopenharmony_ci let item = 27219625d8cSopenharmony_ci Item::from_args_field(field, item.casing(), item.env_casing())?; 27319625d8cSopenharmony_ci Ok((field, item)) 27419625d8cSopenharmony_ci }) 27519625d8cSopenharmony_ci .collect::<Result<Vec<_>, syn::Error>>()?; 27619625d8cSopenharmony_ci args::gen_augment(&fields, &subcommand_var, item, override_required)? 27719625d8cSopenharmony_ci } 27819625d8cSopenharmony_ci Unit => { 27919625d8cSopenharmony_ci let arg_block = quote!( #subcommand_var ); 28019625d8cSopenharmony_ci let initial_app_methods = item.initial_top_level_methods(); 28119625d8cSopenharmony_ci let final_from_attrs = item.final_top_level_methods(); 28219625d8cSopenharmony_ci quote! { 28319625d8cSopenharmony_ci let #subcommand_var = #subcommand_var #initial_app_methods; 28419625d8cSopenharmony_ci let #subcommand_var = #arg_block; 28519625d8cSopenharmony_ci #subcommand_var #final_from_attrs 28619625d8cSopenharmony_ci } 28719625d8cSopenharmony_ci } 28819625d8cSopenharmony_ci Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => { 28919625d8cSopenharmony_ci let ty = &unnamed[0]; 29019625d8cSopenharmony_ci let arg_block = if override_required { 29119625d8cSopenharmony_ci quote_spanned! { ty.span()=> 29219625d8cSopenharmony_ci { 29319625d8cSopenharmony_ci <#ty as clap::Args>::augment_args_for_update(#subcommand_var) 29419625d8cSopenharmony_ci } 29519625d8cSopenharmony_ci } 29619625d8cSopenharmony_ci } else { 29719625d8cSopenharmony_ci quote_spanned! { ty.span()=> 29819625d8cSopenharmony_ci { 29919625d8cSopenharmony_ci <#ty as clap::Args>::augment_args(#subcommand_var) 30019625d8cSopenharmony_ci } 30119625d8cSopenharmony_ci } 30219625d8cSopenharmony_ci }; 30319625d8cSopenharmony_ci let initial_app_methods = item.initial_top_level_methods(); 30419625d8cSopenharmony_ci let final_from_attrs = item.final_top_level_methods(); 30519625d8cSopenharmony_ci quote! { 30619625d8cSopenharmony_ci let #subcommand_var = #subcommand_var #initial_app_methods; 30719625d8cSopenharmony_ci let #subcommand_var = #arg_block; 30819625d8cSopenharmony_ci #subcommand_var #final_from_attrs 30919625d8cSopenharmony_ci } 31019625d8cSopenharmony_ci } 31119625d8cSopenharmony_ci Unnamed(..) => { 31219625d8cSopenharmony_ci abort!(variant, "non single-typed tuple enums are not supported") 31319625d8cSopenharmony_ci } 31419625d8cSopenharmony_ci }; 31519625d8cSopenharmony_ci 31619625d8cSopenharmony_ci let deprecations = if !override_required { 31719625d8cSopenharmony_ci item.deprecations() 31819625d8cSopenharmony_ci } else { 31919625d8cSopenharmony_ci quote!() 32019625d8cSopenharmony_ci }; 32119625d8cSopenharmony_ci let name = item.cased_name(); 32219625d8cSopenharmony_ci let subcommand = quote! { 32319625d8cSopenharmony_ci let #app_var = #app_var.subcommand({ 32419625d8cSopenharmony_ci #deprecations 32519625d8cSopenharmony_ci let #subcommand_var = clap::Command::new(#name); 32619625d8cSopenharmony_ci #sub_augment 32719625d8cSopenharmony_ci }); 32819625d8cSopenharmony_ci }; 32919625d8cSopenharmony_ci Some(subcommand) 33019625d8cSopenharmony_ci } 33119625d8cSopenharmony_ci }; 33219625d8cSopenharmony_ci subcommands.push(genned); 33319625d8cSopenharmony_ci } 33419625d8cSopenharmony_ci 33519625d8cSopenharmony_ci let deprecations = if !override_required { 33619625d8cSopenharmony_ci parent_item.deprecations() 33719625d8cSopenharmony_ci } else { 33819625d8cSopenharmony_ci quote!() 33919625d8cSopenharmony_ci }; 34019625d8cSopenharmony_ci let initial_app_methods = parent_item.initial_top_level_methods(); 34119625d8cSopenharmony_ci let final_app_methods = parent_item.final_top_level_methods(); 34219625d8cSopenharmony_ci Ok(quote! { 34319625d8cSopenharmony_ci #deprecations; 34419625d8cSopenharmony_ci let #app_var = #app_var #initial_app_methods; 34519625d8cSopenharmony_ci #( #subcommands )*; 34619625d8cSopenharmony_ci #app_var #final_app_methods 34719625d8cSopenharmony_ci }) 34819625d8cSopenharmony_ci} 34919625d8cSopenharmony_ci 35019625d8cSopenharmony_cifn gen_has_subcommand(variants: &[(&Variant, Item)]) -> Result<TokenStream, syn::Error> { 35119625d8cSopenharmony_ci use syn::Fields::*; 35219625d8cSopenharmony_ci 35319625d8cSopenharmony_ci let mut ext_subcmd = false; 35419625d8cSopenharmony_ci 35519625d8cSopenharmony_ci let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants 35619625d8cSopenharmony_ci .iter() 35719625d8cSopenharmony_ci .filter_map(|(variant, item)| { 35819625d8cSopenharmony_ci let kind = item.kind(); 35919625d8cSopenharmony_ci match &*kind { 36019625d8cSopenharmony_ci Kind::Skip(_, _) | Kind::Arg(_) | Kind::FromGlobal(_) | Kind::Value => None, 36119625d8cSopenharmony_ci 36219625d8cSopenharmony_ci Kind::ExternalSubcommand => { 36319625d8cSopenharmony_ci ext_subcmd = true; 36419625d8cSopenharmony_ci None 36519625d8cSopenharmony_ci } 36619625d8cSopenharmony_ci Kind::Flatten(_) | Kind::Subcommand(_) | Kind::Command(_) => Some((variant, item)), 36719625d8cSopenharmony_ci } 36819625d8cSopenharmony_ci }) 36919625d8cSopenharmony_ci .partition(|(_, item)| { 37019625d8cSopenharmony_ci let kind = item.kind(); 37119625d8cSopenharmony_ci matches!(&*kind, Kind::Flatten(_)) 37219625d8cSopenharmony_ci }); 37319625d8cSopenharmony_ci 37419625d8cSopenharmony_ci let subcommands = variants.iter().map(|(_variant, item)| { 37519625d8cSopenharmony_ci let sub_name = item.cased_name(); 37619625d8cSopenharmony_ci quote! { 37719625d8cSopenharmony_ci if #sub_name == __clap_name { 37819625d8cSopenharmony_ci return true 37919625d8cSopenharmony_ci } 38019625d8cSopenharmony_ci } 38119625d8cSopenharmony_ci }); 38219625d8cSopenharmony_ci let child_subcommands = flatten_variants 38319625d8cSopenharmony_ci .iter() 38419625d8cSopenharmony_ci .map(|(variant, _attrs)| match variant.fields { 38519625d8cSopenharmony_ci Unnamed(ref fields) if fields.unnamed.len() == 1 => { 38619625d8cSopenharmony_ci let ty = &fields.unnamed[0]; 38719625d8cSopenharmony_ci Ok(quote! { 38819625d8cSopenharmony_ci if <#ty as clap::Subcommand>::has_subcommand(__clap_name) { 38919625d8cSopenharmony_ci return true; 39019625d8cSopenharmony_ci } 39119625d8cSopenharmony_ci }) 39219625d8cSopenharmony_ci } 39319625d8cSopenharmony_ci _ => abort!( 39419625d8cSopenharmony_ci variant, 39519625d8cSopenharmony_ci "`flatten` is usable only with single-typed tuple variants" 39619625d8cSopenharmony_ci ), 39719625d8cSopenharmony_ci }) 39819625d8cSopenharmony_ci .collect::<Result<Vec<_>, syn::Error>>()?; 39919625d8cSopenharmony_ci 40019625d8cSopenharmony_ci let genned = if ext_subcmd { 40119625d8cSopenharmony_ci quote! { true } 40219625d8cSopenharmony_ci } else { 40319625d8cSopenharmony_ci quote! { 40419625d8cSopenharmony_ci #( #subcommands )* 40519625d8cSopenharmony_ci 40619625d8cSopenharmony_ci #( #child_subcommands )else* 40719625d8cSopenharmony_ci 40819625d8cSopenharmony_ci false 40919625d8cSopenharmony_ci } 41019625d8cSopenharmony_ci }; 41119625d8cSopenharmony_ci Ok(genned) 41219625d8cSopenharmony_ci} 41319625d8cSopenharmony_ci 41419625d8cSopenharmony_cifn gen_from_arg_matches(variants: &[(&Variant, Item)]) -> Result<TokenStream, syn::Error> { 41519625d8cSopenharmony_ci use syn::Fields::*; 41619625d8cSopenharmony_ci 41719625d8cSopenharmony_ci let subcommand_name_var = format_ident!("__clap_name"); 41819625d8cSopenharmony_ci let sub_arg_matches_var = format_ident!("__clap_arg_matches"); 41919625d8cSopenharmony_ci 42019625d8cSopenharmony_ci let mut ext_subcmd = None; 42119625d8cSopenharmony_ci let mut flatten_variants = Vec::new(); 42219625d8cSopenharmony_ci let mut unflatten_variants = Vec::new(); 42319625d8cSopenharmony_ci for (variant, item) in variants { 42419625d8cSopenharmony_ci let kind = item.kind(); 42519625d8cSopenharmony_ci match &*kind { 42619625d8cSopenharmony_ci Kind::Skip(_, _) | Kind::Arg(_) | Kind::FromGlobal(_) | Kind::Value => {} 42719625d8cSopenharmony_ci 42819625d8cSopenharmony_ci Kind::ExternalSubcommand => { 42919625d8cSopenharmony_ci if ext_subcmd.is_some() { 43019625d8cSopenharmony_ci abort!( 43119625d8cSopenharmony_ci item.kind().span(), 43219625d8cSopenharmony_ci "Only one variant can be marked with `external_subcommand`, \ 43319625d8cSopenharmony_ci this is the second" 43419625d8cSopenharmony_ci ); 43519625d8cSopenharmony_ci } 43619625d8cSopenharmony_ci 43719625d8cSopenharmony_ci let ty = match variant.fields { 43819625d8cSopenharmony_ci Unnamed(ref fields) if fields.unnamed.len() == 1 => &fields.unnamed[0].ty, 43919625d8cSopenharmony_ci 44019625d8cSopenharmony_ci _ => abort!( 44119625d8cSopenharmony_ci variant, 44219625d8cSopenharmony_ci "The enum variant marked with `external_subcommand` must be \ 44319625d8cSopenharmony_ci a single-typed tuple, and the type must be either `Vec<String>` \ 44419625d8cSopenharmony_ci or `Vec<OsString>`." 44519625d8cSopenharmony_ci ), 44619625d8cSopenharmony_ci }; 44719625d8cSopenharmony_ci 44819625d8cSopenharmony_ci let (span, str_ty) = match subty_if_name(ty, "Vec") { 44919625d8cSopenharmony_ci Some(subty) => { 45019625d8cSopenharmony_ci if is_simple_ty(subty, "String") { 45119625d8cSopenharmony_ci (subty.span(), quote!(::std::string::String)) 45219625d8cSopenharmony_ci } else if is_simple_ty(subty, "OsString") { 45319625d8cSopenharmony_ci (subty.span(), quote!(::std::ffi::OsString)) 45419625d8cSopenharmony_ci } else { 45519625d8cSopenharmony_ci abort!( 45619625d8cSopenharmony_ci ty.span(), 45719625d8cSopenharmony_ci "The type must be either `Vec<String>` or `Vec<OsString>` \ 45819625d8cSopenharmony_ci to be used with `external_subcommand`." 45919625d8cSopenharmony_ci ); 46019625d8cSopenharmony_ci } 46119625d8cSopenharmony_ci } 46219625d8cSopenharmony_ci 46319625d8cSopenharmony_ci None => abort!( 46419625d8cSopenharmony_ci ty.span(), 46519625d8cSopenharmony_ci "The type must be either `Vec<String>` or `Vec<OsString>` \ 46619625d8cSopenharmony_ci to be used with `external_subcommand`." 46719625d8cSopenharmony_ci ), 46819625d8cSopenharmony_ci }; 46919625d8cSopenharmony_ci 47019625d8cSopenharmony_ci ext_subcmd = Some((span, &variant.ident, str_ty)); 47119625d8cSopenharmony_ci } 47219625d8cSopenharmony_ci Kind::Flatten(_) | Kind::Subcommand(_) | Kind::Command(_) => { 47319625d8cSopenharmony_ci if matches!(&*item.kind(), Kind::Flatten(_)) { 47419625d8cSopenharmony_ci flatten_variants.push((variant, item)); 47519625d8cSopenharmony_ci } else { 47619625d8cSopenharmony_ci unflatten_variants.push((variant, item)); 47719625d8cSopenharmony_ci } 47819625d8cSopenharmony_ci } 47919625d8cSopenharmony_ci } 48019625d8cSopenharmony_ci } 48119625d8cSopenharmony_ci 48219625d8cSopenharmony_ci let subcommands = unflatten_variants.iter().map(|(variant, item)| { 48319625d8cSopenharmony_ci let sub_name = item.cased_name(); 48419625d8cSopenharmony_ci let variant_name = &variant.ident; 48519625d8cSopenharmony_ci let constructor_block = match variant.fields { 48619625d8cSopenharmony_ci Named(ref fields) => { 48719625d8cSopenharmony_ci let fields = fields 48819625d8cSopenharmony_ci .named 48919625d8cSopenharmony_ci .iter() 49019625d8cSopenharmony_ci .map(|field| { 49119625d8cSopenharmony_ci let item = Item::from_args_field(field, item.casing(), item.env_casing())?; 49219625d8cSopenharmony_ci Ok((field, item)) 49319625d8cSopenharmony_ci }) 49419625d8cSopenharmony_ci .collect::<Result<Vec<_>, syn::Error>>()?; 49519625d8cSopenharmony_ci args::gen_constructor(&fields)? 49619625d8cSopenharmony_ci }, 49719625d8cSopenharmony_ci Unit => quote!(), 49819625d8cSopenharmony_ci Unnamed(ref fields) if fields.unnamed.len() == 1 => { 49919625d8cSopenharmony_ci let ty = &fields.unnamed[0]; 50019625d8cSopenharmony_ci quote!( ( <#ty as clap::FromArgMatches>::from_arg_matches_mut(__clap_arg_matches)? ) ) 50119625d8cSopenharmony_ci } 50219625d8cSopenharmony_ci Unnamed(..) => abort_call_site!("{}: tuple enums are not supported", variant.ident), 50319625d8cSopenharmony_ci }; 50419625d8cSopenharmony_ci 50519625d8cSopenharmony_ci Ok(quote! { 50619625d8cSopenharmony_ci if #subcommand_name_var == #sub_name && !#sub_arg_matches_var.contains_id("") { 50719625d8cSopenharmony_ci return ::std::result::Result::Ok(Self :: #variant_name #constructor_block) 50819625d8cSopenharmony_ci } 50919625d8cSopenharmony_ci }) 51019625d8cSopenharmony_ci }).collect::<Result<Vec<_>, syn::Error>>()?; 51119625d8cSopenharmony_ci let child_subcommands = flatten_variants.iter().map(|(variant, _attrs)| { 51219625d8cSopenharmony_ci let variant_name = &variant.ident; 51319625d8cSopenharmony_ci match variant.fields { 51419625d8cSopenharmony_ci Unnamed(ref fields) if fields.unnamed.len() == 1 => { 51519625d8cSopenharmony_ci let ty = &fields.unnamed[0]; 51619625d8cSopenharmony_ci Ok(quote! { 51719625d8cSopenharmony_ci if __clap_arg_matches 51819625d8cSopenharmony_ci .subcommand_name() 51919625d8cSopenharmony_ci .map(|__clap_name| <#ty as clap::Subcommand>::has_subcommand(__clap_name)) 52019625d8cSopenharmony_ci .unwrap_or_default() 52119625d8cSopenharmony_ci { 52219625d8cSopenharmony_ci let __clap_res = <#ty as clap::FromArgMatches>::from_arg_matches_mut(__clap_arg_matches)?; 52319625d8cSopenharmony_ci return ::std::result::Result::Ok(Self :: #variant_name (__clap_res)); 52419625d8cSopenharmony_ci } 52519625d8cSopenharmony_ci }) 52619625d8cSopenharmony_ci } 52719625d8cSopenharmony_ci _ => abort!( 52819625d8cSopenharmony_ci variant, 52919625d8cSopenharmony_ci "`flatten` is usable only with single-typed tuple variants" 53019625d8cSopenharmony_ci ), 53119625d8cSopenharmony_ci } 53219625d8cSopenharmony_ci }).collect::<Result<Vec<_>, syn::Error>>()?; 53319625d8cSopenharmony_ci 53419625d8cSopenharmony_ci let wildcard = match ext_subcmd { 53519625d8cSopenharmony_ci Some((span, var_name, str_ty)) => quote_spanned! { span=> 53619625d8cSopenharmony_ci ::std::result::Result::Ok(Self::#var_name( 53719625d8cSopenharmony_ci ::std::iter::once(#str_ty::from(#subcommand_name_var)) 53819625d8cSopenharmony_ci .chain( 53919625d8cSopenharmony_ci #sub_arg_matches_var 54019625d8cSopenharmony_ci .remove_many::<#str_ty>("") 54119625d8cSopenharmony_ci .unwrap() 54219625d8cSopenharmony_ci .map(#str_ty::from) 54319625d8cSopenharmony_ci ) 54419625d8cSopenharmony_ci .collect::<::std::vec::Vec<_>>() 54519625d8cSopenharmony_ci )) 54619625d8cSopenharmony_ci }, 54719625d8cSopenharmony_ci 54819625d8cSopenharmony_ci None => quote! { 54919625d8cSopenharmony_ci ::std::result::Result::Err(clap::Error::raw(clap::error::ErrorKind::InvalidSubcommand, format!("The subcommand '{}' wasn't recognized", #subcommand_name_var))) 55019625d8cSopenharmony_ci }, 55119625d8cSopenharmony_ci }; 55219625d8cSopenharmony_ci 55319625d8cSopenharmony_ci let raw_deprecated = args::raw_deprecated(); 55419625d8cSopenharmony_ci Ok(quote! { 55519625d8cSopenharmony_ci fn from_arg_matches_mut(__clap_arg_matches: &mut clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> { 55619625d8cSopenharmony_ci #raw_deprecated 55719625d8cSopenharmony_ci 55819625d8cSopenharmony_ci #( #child_subcommands )else* 55919625d8cSopenharmony_ci 56019625d8cSopenharmony_ci if let Some((#subcommand_name_var, mut __clap_arg_sub_matches)) = __clap_arg_matches.remove_subcommand() { 56119625d8cSopenharmony_ci let #sub_arg_matches_var = &mut __clap_arg_sub_matches; 56219625d8cSopenharmony_ci #( #subcommands )* 56319625d8cSopenharmony_ci 56419625d8cSopenharmony_ci #wildcard 56519625d8cSopenharmony_ci } else { 56619625d8cSopenharmony_ci ::std::result::Result::Err(clap::Error::raw(clap::error::ErrorKind::MissingSubcommand, "A subcommand is required but one was not provided.")) 56719625d8cSopenharmony_ci } 56819625d8cSopenharmony_ci } 56919625d8cSopenharmony_ci }) 57019625d8cSopenharmony_ci} 57119625d8cSopenharmony_ci 57219625d8cSopenharmony_cifn gen_update_from_arg_matches(variants: &[(&Variant, Item)]) -> Result<TokenStream, syn::Error> { 57319625d8cSopenharmony_ci use syn::Fields::*; 57419625d8cSopenharmony_ci 57519625d8cSopenharmony_ci let (flatten, variants): (Vec<_>, Vec<_>) = variants 57619625d8cSopenharmony_ci .iter() 57719625d8cSopenharmony_ci .filter_map(|(variant, item)| { 57819625d8cSopenharmony_ci let kind = item.kind(); 57919625d8cSopenharmony_ci match &*kind { 58019625d8cSopenharmony_ci // Fallback to `from_arg_matches_mut` 58119625d8cSopenharmony_ci Kind::Skip(_, _) 58219625d8cSopenharmony_ci | Kind::Arg(_) 58319625d8cSopenharmony_ci | Kind::FromGlobal(_) 58419625d8cSopenharmony_ci | Kind::Value 58519625d8cSopenharmony_ci | Kind::ExternalSubcommand => None, 58619625d8cSopenharmony_ci Kind::Flatten(_) | Kind::Subcommand(_) | Kind::Command(_) => Some((variant, item)), 58719625d8cSopenharmony_ci } 58819625d8cSopenharmony_ci }) 58919625d8cSopenharmony_ci .partition(|(_, item)| { 59019625d8cSopenharmony_ci let kind = item.kind(); 59119625d8cSopenharmony_ci matches!(&*kind, Kind::Flatten(_)) 59219625d8cSopenharmony_ci }); 59319625d8cSopenharmony_ci 59419625d8cSopenharmony_ci let subcommands = variants.iter().map(|(variant, item)| { 59519625d8cSopenharmony_ci let sub_name = item.cased_name(); 59619625d8cSopenharmony_ci let variant_name = &variant.ident; 59719625d8cSopenharmony_ci let (pattern, updater) = match variant.fields { 59819625d8cSopenharmony_ci Named(ref fields) => { 59919625d8cSopenharmony_ci let field_names = fields.named.iter().map(|field| { 60019625d8cSopenharmony_ci field.ident.as_ref().unwrap() 60119625d8cSopenharmony_ci }).collect::<Vec<_>>(); 60219625d8cSopenharmony_ci let fields = fields 60319625d8cSopenharmony_ci .named 60419625d8cSopenharmony_ci .iter() 60519625d8cSopenharmony_ci .map(|field| { 60619625d8cSopenharmony_ci let item = Item::from_args_field(field, item.casing(), item.env_casing())?; 60719625d8cSopenharmony_ci Ok((field, item)) 60819625d8cSopenharmony_ci }) 60919625d8cSopenharmony_ci .collect::<Result<Vec<_>, syn::Error>>()?; 61019625d8cSopenharmony_ci let update = args::gen_updater(&fields, false)?; 61119625d8cSopenharmony_ci (quote!( { #( #field_names, )* }), quote!( { #update } )) 61219625d8cSopenharmony_ci } 61319625d8cSopenharmony_ci Unit => (quote!(), quote!({})), 61419625d8cSopenharmony_ci Unnamed(ref fields) => { 61519625d8cSopenharmony_ci if fields.unnamed.len() == 1 { 61619625d8cSopenharmony_ci ( 61719625d8cSopenharmony_ci quote!((ref mut __clap_arg)), 61819625d8cSopenharmony_ci quote!(clap::FromArgMatches::update_from_arg_matches_mut( 61919625d8cSopenharmony_ci __clap_arg, 62019625d8cSopenharmony_ci __clap_arg_matches 62119625d8cSopenharmony_ci )?), 62219625d8cSopenharmony_ci ) 62319625d8cSopenharmony_ci } else { 62419625d8cSopenharmony_ci abort_call_site!("{}: tuple enums are not supported", variant.ident) 62519625d8cSopenharmony_ci } 62619625d8cSopenharmony_ci } 62719625d8cSopenharmony_ci }; 62819625d8cSopenharmony_ci 62919625d8cSopenharmony_ci Ok(quote! { 63019625d8cSopenharmony_ci Self :: #variant_name #pattern if #sub_name == __clap_name => { 63119625d8cSopenharmony_ci let (_, mut __clap_arg_sub_matches) = __clap_arg_matches.remove_subcommand().unwrap(); 63219625d8cSopenharmony_ci let __clap_arg_matches = &mut __clap_arg_sub_matches; 63319625d8cSopenharmony_ci #updater 63419625d8cSopenharmony_ci } 63519625d8cSopenharmony_ci }) 63619625d8cSopenharmony_ci }).collect::<Result<Vec<_>, _>>()?; 63719625d8cSopenharmony_ci 63819625d8cSopenharmony_ci let child_subcommands = flatten.iter().map(|(variant, _attrs)| { 63919625d8cSopenharmony_ci let variant_name = &variant.ident; 64019625d8cSopenharmony_ci match variant.fields { 64119625d8cSopenharmony_ci Unnamed(ref fields) if fields.unnamed.len() == 1 => { 64219625d8cSopenharmony_ci let ty = &fields.unnamed[0]; 64319625d8cSopenharmony_ci Ok(quote! { 64419625d8cSopenharmony_ci if <#ty as clap::Subcommand>::has_subcommand(__clap_name) { 64519625d8cSopenharmony_ci if let Self :: #variant_name (child) = s { 64619625d8cSopenharmony_ci <#ty as clap::FromArgMatches>::update_from_arg_matches_mut(child, __clap_arg_matches)?; 64719625d8cSopenharmony_ci return ::std::result::Result::Ok(()); 64819625d8cSopenharmony_ci } 64919625d8cSopenharmony_ci } 65019625d8cSopenharmony_ci }) 65119625d8cSopenharmony_ci } 65219625d8cSopenharmony_ci _ => abort!( 65319625d8cSopenharmony_ci variant, 65419625d8cSopenharmony_ci "`flatten` is usable only with single-typed tuple variants" 65519625d8cSopenharmony_ci ), 65619625d8cSopenharmony_ci } 65719625d8cSopenharmony_ci }).collect::<Result<Vec<_>, _>>()?; 65819625d8cSopenharmony_ci 65919625d8cSopenharmony_ci let raw_deprecated = args::raw_deprecated(); 66019625d8cSopenharmony_ci Ok(quote! { 66119625d8cSopenharmony_ci fn update_from_arg_matches_mut<'b>( 66219625d8cSopenharmony_ci &mut self, 66319625d8cSopenharmony_ci __clap_arg_matches: &mut clap::ArgMatches, 66419625d8cSopenharmony_ci ) -> ::std::result::Result<(), clap::Error> { 66519625d8cSopenharmony_ci #raw_deprecated 66619625d8cSopenharmony_ci 66719625d8cSopenharmony_ci if let Some(__clap_name) = __clap_arg_matches.subcommand_name() { 66819625d8cSopenharmony_ci match self { 66919625d8cSopenharmony_ci #( #subcommands ),* 67019625d8cSopenharmony_ci s => { 67119625d8cSopenharmony_ci #( #child_subcommands )* 67219625d8cSopenharmony_ci *s = <Self as clap::FromArgMatches>::from_arg_matches_mut(__clap_arg_matches)?; 67319625d8cSopenharmony_ci } 67419625d8cSopenharmony_ci } 67519625d8cSopenharmony_ci } 67619625d8cSopenharmony_ci ::std::result::Result::Ok(()) 67719625d8cSopenharmony_ci } 67819625d8cSopenharmony_ci }) 67919625d8cSopenharmony_ci} 680