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