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::ext::IdentExt; 1819625d8cSopenharmony_ciuse syn::{ 1919625d8cSopenharmony_ci punctuated::Punctuated, spanned::Spanned, token::Comma, Data, DataStruct, DeriveInput, Field, 2019625d8cSopenharmony_ci Fields, Generics, 2119625d8cSopenharmony_ci}; 2219625d8cSopenharmony_ci 2319625d8cSopenharmony_ciuse crate::item::{Item, Kind, Name}; 2419625d8cSopenharmony_ciuse crate::utils::{inner_type, sub_type, Sp, Ty}; 2519625d8cSopenharmony_ci 2619625d8cSopenharmony_cipub fn derive_args(input: &DeriveInput) -> Result<TokenStream, syn::Error> { 2719625d8cSopenharmony_ci let ident = &input.ident; 2819625d8cSopenharmony_ci 2919625d8cSopenharmony_ci match input.data { 3019625d8cSopenharmony_ci Data::Struct(DataStruct { 3119625d8cSopenharmony_ci fields: Fields::Named(ref fields), 3219625d8cSopenharmony_ci .. 3319625d8cSopenharmony_ci }) => { 3419625d8cSopenharmony_ci let name = Name::Derived(ident.clone()); 3519625d8cSopenharmony_ci let item = Item::from_args_struct(input, name)?; 3619625d8cSopenharmony_ci let fields = fields 3719625d8cSopenharmony_ci .named 3819625d8cSopenharmony_ci .iter() 3919625d8cSopenharmony_ci .map(|field| { 4019625d8cSopenharmony_ci let item = Item::from_args_field(field, item.casing(), item.env_casing())?; 4119625d8cSopenharmony_ci Ok((field, item)) 4219625d8cSopenharmony_ci }) 4319625d8cSopenharmony_ci .collect::<Result<Vec<_>, syn::Error>>()?; 4419625d8cSopenharmony_ci gen_for_struct(&item, ident, &input.generics, &fields) 4519625d8cSopenharmony_ci } 4619625d8cSopenharmony_ci Data::Struct(DataStruct { 4719625d8cSopenharmony_ci fields: Fields::Unit, 4819625d8cSopenharmony_ci .. 4919625d8cSopenharmony_ci }) => { 5019625d8cSopenharmony_ci let name = Name::Derived(ident.clone()); 5119625d8cSopenharmony_ci let item = Item::from_args_struct(input, name)?; 5219625d8cSopenharmony_ci let fields = Punctuated::<Field, Comma>::new(); 5319625d8cSopenharmony_ci let fields = fields 5419625d8cSopenharmony_ci .iter() 5519625d8cSopenharmony_ci .map(|field| { 5619625d8cSopenharmony_ci let item = Item::from_args_field(field, item.casing(), item.env_casing())?; 5719625d8cSopenharmony_ci Ok((field, item)) 5819625d8cSopenharmony_ci }) 5919625d8cSopenharmony_ci .collect::<Result<Vec<_>, syn::Error>>()?; 6019625d8cSopenharmony_ci gen_for_struct(&item, ident, &input.generics, &fields) 6119625d8cSopenharmony_ci } 6219625d8cSopenharmony_ci _ => abort_call_site!("`#[derive(Args)]` only supports non-tuple structs"), 6319625d8cSopenharmony_ci } 6419625d8cSopenharmony_ci} 6519625d8cSopenharmony_ci 6619625d8cSopenharmony_cipub fn gen_for_struct( 6719625d8cSopenharmony_ci item: &Item, 6819625d8cSopenharmony_ci item_name: &Ident, 6919625d8cSopenharmony_ci generics: &Generics, 7019625d8cSopenharmony_ci fields: &[(&Field, Item)], 7119625d8cSopenharmony_ci) -> Result<TokenStream, syn::Error> { 7219625d8cSopenharmony_ci if !matches!(&*item.kind(), Kind::Command(_)) { 7319625d8cSopenharmony_ci abort! { item.kind().span(), 7419625d8cSopenharmony_ci "`{}` cannot be used with `command`", 7519625d8cSopenharmony_ci item.kind().name(), 7619625d8cSopenharmony_ci } 7719625d8cSopenharmony_ci } 7819625d8cSopenharmony_ci 7919625d8cSopenharmony_ci let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 8019625d8cSopenharmony_ci 8119625d8cSopenharmony_ci let constructor = gen_constructor(fields)?; 8219625d8cSopenharmony_ci let updater = gen_updater(fields, true)?; 8319625d8cSopenharmony_ci let raw_deprecated = raw_deprecated(); 8419625d8cSopenharmony_ci 8519625d8cSopenharmony_ci let app_var = Ident::new("__clap_app", Span::call_site()); 8619625d8cSopenharmony_ci let augmentation = gen_augment(fields, &app_var, item, false)?; 8719625d8cSopenharmony_ci let augmentation_update = gen_augment(fields, &app_var, item, true)?; 8819625d8cSopenharmony_ci 8919625d8cSopenharmony_ci let group_id = if item.skip_group() { 9019625d8cSopenharmony_ci quote!(None) 9119625d8cSopenharmony_ci } else { 9219625d8cSopenharmony_ci let group_id = item.ident().unraw().to_string(); 9319625d8cSopenharmony_ci quote!(Some(clap::Id::from(#group_id))) 9419625d8cSopenharmony_ci }; 9519625d8cSopenharmony_ci 9619625d8cSopenharmony_ci Ok(quote! { 9719625d8cSopenharmony_ci #[allow(dead_code, unreachable_code, unused_variables, unused_braces)] 9819625d8cSopenharmony_ci #[allow( 9919625d8cSopenharmony_ci clippy::style, 10019625d8cSopenharmony_ci clippy::complexity, 10119625d8cSopenharmony_ci clippy::pedantic, 10219625d8cSopenharmony_ci clippy::restriction, 10319625d8cSopenharmony_ci clippy::perf, 10419625d8cSopenharmony_ci clippy::deprecated, 10519625d8cSopenharmony_ci clippy::nursery, 10619625d8cSopenharmony_ci clippy::cargo, 10719625d8cSopenharmony_ci clippy::suspicious_else_formatting, 10819625d8cSopenharmony_ci clippy::almost_swapped, 10919625d8cSopenharmony_ci )] 11019625d8cSopenharmony_ci impl #impl_generics clap::FromArgMatches for #item_name #ty_generics #where_clause { 11119625d8cSopenharmony_ci fn from_arg_matches(__clap_arg_matches: &clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> { 11219625d8cSopenharmony_ci Self::from_arg_matches_mut(&mut __clap_arg_matches.clone()) 11319625d8cSopenharmony_ci } 11419625d8cSopenharmony_ci 11519625d8cSopenharmony_ci fn from_arg_matches_mut(__clap_arg_matches: &mut clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> { 11619625d8cSopenharmony_ci #raw_deprecated 11719625d8cSopenharmony_ci let v = #item_name #constructor; 11819625d8cSopenharmony_ci ::std::result::Result::Ok(v) 11919625d8cSopenharmony_ci } 12019625d8cSopenharmony_ci 12119625d8cSopenharmony_ci fn update_from_arg_matches(&mut self, __clap_arg_matches: &clap::ArgMatches) -> ::std::result::Result<(), clap::Error> { 12219625d8cSopenharmony_ci self.update_from_arg_matches_mut(&mut __clap_arg_matches.clone()) 12319625d8cSopenharmony_ci } 12419625d8cSopenharmony_ci 12519625d8cSopenharmony_ci fn update_from_arg_matches_mut(&mut self, __clap_arg_matches: &mut clap::ArgMatches) -> ::std::result::Result<(), clap::Error> { 12619625d8cSopenharmony_ci #raw_deprecated 12719625d8cSopenharmony_ci #updater 12819625d8cSopenharmony_ci ::std::result::Result::Ok(()) 12919625d8cSopenharmony_ci } 13019625d8cSopenharmony_ci } 13119625d8cSopenharmony_ci 13219625d8cSopenharmony_ci #[allow(dead_code, unreachable_code, unused_variables, unused_braces)] 13319625d8cSopenharmony_ci #[allow( 13419625d8cSopenharmony_ci clippy::style, 13519625d8cSopenharmony_ci clippy::complexity, 13619625d8cSopenharmony_ci clippy::pedantic, 13719625d8cSopenharmony_ci clippy::restriction, 13819625d8cSopenharmony_ci clippy::perf, 13919625d8cSopenharmony_ci clippy::deprecated, 14019625d8cSopenharmony_ci clippy::nursery, 14119625d8cSopenharmony_ci clippy::cargo, 14219625d8cSopenharmony_ci clippy::suspicious_else_formatting, 14319625d8cSopenharmony_ci clippy::almost_swapped, 14419625d8cSopenharmony_ci )] 14519625d8cSopenharmony_ci impl #impl_generics clap::Args for #item_name #ty_generics #where_clause { 14619625d8cSopenharmony_ci fn group_id() -> Option<clap::Id> { 14719625d8cSopenharmony_ci #group_id 14819625d8cSopenharmony_ci } 14919625d8cSopenharmony_ci fn augment_args<'b>(#app_var: clap::Command) -> clap::Command { 15019625d8cSopenharmony_ci #augmentation 15119625d8cSopenharmony_ci } 15219625d8cSopenharmony_ci fn augment_args_for_update<'b>(#app_var: clap::Command) -> clap::Command { 15319625d8cSopenharmony_ci #augmentation_update 15419625d8cSopenharmony_ci } 15519625d8cSopenharmony_ci } 15619625d8cSopenharmony_ci }) 15719625d8cSopenharmony_ci} 15819625d8cSopenharmony_ci 15919625d8cSopenharmony_ci/// Generate a block of code to add arguments/subcommands corresponding to 16019625d8cSopenharmony_ci/// the `fields` to an cmd. 16119625d8cSopenharmony_cipub fn gen_augment( 16219625d8cSopenharmony_ci fields: &[(&Field, Item)], 16319625d8cSopenharmony_ci app_var: &Ident, 16419625d8cSopenharmony_ci parent_item: &Item, 16519625d8cSopenharmony_ci override_required: bool, 16619625d8cSopenharmony_ci) -> Result<TokenStream, syn::Error> { 16719625d8cSopenharmony_ci let mut subcommand_specified = false; 16819625d8cSopenharmony_ci let mut args = Vec::new(); 16919625d8cSopenharmony_ci for (field, item) in fields { 17019625d8cSopenharmony_ci let kind = item.kind(); 17119625d8cSopenharmony_ci let genned = match &*kind { 17219625d8cSopenharmony_ci Kind::Command(_) 17319625d8cSopenharmony_ci | Kind::Value 17419625d8cSopenharmony_ci | Kind::Skip(_, _) 17519625d8cSopenharmony_ci | Kind::FromGlobal(_) 17619625d8cSopenharmony_ci | Kind::ExternalSubcommand => None, 17719625d8cSopenharmony_ci Kind::Subcommand(ty) => { 17819625d8cSopenharmony_ci if subcommand_specified { 17919625d8cSopenharmony_ci abort!( 18019625d8cSopenharmony_ci field.span(), 18119625d8cSopenharmony_ci "`#[command(subcommand)]` can only be used once per container" 18219625d8cSopenharmony_ci ); 18319625d8cSopenharmony_ci } 18419625d8cSopenharmony_ci subcommand_specified = true; 18519625d8cSopenharmony_ci 18619625d8cSopenharmony_ci let subcmd_type = match (**ty, sub_type(&field.ty)) { 18719625d8cSopenharmony_ci (Ty::Option, Some(sub_type)) => sub_type, 18819625d8cSopenharmony_ci _ => &field.ty, 18919625d8cSopenharmony_ci }; 19019625d8cSopenharmony_ci let implicit_methods = if **ty == Ty::Option { 19119625d8cSopenharmony_ci quote!() 19219625d8cSopenharmony_ci } else { 19319625d8cSopenharmony_ci quote_spanned! { kind.span()=> 19419625d8cSopenharmony_ci .subcommand_required(true) 19519625d8cSopenharmony_ci .arg_required_else_help(true) 19619625d8cSopenharmony_ci } 19719625d8cSopenharmony_ci }; 19819625d8cSopenharmony_ci 19919625d8cSopenharmony_ci let override_methods = if override_required { 20019625d8cSopenharmony_ci quote_spanned! { kind.span()=> 20119625d8cSopenharmony_ci .subcommand_required(false) 20219625d8cSopenharmony_ci .arg_required_else_help(false) 20319625d8cSopenharmony_ci } 20419625d8cSopenharmony_ci } else { 20519625d8cSopenharmony_ci quote!() 20619625d8cSopenharmony_ci }; 20719625d8cSopenharmony_ci 20819625d8cSopenharmony_ci Some(quote! { 20919625d8cSopenharmony_ci let #app_var = <#subcmd_type as clap::Subcommand>::augment_subcommands( #app_var ); 21019625d8cSopenharmony_ci let #app_var = #app_var 21119625d8cSopenharmony_ci #implicit_methods 21219625d8cSopenharmony_ci #override_methods; 21319625d8cSopenharmony_ci }) 21419625d8cSopenharmony_ci } 21519625d8cSopenharmony_ci Kind::Flatten(ty) => { 21619625d8cSopenharmony_ci let inner_type = match (**ty, sub_type(&field.ty)) { 21719625d8cSopenharmony_ci (Ty::Option, Some(sub_type)) => sub_type, 21819625d8cSopenharmony_ci _ => &field.ty, 21919625d8cSopenharmony_ci }; 22019625d8cSopenharmony_ci 22119625d8cSopenharmony_ci let next_help_heading = item.next_help_heading(); 22219625d8cSopenharmony_ci let next_display_order = item.next_display_order(); 22319625d8cSopenharmony_ci if override_required { 22419625d8cSopenharmony_ci Some(quote_spanned! { kind.span()=> 22519625d8cSopenharmony_ci let #app_var = #app_var 22619625d8cSopenharmony_ci #next_help_heading 22719625d8cSopenharmony_ci #next_display_order; 22819625d8cSopenharmony_ci let #app_var = <#inner_type as clap::Args>::augment_args_for_update(#app_var); 22919625d8cSopenharmony_ci }) 23019625d8cSopenharmony_ci } else { 23119625d8cSopenharmony_ci Some(quote_spanned! { kind.span()=> 23219625d8cSopenharmony_ci let #app_var = #app_var 23319625d8cSopenharmony_ci #next_help_heading 23419625d8cSopenharmony_ci #next_display_order; 23519625d8cSopenharmony_ci let #app_var = <#inner_type as clap::Args>::augment_args(#app_var); 23619625d8cSopenharmony_ci }) 23719625d8cSopenharmony_ci } 23819625d8cSopenharmony_ci } 23919625d8cSopenharmony_ci Kind::Arg(ty) => { 24019625d8cSopenharmony_ci let value_parser = item.value_parser(&field.ty); 24119625d8cSopenharmony_ci let action = item.action(&field.ty); 24219625d8cSopenharmony_ci let value_name = item.value_name(); 24319625d8cSopenharmony_ci 24419625d8cSopenharmony_ci let implicit_methods = match **ty { 24519625d8cSopenharmony_ci Ty::Unit => { 24619625d8cSopenharmony_ci // Leaving out `value_parser` as it will always fail 24719625d8cSopenharmony_ci quote_spanned! { ty.span()=> 24819625d8cSopenharmony_ci .value_name(#value_name) 24919625d8cSopenharmony_ci #action 25019625d8cSopenharmony_ci } 25119625d8cSopenharmony_ci } 25219625d8cSopenharmony_ci Ty::Option => { 25319625d8cSopenharmony_ci quote_spanned! { ty.span()=> 25419625d8cSopenharmony_ci .value_name(#value_name) 25519625d8cSopenharmony_ci #value_parser 25619625d8cSopenharmony_ci #action 25719625d8cSopenharmony_ci } 25819625d8cSopenharmony_ci } 25919625d8cSopenharmony_ci 26019625d8cSopenharmony_ci Ty::OptionOption => quote_spanned! { ty.span()=> 26119625d8cSopenharmony_ci .value_name(#value_name) 26219625d8cSopenharmony_ci .num_args(0..=1) 26319625d8cSopenharmony_ci #value_parser 26419625d8cSopenharmony_ci #action 26519625d8cSopenharmony_ci }, 26619625d8cSopenharmony_ci 26719625d8cSopenharmony_ci Ty::OptionVec => { 26819625d8cSopenharmony_ci if item.is_positional() { 26919625d8cSopenharmony_ci quote_spanned! { ty.span()=> 27019625d8cSopenharmony_ci .value_name(#value_name) 27119625d8cSopenharmony_ci .num_args(1..) // action won't be sufficient for getting multiple 27219625d8cSopenharmony_ci #value_parser 27319625d8cSopenharmony_ci #action 27419625d8cSopenharmony_ci } 27519625d8cSopenharmony_ci } else { 27619625d8cSopenharmony_ci quote_spanned! { ty.span()=> 27719625d8cSopenharmony_ci .value_name(#value_name) 27819625d8cSopenharmony_ci #value_parser 27919625d8cSopenharmony_ci #action 28019625d8cSopenharmony_ci } 28119625d8cSopenharmony_ci } 28219625d8cSopenharmony_ci } 28319625d8cSopenharmony_ci 28419625d8cSopenharmony_ci Ty::Vec => { 28519625d8cSopenharmony_ci if item.is_positional() { 28619625d8cSopenharmony_ci quote_spanned! { ty.span()=> 28719625d8cSopenharmony_ci .value_name(#value_name) 28819625d8cSopenharmony_ci .num_args(1..) // action won't be sufficient for getting multiple 28919625d8cSopenharmony_ci #value_parser 29019625d8cSopenharmony_ci #action 29119625d8cSopenharmony_ci } 29219625d8cSopenharmony_ci } else { 29319625d8cSopenharmony_ci quote_spanned! { ty.span()=> 29419625d8cSopenharmony_ci .value_name(#value_name) 29519625d8cSopenharmony_ci #value_parser 29619625d8cSopenharmony_ci #action 29719625d8cSopenharmony_ci } 29819625d8cSopenharmony_ci } 29919625d8cSopenharmony_ci } 30019625d8cSopenharmony_ci 30119625d8cSopenharmony_ci Ty::VecVec | Ty::OptionVecVec => { 30219625d8cSopenharmony_ci quote_spanned! { ty.span() => 30319625d8cSopenharmony_ci .value_name(#value_name) 30419625d8cSopenharmony_ci #value_parser 30519625d8cSopenharmony_ci #action 30619625d8cSopenharmony_ci } 30719625d8cSopenharmony_ci } 30819625d8cSopenharmony_ci 30919625d8cSopenharmony_ci Ty::Other => { 31019625d8cSopenharmony_ci let required = item.find_default_method().is_none(); 31119625d8cSopenharmony_ci // `ArgAction::takes_values` is assuming `ArgAction::default_value` will be 31219625d8cSopenharmony_ci // set though that won't always be true but this should be good enough, 31319625d8cSopenharmony_ci // otherwise we'll report an "arg required" error when unwrapping. 31419625d8cSopenharmony_ci let action_value = action.args(); 31519625d8cSopenharmony_ci quote_spanned! { ty.span()=> 31619625d8cSopenharmony_ci .value_name(#value_name) 31719625d8cSopenharmony_ci .required(#required && #action_value.takes_values()) 31819625d8cSopenharmony_ci #value_parser 31919625d8cSopenharmony_ci #action 32019625d8cSopenharmony_ci } 32119625d8cSopenharmony_ci } 32219625d8cSopenharmony_ci }; 32319625d8cSopenharmony_ci 32419625d8cSopenharmony_ci let id = item.id(); 32519625d8cSopenharmony_ci let explicit_methods = item.field_methods(); 32619625d8cSopenharmony_ci let deprecations = if !override_required { 32719625d8cSopenharmony_ci item.deprecations() 32819625d8cSopenharmony_ci } else { 32919625d8cSopenharmony_ci quote!() 33019625d8cSopenharmony_ci }; 33119625d8cSopenharmony_ci let override_methods = if override_required { 33219625d8cSopenharmony_ci quote_spanned! { kind.span()=> 33319625d8cSopenharmony_ci .required(false) 33419625d8cSopenharmony_ci } 33519625d8cSopenharmony_ci } else { 33619625d8cSopenharmony_ci quote!() 33719625d8cSopenharmony_ci }; 33819625d8cSopenharmony_ci 33919625d8cSopenharmony_ci Some(quote_spanned! { field.span()=> 34019625d8cSopenharmony_ci let #app_var = #app_var.arg({ 34119625d8cSopenharmony_ci #deprecations 34219625d8cSopenharmony_ci 34319625d8cSopenharmony_ci #[allow(deprecated)] 34419625d8cSopenharmony_ci let arg = clap::Arg::new(#id) 34519625d8cSopenharmony_ci #implicit_methods; 34619625d8cSopenharmony_ci 34719625d8cSopenharmony_ci let arg = arg 34819625d8cSopenharmony_ci #explicit_methods; 34919625d8cSopenharmony_ci 35019625d8cSopenharmony_ci let arg = arg 35119625d8cSopenharmony_ci #override_methods; 35219625d8cSopenharmony_ci 35319625d8cSopenharmony_ci arg 35419625d8cSopenharmony_ci }); 35519625d8cSopenharmony_ci }) 35619625d8cSopenharmony_ci } 35719625d8cSopenharmony_ci }; 35819625d8cSopenharmony_ci args.push(genned); 35919625d8cSopenharmony_ci } 36019625d8cSopenharmony_ci 36119625d8cSopenharmony_ci let deprecations = if !override_required { 36219625d8cSopenharmony_ci parent_item.deprecations() 36319625d8cSopenharmony_ci } else { 36419625d8cSopenharmony_ci quote!() 36519625d8cSopenharmony_ci }; 36619625d8cSopenharmony_ci let initial_app_methods = parent_item.initial_top_level_methods(); 36719625d8cSopenharmony_ci let final_app_methods = parent_item.final_top_level_methods(); 36819625d8cSopenharmony_ci let group_app_methods = if parent_item.skip_group() { 36919625d8cSopenharmony_ci quote!() 37019625d8cSopenharmony_ci } else { 37119625d8cSopenharmony_ci let group_id = parent_item.ident().unraw().to_string(); 37219625d8cSopenharmony_ci let literal_group_members = fields 37319625d8cSopenharmony_ci .iter() 37419625d8cSopenharmony_ci .filter_map(|(_field, item)| { 37519625d8cSopenharmony_ci let kind = item.kind(); 37619625d8cSopenharmony_ci if matches!(*kind, Kind::Arg(_)) { 37719625d8cSopenharmony_ci Some(item.id()) 37819625d8cSopenharmony_ci } else { 37919625d8cSopenharmony_ci None 38019625d8cSopenharmony_ci } 38119625d8cSopenharmony_ci }) 38219625d8cSopenharmony_ci .collect::<Vec<_>>(); 38319625d8cSopenharmony_ci let literal_group_members_len = literal_group_members.len(); 38419625d8cSopenharmony_ci let mut literal_group_members = quote! {{ 38519625d8cSopenharmony_ci let members: [clap::Id; #literal_group_members_len] = [#( clap::Id::from(#literal_group_members) ),* ]; 38619625d8cSopenharmony_ci members 38719625d8cSopenharmony_ci }}; 38819625d8cSopenharmony_ci // HACK: Validation isn't ready yet for nested arg groups, so just don't populate the group in 38919625d8cSopenharmony_ci // that situation 39019625d8cSopenharmony_ci let possible_group_members_len = fields 39119625d8cSopenharmony_ci .iter() 39219625d8cSopenharmony_ci .filter(|(_field, item)| { 39319625d8cSopenharmony_ci let kind = item.kind(); 39419625d8cSopenharmony_ci matches!(*kind, Kind::Flatten(_)) 39519625d8cSopenharmony_ci }) 39619625d8cSopenharmony_ci .count(); 39719625d8cSopenharmony_ci if 0 < possible_group_members_len { 39819625d8cSopenharmony_ci literal_group_members = quote! {{ 39919625d8cSopenharmony_ci let members: [clap::Id; 0] = []; 40019625d8cSopenharmony_ci members 40119625d8cSopenharmony_ci }}; 40219625d8cSopenharmony_ci } 40319625d8cSopenharmony_ci 40419625d8cSopenharmony_ci quote!( 40519625d8cSopenharmony_ci .group( 40619625d8cSopenharmony_ci clap::ArgGroup::new(#group_id) 40719625d8cSopenharmony_ci .multiple(true) 40819625d8cSopenharmony_ci .args(#literal_group_members) 40919625d8cSopenharmony_ci ) 41019625d8cSopenharmony_ci ) 41119625d8cSopenharmony_ci }; 41219625d8cSopenharmony_ci Ok(quote! {{ 41319625d8cSopenharmony_ci #deprecations 41419625d8cSopenharmony_ci let #app_var = #app_var 41519625d8cSopenharmony_ci #initial_app_methods 41619625d8cSopenharmony_ci #group_app_methods 41719625d8cSopenharmony_ci ; 41819625d8cSopenharmony_ci #( #args )* 41919625d8cSopenharmony_ci #app_var #final_app_methods 42019625d8cSopenharmony_ci }}) 42119625d8cSopenharmony_ci} 42219625d8cSopenharmony_ci 42319625d8cSopenharmony_cipub fn gen_constructor(fields: &[(&Field, Item)]) -> Result<TokenStream, syn::Error> { 42419625d8cSopenharmony_ci let fields = fields.iter().map(|(field, item)| { 42519625d8cSopenharmony_ci let field_name = field.ident.as_ref().unwrap(); 42619625d8cSopenharmony_ci let kind = item.kind(); 42719625d8cSopenharmony_ci let arg_matches = format_ident!("__clap_arg_matches"); 42819625d8cSopenharmony_ci let genned = match &*kind { 42919625d8cSopenharmony_ci Kind::Command(_) 43019625d8cSopenharmony_ci | Kind::Value 43119625d8cSopenharmony_ci | Kind::ExternalSubcommand => { 43219625d8cSopenharmony_ci abort! { kind.span(), 43319625d8cSopenharmony_ci "`{}` cannot be used with `arg`", 43419625d8cSopenharmony_ci kind.name(), 43519625d8cSopenharmony_ci } 43619625d8cSopenharmony_ci } 43719625d8cSopenharmony_ci Kind::Subcommand(ty) => { 43819625d8cSopenharmony_ci let subcmd_type = match (**ty, sub_type(&field.ty)) { 43919625d8cSopenharmony_ci (Ty::Option, Some(sub_type)) => sub_type, 44019625d8cSopenharmony_ci _ => &field.ty, 44119625d8cSopenharmony_ci }; 44219625d8cSopenharmony_ci match **ty { 44319625d8cSopenharmony_ci Ty::Option => { 44419625d8cSopenharmony_ci quote_spanned! { kind.span()=> 44519625d8cSopenharmony_ci #field_name: { 44619625d8cSopenharmony_ci if #arg_matches.subcommand_name().map(<#subcmd_type as clap::Subcommand>::has_subcommand).unwrap_or(false) { 44719625d8cSopenharmony_ci Some(<#subcmd_type as clap::FromArgMatches>::from_arg_matches_mut(#arg_matches)?) 44819625d8cSopenharmony_ci } else { 44919625d8cSopenharmony_ci None 45019625d8cSopenharmony_ci } 45119625d8cSopenharmony_ci } 45219625d8cSopenharmony_ci } 45319625d8cSopenharmony_ci }, 45419625d8cSopenharmony_ci Ty::Other => { 45519625d8cSopenharmony_ci quote_spanned! { kind.span()=> 45619625d8cSopenharmony_ci #field_name: { 45719625d8cSopenharmony_ci <#subcmd_type as clap::FromArgMatches>::from_arg_matches_mut(#arg_matches)? 45819625d8cSopenharmony_ci } 45919625d8cSopenharmony_ci } 46019625d8cSopenharmony_ci }, 46119625d8cSopenharmony_ci Ty::Unit | 46219625d8cSopenharmony_ci Ty::Vec | 46319625d8cSopenharmony_ci Ty::OptionOption | 46419625d8cSopenharmony_ci Ty::OptionVec | 46519625d8cSopenharmony_ci Ty::VecVec | 46619625d8cSopenharmony_ci Ty::OptionVecVec => { 46719625d8cSopenharmony_ci abort!( 46819625d8cSopenharmony_ci ty.span(), 46919625d8cSopenharmony_ci "{} types are not supported for subcommand", 47019625d8cSopenharmony_ci ty.as_str() 47119625d8cSopenharmony_ci ); 47219625d8cSopenharmony_ci } 47319625d8cSopenharmony_ci } 47419625d8cSopenharmony_ci } 47519625d8cSopenharmony_ci 47619625d8cSopenharmony_ci Kind::Flatten(ty) => { 47719625d8cSopenharmony_ci let inner_type = match (**ty, sub_type(&field.ty)) { 47819625d8cSopenharmony_ci (Ty::Option, Some(sub_type)) => sub_type, 47919625d8cSopenharmony_ci _ => &field.ty, 48019625d8cSopenharmony_ci }; 48119625d8cSopenharmony_ci match **ty { 48219625d8cSopenharmony_ci Ty::Other => { 48319625d8cSopenharmony_ci quote_spanned! { kind.span()=> 48419625d8cSopenharmony_ci #field_name: <#inner_type as clap::FromArgMatches>::from_arg_matches_mut(#arg_matches)? 48519625d8cSopenharmony_ci } 48619625d8cSopenharmony_ci }, 48719625d8cSopenharmony_ci Ty::Option => { 48819625d8cSopenharmony_ci quote_spanned! { kind.span()=> 48919625d8cSopenharmony_ci #field_name: { 49019625d8cSopenharmony_ci let group_id = <#inner_type as clap::Args>::group_id() 49119625d8cSopenharmony_ci .expect("`#[arg(flatten)]`ed field type implements `Args::group_id`"); 49219625d8cSopenharmony_ci if #arg_matches.contains_id(group_id.as_str()) { 49319625d8cSopenharmony_ci Some( 49419625d8cSopenharmony_ci <#inner_type as clap::FromArgMatches>::from_arg_matches_mut(#arg_matches)? 49519625d8cSopenharmony_ci ) 49619625d8cSopenharmony_ci } else { 49719625d8cSopenharmony_ci None 49819625d8cSopenharmony_ci } 49919625d8cSopenharmony_ci } 50019625d8cSopenharmony_ci } 50119625d8cSopenharmony_ci }, 50219625d8cSopenharmony_ci Ty::Unit | 50319625d8cSopenharmony_ci Ty::Vec | 50419625d8cSopenharmony_ci Ty::OptionOption | 50519625d8cSopenharmony_ci Ty::OptionVec | 50619625d8cSopenharmony_ci Ty::VecVec | 50719625d8cSopenharmony_ci Ty::OptionVecVec => { 50819625d8cSopenharmony_ci abort!( 50919625d8cSopenharmony_ci ty.span(), 51019625d8cSopenharmony_ci "{} types are not supported for flatten", 51119625d8cSopenharmony_ci ty.as_str() 51219625d8cSopenharmony_ci ); 51319625d8cSopenharmony_ci } 51419625d8cSopenharmony_ci } 51519625d8cSopenharmony_ci }, 51619625d8cSopenharmony_ci 51719625d8cSopenharmony_ci Kind::Skip(val, _) => match val { 51819625d8cSopenharmony_ci None => quote_spanned!(kind.span()=> #field_name: Default::default()), 51919625d8cSopenharmony_ci Some(val) => quote_spanned!(kind.span()=> #field_name: (#val).into()), 52019625d8cSopenharmony_ci }, 52119625d8cSopenharmony_ci 52219625d8cSopenharmony_ci Kind::Arg(ty) | Kind::FromGlobal(ty) => { 52319625d8cSopenharmony_ci gen_parsers(item, ty, field_name, field, None)? 52419625d8cSopenharmony_ci } 52519625d8cSopenharmony_ci }; 52619625d8cSopenharmony_ci Ok(genned) 52719625d8cSopenharmony_ci }).collect::<Result<Vec<_>, syn::Error>>()?; 52819625d8cSopenharmony_ci 52919625d8cSopenharmony_ci Ok(quote! {{ 53019625d8cSopenharmony_ci #( #fields ),* 53119625d8cSopenharmony_ci }}) 53219625d8cSopenharmony_ci} 53319625d8cSopenharmony_ci 53419625d8cSopenharmony_cipub fn gen_updater(fields: &[(&Field, Item)], use_self: bool) -> Result<TokenStream, syn::Error> { 53519625d8cSopenharmony_ci let mut genned_fields = Vec::new(); 53619625d8cSopenharmony_ci for (field, item) in fields { 53719625d8cSopenharmony_ci let field_name = field.ident.as_ref().unwrap(); 53819625d8cSopenharmony_ci let kind = item.kind(); 53919625d8cSopenharmony_ci 54019625d8cSopenharmony_ci let access = if use_self { 54119625d8cSopenharmony_ci quote! { 54219625d8cSopenharmony_ci #[allow(non_snake_case)] 54319625d8cSopenharmony_ci let #field_name = &mut self.#field_name; 54419625d8cSopenharmony_ci } 54519625d8cSopenharmony_ci } else { 54619625d8cSopenharmony_ci quote!() 54719625d8cSopenharmony_ci }; 54819625d8cSopenharmony_ci let arg_matches = format_ident!("__clap_arg_matches"); 54919625d8cSopenharmony_ci 55019625d8cSopenharmony_ci let genned = match &*kind { 55119625d8cSopenharmony_ci Kind::Command(_) | Kind::Value | Kind::ExternalSubcommand => { 55219625d8cSopenharmony_ci abort! { kind.span(), 55319625d8cSopenharmony_ci "`{}` cannot be used with `arg`", 55419625d8cSopenharmony_ci kind.name(), 55519625d8cSopenharmony_ci } 55619625d8cSopenharmony_ci } 55719625d8cSopenharmony_ci Kind::Subcommand(ty) => { 55819625d8cSopenharmony_ci let subcmd_type = match (**ty, sub_type(&field.ty)) { 55919625d8cSopenharmony_ci (Ty::Option, Some(sub_type)) => sub_type, 56019625d8cSopenharmony_ci _ => &field.ty, 56119625d8cSopenharmony_ci }; 56219625d8cSopenharmony_ci 56319625d8cSopenharmony_ci let updater = quote_spanned! { ty.span()=> 56419625d8cSopenharmony_ci <#subcmd_type as clap::FromArgMatches>::update_from_arg_matches_mut(#field_name, #arg_matches)?; 56519625d8cSopenharmony_ci }; 56619625d8cSopenharmony_ci 56719625d8cSopenharmony_ci let updater = match **ty { 56819625d8cSopenharmony_ci Ty::Option => quote_spanned! { kind.span()=> 56919625d8cSopenharmony_ci if let Some(#field_name) = #field_name.as_mut() { 57019625d8cSopenharmony_ci #updater 57119625d8cSopenharmony_ci } else { 57219625d8cSopenharmony_ci *#field_name = Some(<#subcmd_type as clap::FromArgMatches>::from_arg_matches_mut( 57319625d8cSopenharmony_ci #arg_matches 57419625d8cSopenharmony_ci )?); 57519625d8cSopenharmony_ci } 57619625d8cSopenharmony_ci }, 57719625d8cSopenharmony_ci _ => quote_spanned! { kind.span()=> 57819625d8cSopenharmony_ci #updater 57919625d8cSopenharmony_ci }, 58019625d8cSopenharmony_ci }; 58119625d8cSopenharmony_ci 58219625d8cSopenharmony_ci quote_spanned! { kind.span()=> 58319625d8cSopenharmony_ci { 58419625d8cSopenharmony_ci #access 58519625d8cSopenharmony_ci #updater 58619625d8cSopenharmony_ci } 58719625d8cSopenharmony_ci } 58819625d8cSopenharmony_ci } 58919625d8cSopenharmony_ci 59019625d8cSopenharmony_ci Kind::Flatten(ty) => { 59119625d8cSopenharmony_ci let inner_type = match (**ty, sub_type(&field.ty)) { 59219625d8cSopenharmony_ci (Ty::Option, Some(sub_type)) => sub_type, 59319625d8cSopenharmony_ci _ => &field.ty, 59419625d8cSopenharmony_ci }; 59519625d8cSopenharmony_ci 59619625d8cSopenharmony_ci let updater = quote_spanned! { ty.span()=> 59719625d8cSopenharmony_ci <#inner_type as clap::FromArgMatches>::update_from_arg_matches_mut(#field_name, #arg_matches)?; 59819625d8cSopenharmony_ci }; 59919625d8cSopenharmony_ci 60019625d8cSopenharmony_ci let updater = match **ty { 60119625d8cSopenharmony_ci Ty::Option => quote_spanned! { kind.span()=> 60219625d8cSopenharmony_ci if let Some(#field_name) = #field_name.as_mut() { 60319625d8cSopenharmony_ci #updater 60419625d8cSopenharmony_ci } else { 60519625d8cSopenharmony_ci *#field_name = Some(<#inner_type as clap::FromArgMatches>::from_arg_matches_mut( 60619625d8cSopenharmony_ci #arg_matches 60719625d8cSopenharmony_ci )?); 60819625d8cSopenharmony_ci } 60919625d8cSopenharmony_ci }, 61019625d8cSopenharmony_ci _ => quote_spanned! { kind.span()=> 61119625d8cSopenharmony_ci #updater 61219625d8cSopenharmony_ci }, 61319625d8cSopenharmony_ci }; 61419625d8cSopenharmony_ci 61519625d8cSopenharmony_ci quote_spanned! { kind.span()=> 61619625d8cSopenharmony_ci { 61719625d8cSopenharmony_ci #access 61819625d8cSopenharmony_ci #updater 61919625d8cSopenharmony_ci } 62019625d8cSopenharmony_ci } 62119625d8cSopenharmony_ci } 62219625d8cSopenharmony_ci 62319625d8cSopenharmony_ci Kind::Skip(_, _) => quote!(), 62419625d8cSopenharmony_ci 62519625d8cSopenharmony_ci Kind::Arg(ty) | Kind::FromGlobal(ty) => { 62619625d8cSopenharmony_ci gen_parsers(item, ty, field_name, field, Some(&access))? 62719625d8cSopenharmony_ci } 62819625d8cSopenharmony_ci }; 62919625d8cSopenharmony_ci genned_fields.push(genned); 63019625d8cSopenharmony_ci } 63119625d8cSopenharmony_ci 63219625d8cSopenharmony_ci Ok(quote! { 63319625d8cSopenharmony_ci #( #genned_fields )* 63419625d8cSopenharmony_ci }) 63519625d8cSopenharmony_ci} 63619625d8cSopenharmony_ci 63719625d8cSopenharmony_cifn gen_parsers( 63819625d8cSopenharmony_ci item: &Item, 63919625d8cSopenharmony_ci ty: &Sp<Ty>, 64019625d8cSopenharmony_ci field_name: &Ident, 64119625d8cSopenharmony_ci field: &Field, 64219625d8cSopenharmony_ci update: Option<&TokenStream>, 64319625d8cSopenharmony_ci) -> Result<TokenStream, syn::Error> { 64419625d8cSopenharmony_ci let span = ty.span(); 64519625d8cSopenharmony_ci let convert_type = inner_type(&field.ty); 64619625d8cSopenharmony_ci let id = item.id(); 64719625d8cSopenharmony_ci let get_one = quote_spanned!(span=> remove_one::<#convert_type>); 64819625d8cSopenharmony_ci let get_many = quote_spanned!(span=> remove_many::<#convert_type>); 64919625d8cSopenharmony_ci let get_occurrences = quote_spanned!(span=> remove_occurrences::<#convert_type>); 65019625d8cSopenharmony_ci 65119625d8cSopenharmony_ci // Give this identifier the same hygiene 65219625d8cSopenharmony_ci // as the `arg_matches` parameter definition. This 65319625d8cSopenharmony_ci // allows us to refer to `arg_matches` within a `quote_spanned` block 65419625d8cSopenharmony_ci let arg_matches = format_ident!("__clap_arg_matches"); 65519625d8cSopenharmony_ci 65619625d8cSopenharmony_ci let field_value = match **ty { 65719625d8cSopenharmony_ci Ty::Unit => { 65819625d8cSopenharmony_ci quote_spanned! { ty.span()=> 65919625d8cSopenharmony_ci () 66019625d8cSopenharmony_ci } 66119625d8cSopenharmony_ci } 66219625d8cSopenharmony_ci 66319625d8cSopenharmony_ci Ty::Option => { 66419625d8cSopenharmony_ci quote_spanned! { ty.span()=> 66519625d8cSopenharmony_ci #arg_matches.#get_one(#id) 66619625d8cSopenharmony_ci } 66719625d8cSopenharmony_ci } 66819625d8cSopenharmony_ci 66919625d8cSopenharmony_ci Ty::OptionOption => quote_spanned! { ty.span()=> 67019625d8cSopenharmony_ci if #arg_matches.contains_id(#id) { 67119625d8cSopenharmony_ci Some( 67219625d8cSopenharmony_ci #arg_matches.#get_one(#id) 67319625d8cSopenharmony_ci ) 67419625d8cSopenharmony_ci } else { 67519625d8cSopenharmony_ci None 67619625d8cSopenharmony_ci } 67719625d8cSopenharmony_ci }, 67819625d8cSopenharmony_ci 67919625d8cSopenharmony_ci Ty::OptionVec => quote_spanned! { ty.span()=> 68019625d8cSopenharmony_ci if #arg_matches.contains_id(#id) { 68119625d8cSopenharmony_ci Some(#arg_matches.#get_many(#id) 68219625d8cSopenharmony_ci .map(|v| v.collect::<Vec<_>>()) 68319625d8cSopenharmony_ci .unwrap_or_else(Vec::new)) 68419625d8cSopenharmony_ci } else { 68519625d8cSopenharmony_ci None 68619625d8cSopenharmony_ci } 68719625d8cSopenharmony_ci }, 68819625d8cSopenharmony_ci 68919625d8cSopenharmony_ci Ty::Vec => { 69019625d8cSopenharmony_ci quote_spanned! { ty.span()=> 69119625d8cSopenharmony_ci #arg_matches.#get_many(#id) 69219625d8cSopenharmony_ci .map(|v| v.collect::<Vec<_>>()) 69319625d8cSopenharmony_ci .unwrap_or_else(Vec::new) 69419625d8cSopenharmony_ci } 69519625d8cSopenharmony_ci } 69619625d8cSopenharmony_ci 69719625d8cSopenharmony_ci Ty::VecVec => quote_spanned! { ty.span()=> 69819625d8cSopenharmony_ci #arg_matches.#get_occurrences(#id) 69919625d8cSopenharmony_ci .map(|g| g.map(::std::iter::Iterator::collect).collect::<Vec<Vec<_>>>()) 70019625d8cSopenharmony_ci .unwrap_or_else(Vec::new) 70119625d8cSopenharmony_ci }, 70219625d8cSopenharmony_ci 70319625d8cSopenharmony_ci Ty::OptionVecVec => quote_spanned! { ty.span()=> 70419625d8cSopenharmony_ci #arg_matches.#get_occurrences(#id) 70519625d8cSopenharmony_ci .map(|g| g.map(::std::iter::Iterator::collect).collect::<Vec<Vec<_>>>()) 70619625d8cSopenharmony_ci }, 70719625d8cSopenharmony_ci 70819625d8cSopenharmony_ci Ty::Other => { 70919625d8cSopenharmony_ci quote_spanned! { ty.span()=> 71019625d8cSopenharmony_ci #arg_matches.#get_one(#id) 71119625d8cSopenharmony_ci .ok_or_else(|| clap::Error::raw(clap::error::ErrorKind::MissingRequiredArgument, format!("The following required argument was not provided: {}", #id)))? 71219625d8cSopenharmony_ci } 71319625d8cSopenharmony_ci } 71419625d8cSopenharmony_ci }; 71519625d8cSopenharmony_ci 71619625d8cSopenharmony_ci let genned = if let Some(access) = update { 71719625d8cSopenharmony_ci quote_spanned! { field.span()=> 71819625d8cSopenharmony_ci if #arg_matches.contains_id(#id) { 71919625d8cSopenharmony_ci #access 72019625d8cSopenharmony_ci *#field_name = #field_value 72119625d8cSopenharmony_ci } 72219625d8cSopenharmony_ci } 72319625d8cSopenharmony_ci } else { 72419625d8cSopenharmony_ci quote_spanned!(field.span()=> #field_name: #field_value ) 72519625d8cSopenharmony_ci }; 72619625d8cSopenharmony_ci Ok(genned) 72719625d8cSopenharmony_ci} 72819625d8cSopenharmony_ci 72919625d8cSopenharmony_ci#[cfg(feature = "raw-deprecated")] 73019625d8cSopenharmony_cipub fn raw_deprecated() -> TokenStream { 73119625d8cSopenharmony_ci quote! {} 73219625d8cSopenharmony_ci} 73319625d8cSopenharmony_ci 73419625d8cSopenharmony_ci#[cfg(not(feature = "raw-deprecated"))] 73519625d8cSopenharmony_cipub fn raw_deprecated() -> TokenStream { 73619625d8cSopenharmony_ci quote! { 73719625d8cSopenharmony_ci #![allow(deprecated)] // Assuming any deprecation in here will be related to a deprecation in `Args` 73819625d8cSopenharmony_ci 73919625d8cSopenharmony_ci } 74019625d8cSopenharmony_ci} 741