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