diff options
Diffstat (limited to 'vendor/clap_derive/src/derives')
-rw-r--r-- | vendor/clap_derive/src/derives/args.rs | 801 | ||||
-rw-r--r-- | vendor/clap_derive/src/derives/into_app.rs | 62 | ||||
-rw-r--r-- | vendor/clap_derive/src/derives/parser.rs | 90 | ||||
-rw-r--r-- | vendor/clap_derive/src/derives/subcommand.rs | 495 | ||||
-rw-r--r-- | vendor/clap_derive/src/derives/value_enum.rs | 85 |
5 files changed, 743 insertions, 790 deletions
diff --git a/vendor/clap_derive/src/derives/args.rs b/vendor/clap_derive/src/derives/args.rs index 4195a0810..b5d51bfca 100644 --- a/vendor/clap_derive/src/derives/args.rs +++ b/vendor/clap_derive/src/derives/args.rs @@ -12,20 +12,19 @@ // commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the // MIT/Apache 2.0 license. -use crate::{ - attrs::{Attrs, Kind, Name, ParserKind, DEFAULT_CASING, DEFAULT_ENV_CASING}, - dummies, - utils::{inner_type, is_simple_ty, sub_type, Sp, Ty}, -}; - use proc_macro2::{Ident, Span, TokenStream}; use proc_macro_error::{abort, abort_call_site}; use quote::{format_ident, quote, quote_spanned}; +use syn::ext::IdentExt; use syn::{ - punctuated::Punctuated, spanned::Spanned, token::Comma, Attribute, Data, DataStruct, - DeriveInput, Field, Fields, Generics, Type, + punctuated::Punctuated, spanned::Spanned, token::Comma, Data, DataStruct, DeriveInput, Field, + Fields, Generics, }; +use crate::dummies; +use crate::item::{Item, Kind, Name}; +use crate::utils::{inner_type, sub_type, Sp, Ty}; + pub fn derive_args(input: &DeriveInput) -> TokenStream { let ident = &input.ident; @@ -35,87 +34,68 @@ pub fn derive_args(input: &DeriveInput) -> TokenStream { Data::Struct(DataStruct { fields: Fields::Named(ref fields), .. - }) => gen_for_struct(ident, &input.generics, &fields.named, &input.attrs), + }) => { + let name = Name::Derived(ident.clone()); + let item = Item::from_args_struct(input, name); + let fields = fields + .named + .iter() + .map(|field| { + let item = Item::from_args_field(field, item.casing(), item.env_casing()); + (field, item) + }) + .collect::<Vec<_>>(); + gen_for_struct(&item, ident, &input.generics, &fields) + } Data::Struct(DataStruct { fields: Fields::Unit, .. - }) => gen_for_struct( - ident, - &input.generics, - &Punctuated::<Field, Comma>::new(), - &input.attrs, - ), + }) => { + let name = Name::Derived(ident.clone()); + let item = Item::from_args_struct(input, name); + let fields = Punctuated::<Field, Comma>::new(); + let fields = fields + .iter() + .map(|field| { + let item = Item::from_args_field(field, item.casing(), item.env_casing()); + (field, item) + }) + .collect::<Vec<_>>(); + gen_for_struct(&item, ident, &input.generics, &fields) + } _ => abort_call_site!("`#[derive(Args)]` only supports non-tuple structs"), } } pub fn gen_for_struct( - struct_name: &Ident, + item: &Item, + item_name: &Ident, generics: &Generics, - fields: &Punctuated<Field, Comma>, - attrs: &[Attribute], + fields: &[(&Field, Item)], ) -> TokenStream { - let from_arg_matches = gen_from_arg_matches_for_struct(struct_name, generics, fields, attrs); - - let attrs = Attrs::from_struct( - Span::call_site(), - attrs, - Name::Derived(struct_name.clone()), - Sp::call_site(DEFAULT_CASING), - Sp::call_site(DEFAULT_ENV_CASING), - ); - let app_var = Ident::new("__clap_app", Span::call_site()); - let augmentation = gen_augment(fields, &app_var, &attrs, false); - let augmentation_update = gen_augment(fields, &app_var, &attrs, true); - - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - - quote! { - #from_arg_matches - - #[allow(dead_code, unreachable_code, unused_variables, unused_braces)] - #[allow( - clippy::style, - clippy::complexity, - clippy::pedantic, - clippy::restriction, - clippy::perf, - clippy::deprecated, - clippy::nursery, - clippy::cargo, - clippy::suspicious_else_formatting, - )] - #[deny(clippy::correctness)] - impl #impl_generics clap::Args for #struct_name #ty_generics #where_clause { - fn augment_args<'b>(#app_var: clap::Command<'b>) -> clap::Command<'b> { - #augmentation - } - fn augment_args_for_update<'b>(#app_var: clap::Command<'b>) -> clap::Command<'b> { - #augmentation_update - } + if !matches!(&*item.kind(), Kind::Command(_)) { + abort! { item.kind().span(), + "`{}` cannot be used with `command`", + item.kind().name(), } } -} -pub fn gen_from_arg_matches_for_struct( - struct_name: &Ident, - generics: &Generics, - fields: &Punctuated<Field, Comma>, - attrs: &[Attribute], -) -> TokenStream { - let attrs = Attrs::from_struct( - Span::call_site(), - attrs, - Name::Derived(struct_name.clone()), - Sp::call_site(DEFAULT_CASING), - Sp::call_site(DEFAULT_ENV_CASING), - ); - - let constructor = gen_constructor(fields, &attrs); - let updater = gen_updater(fields, &attrs, true); + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + let constructor = gen_constructor(fields); + let updater = gen_updater(fields, true); let raw_deprecated = raw_deprecated(); - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + let app_var = Ident::new("__clap_app", Span::call_site()); + let augmentation = gen_augment(fields, &app_var, item, false); + let augmentation_update = gen_augment(fields, &app_var, item, true); + + let group_id = if item.skip_group() { + quote!(None) + } else { + let group_id = item.ident().unraw().to_string(); + quote!(Some(clap::Id::from(#group_id))) + }; quote! { #[allow(dead_code, unreachable_code, unused_variables, unused_braces)] @@ -131,14 +111,14 @@ pub fn gen_from_arg_matches_for_struct( clippy::suspicious_else_formatting, )] #[deny(clippy::correctness)] - impl #impl_generics clap::FromArgMatches for #struct_name #ty_generics #where_clause { + impl #impl_generics clap::FromArgMatches for #item_name #ty_generics #where_clause { fn from_arg_matches(__clap_arg_matches: &clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> { Self::from_arg_matches_mut(&mut __clap_arg_matches.clone()) } fn from_arg_matches_mut(__clap_arg_matches: &mut clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> { #raw_deprecated - let v = #struct_name #constructor; + let v = #item_name #constructor; ::std::result::Result::Ok(v) } @@ -152,229 +132,149 @@ pub fn gen_from_arg_matches_for_struct( ::std::result::Result::Ok(()) } } + + #[allow(dead_code, unreachable_code, unused_variables, unused_braces)] + #[allow( + clippy::style, + clippy::complexity, + clippy::pedantic, + clippy::restriction, + clippy::perf, + clippy::deprecated, + clippy::nursery, + clippy::cargo, + clippy::suspicious_else_formatting, + )] + #[deny(clippy::correctness)] + impl #impl_generics clap::Args for #item_name #ty_generics #where_clause { + fn group_id() -> Option<clap::Id> { + #group_id + } + fn augment_args<'b>(#app_var: clap::Command) -> clap::Command { + #augmentation + } + fn augment_args_for_update<'b>(#app_var: clap::Command) -> clap::Command { + #augmentation_update + } + } } } /// Generate a block of code to add arguments/subcommands corresponding to /// the `fields` to an cmd. pub fn gen_augment( - fields: &Punctuated<Field, Comma>, + fields: &[(&Field, Item)], app_var: &Ident, - parent_attribute: &Attrs, + parent_item: &Item, override_required: bool, ) -> TokenStream { - let mut subcmds = fields.iter().filter_map(|field| { - let attrs = Attrs::from_field( - field, - parent_attribute.casing(), - parent_attribute.env_casing(), - ); - let kind = attrs.kind(); - if let Kind::Subcommand(ty) = &*kind { - let subcmd_type = match (**ty, sub_type(&field.ty)) { - (Ty::Option, Some(sub_type)) => sub_type, - _ => &field.ty, - }; - let required = if **ty == Ty::Option { - quote!() - } else { - quote_spanned! { kind.span()=> - #[allow(deprecated)] - let #app_var = #app_var.setting( - clap::AppSettings::SubcommandRequiredElseHelp - ); + let mut subcommand_specified = false; + let args = fields.iter().filter_map(|(field, item)| { + let kind = item.kind(); + match &*kind { + Kind::Command(_) + | Kind::Value + | Kind::Skip(_, _) + | Kind::FromGlobal(_) + | Kind::ExternalSubcommand => None, + Kind::Subcommand(ty) => { + if subcommand_specified { + abort!(field.span(), "`#[command(subcommand)]` can only be used once per container"); } - }; + subcommand_specified = true; - let span = field.span(); - let ts = if override_required { - quote! { - let #app_var = <#subcmd_type as clap::Subcommand>::augment_subcommands_for_update( #app_var ); - } - } else{ - quote! { + let subcmd_type = match (**ty, sub_type(&field.ty)) { + (Ty::Option, Some(sub_type)) => sub_type, + _ => &field.ty, + }; + let implicit_methods = if **ty == Ty::Option { + quote!() + } else { + quote_spanned! { kind.span()=> + .subcommand_required(true) + .arg_required_else_help(true) + } + }; + + let override_methods = if override_required { + quote_spanned! { kind.span()=> + .subcommand_required(false) + .arg_required_else_help(false) + } + } else { + quote!() + }; + + Some(quote! { let #app_var = <#subcmd_type as clap::Subcommand>::augment_subcommands( #app_var ); - #required - } - }; - Some((span, ts)) - } else { - None - } - }); - let subcmd = subcmds.next().map(|(_, ts)| ts); - if let Some((span, _)) = subcmds.next() { - abort!( - span, - "multiple subcommand sets are not allowed, that's the second" - ); - } + let #app_var = #app_var + #implicit_methods + #override_methods; + }) + } + Kind::Flatten(ty) => { + let inner_type = match (**ty, sub_type(&field.ty)) { + (Ty::Option, Some(sub_type)) => sub_type, + _ => &field.ty, + }; - let args = fields.iter().filter_map(|field| { - let attrs = Attrs::from_field( - field, - parent_attribute.casing(), - parent_attribute.env_casing(), - ); - let kind = attrs.kind(); - match &*kind { - Kind::Subcommand(_) - | Kind::Skip(_) - | Kind::FromGlobal(_) - | Kind::ExternalSubcommand => None, - Kind::Flatten => { - let ty = &field.ty; - let old_heading_var = format_ident!("__clap_old_heading"); - let next_help_heading = attrs.next_help_heading(); - let next_display_order = attrs.next_display_order(); + let next_help_heading = item.next_help_heading(); + let next_display_order = item.next_display_order(); if override_required { Some(quote_spanned! { kind.span()=> - let #old_heading_var = #app_var.get_next_help_heading(); - let #app_var = #app_var #next_help_heading #next_display_order; - let #app_var = <#ty as clap::Args>::augment_args_for_update(#app_var); - let #app_var = #app_var.next_help_heading(#old_heading_var); + let #app_var = #app_var + #next_help_heading + #next_display_order; + let #app_var = <#inner_type as clap::Args>::augment_args_for_update(#app_var); }) } else { Some(quote_spanned! { kind.span()=> - let #old_heading_var = #app_var.get_next_help_heading(); - let #app_var = #app_var #next_help_heading #next_display_order; - let #app_var = <#ty as clap::Args>::augment_args(#app_var); - let #app_var = #app_var.next_help_heading(#old_heading_var); + let #app_var = #app_var + #next_help_heading + #next_display_order; + let #app_var = <#inner_type as clap::Args>::augment_args(#app_var); }) } } Kind::Arg(ty) => { - let convert_type = inner_type(&field.ty); - - let parser = attrs.parser(&field.ty); - - let value_parser = attrs.value_parser(&field.ty); - let action = attrs.action(&field.ty); - let func = &parser.func; - - let mut occurrences = false; - let mut flag = false; - let validator = match *parser.kind { - _ if attrs.ignore_parser() || attrs.is_enum() => quote!(), - ParserKind::TryFromStr => quote_spanned! { func.span()=> - .validator(|s| { - #func(s) - .map(|_: #convert_type| ()) - }) - }, - ParserKind::TryFromOsStr => quote_spanned! { func.span()=> - .validator_os(|s| #func(s).map(|_: #convert_type| ())) - }, - ParserKind::FromStr | ParserKind::FromOsStr => quote!(), - ParserKind::FromFlag => { - flag = true; - quote!() - } - ParserKind::FromOccurrences => { - occurrences = true; - quote!() - } - }; - let parse_deprecation = match *parser.kind { - _ if !attrs.explicit_parser() || cfg!(not(feature = "deprecated")) => quote!(), - ParserKind::FromStr => quote_spanned! { func.span()=> - #[deprecated(since = "3.2.0", note = "Replaced with `#[clap(value_parser = ...)]`")] - fn parse_from_str() { - } - parse_from_str(); - }, - ParserKind::TryFromStr => quote_spanned! { func.span()=> - #[deprecated(since = "3.2.0", note = "Replaced with `#[clap(value_parser = ...)]`")] - fn parse_try_from_str() { - } - parse_try_from_str(); - }, - ParserKind::FromOsStr => quote_spanned! { func.span()=> - #[deprecated(since = "3.2.0", note = "Replaced with `#[clap(value_parser)]` for `PathBuf` or `#[clap(value_parser = ...)]` with a custom `TypedValueParser`")] - fn parse_from_os_str() { - } - parse_from_os_str(); - }, - ParserKind::TryFromOsStr => quote_spanned! { func.span()=> - #[deprecated(since = "3.2.0", note = "Replaced with `#[clap(value_parser = ...)]` with a custom `TypedValueParser`")] - fn parse_try_from_os_str() { - } - parse_try_from_os_str(); - }, - ParserKind::FromFlag => quote_spanned! { func.span()=> - #[deprecated(since = "3.2.0", note = "Replaced with `#[clap(action = ArgAction::SetTrue)]`")] - fn parse_from_flag() { - } - parse_from_flag(); - }, - ParserKind::FromOccurrences => quote_spanned! { func.span()=> - #[deprecated(since = "3.2.0", note = "Replaced with `#[clap(action = ArgAction::Count)]` with a field type of `u8`")] - fn parse_from_occurrences() { - } - parse_from_occurrences(); - }, - }; - - let value_name = attrs.value_name(); - let possible_values = if attrs.is_enum() && !attrs.ignore_parser() { - gen_value_enum_possible_values(convert_type) - } else { - quote!() - }; + let value_parser = item.value_parser(&field.ty); + let action = item.action(&field.ty); + let value_name = item.value_name(); let implicit_methods = match **ty { + Ty::Unit => { + // Leaving out `value_parser` as it will always fail + quote_spanned! { ty.span()=> + .value_name(#value_name) + #action + } + } Ty::Option => { quote_spanned! { ty.span()=> - .takes_value(true) .value_name(#value_name) - #possible_values - #validator #value_parser #action } } Ty::OptionOption => quote_spanned! { ty.span()=> - .takes_value(true) .value_name(#value_name) - .min_values(0) - .max_values(1) - .multiple_values(false) - #possible_values - #validator + .num_args(0..=1) #value_parser #action }, Ty::OptionVec => { - if attrs.ignore_parser() { - if attrs.is_positional() { - quote_spanned! { ty.span()=> - .takes_value(true) - .value_name(#value_name) - .multiple_values(true) // action won't be sufficient for getting multiple - #possible_values - #validator - #value_parser - #action - } - } else { - quote_spanned! { ty.span()=> - .takes_value(true) - .value_name(#value_name) - #possible_values - #validator - #value_parser - #action - } + if item.is_positional() { + quote_spanned! { ty.span()=> + .value_name(#value_name) + .num_args(1..) // action won't be sufficient for getting multiple + #value_parser + #action } } else { quote_spanned! { ty.span()=> - .takes_value(true) .value_name(#value_name) - .multiple_occurrences(true) - #possible_values - #validator #value_parser #action } @@ -382,72 +282,63 @@ pub fn gen_augment( } Ty::Vec => { - if attrs.ignore_parser() { - if attrs.is_positional() { - quote_spanned! { ty.span()=> - .takes_value(true) - .value_name(#value_name) - .multiple_values(true) // action won't be sufficient for getting multiple - #possible_values - #validator - #value_parser - #action - } - } else { - quote_spanned! { ty.span()=> - .takes_value(true) - .value_name(#value_name) - #possible_values - #validator - #value_parser - #action - } + if item.is_positional() { + quote_spanned! { ty.span()=> + .value_name(#value_name) + .num_args(1..) // action won't be sufficient for getting multiple + #value_parser + #action } } else { quote_spanned! { ty.span()=> - .takes_value(true) .value_name(#value_name) - .multiple_occurrences(true) - #possible_values - #validator #value_parser #action } } } - Ty::Other if occurrences => quote_spanned! { ty.span()=> - .multiple_occurrences(true) - }, - - Ty::Other if flag => quote_spanned! { ty.span()=> - .takes_value(false) - }, + Ty::VecVec | Ty::OptionVecVec => { + quote_spanned! { ty.span() => + .value_name(#value_name) + #value_parser + #action + } + } Ty::Other => { - let required = attrs.find_default_method().is_none() && !override_required; + let required = item.find_default_method().is_none(); // `ArgAction::takes_values` is assuming `ArgAction::default_value` will be // set though that won't always be true but this should be good enough, // otherwise we'll report an "arg required" error when unwrapping. let action_value = action.args(); quote_spanned! { ty.span()=> - .takes_value(true) .value_name(#value_name) .required(#required && #action_value.takes_values()) - #possible_values - #validator #value_parser #action } } }; - let id = attrs.id(); - let explicit_methods = attrs.field_methods(true); + let id = item.id(); + let explicit_methods = item.field_methods(); + let deprecations = if !override_required { + item.deprecations() + } else { + quote!() + }; + let override_methods = if override_required { + quote_spanned! { kind.span()=> + .required(false) + } + } else { + quote!() + }; Some(quote_spanned! { field.span()=> let #app_var = #app_var.arg({ - #parse_deprecation + #deprecations #[allow(deprecated)] let arg = clap::Arg::new(#id) @@ -455,6 +346,10 @@ pub fn gen_augment( let arg = arg #explicit_methods; + + let arg = arg + #override_methods; + arg }); }) @@ -462,36 +357,80 @@ pub fn gen_augment( } }); - let initial_app_methods = parent_attribute.initial_top_level_methods(); - let final_app_methods = parent_attribute.final_top_level_methods(); + let deprecations = if !override_required { + parent_item.deprecations() + } else { + quote!() + }; + let initial_app_methods = parent_item.initial_top_level_methods(); + let final_app_methods = parent_item.final_top_level_methods(); + let group_app_methods = if parent_item.skip_group() { + quote!() + } else { + let group_id = parent_item.ident().unraw().to_string(); + let literal_group_members = fields + .iter() + .filter_map(|(_field, item)| { + let kind = item.kind(); + if matches!(*kind, Kind::Arg(_)) { + Some(item.id()) + } else { + None + } + }) + .collect::<Vec<_>>(); + let literal_group_members_len = literal_group_members.len(); + let mut literal_group_members = quote! {{ + let members: [clap::Id; #literal_group_members_len] = [#( clap::Id::from(#literal_group_members) ),* ]; + members + }}; + // HACK: Validation isn't ready yet for nested arg groups, so just don't populate the group in + // that situation + let possible_group_members_len = fields + .iter() + .filter(|(_field, item)| { + let kind = item.kind(); + matches!(*kind, Kind::Flatten(_)) + }) + .count(); + if 0 < possible_group_members_len { + literal_group_members = quote! {{ + let members: [clap::Id; 0] = []; + members + }}; + } + + quote!( + .group( + clap::ArgGroup::new(#group_id) + .multiple(true) + .args(#literal_group_members) + ) + ) + }; quote! {{ - let #app_var = #app_var #initial_app_methods; + #deprecations + let #app_var = #app_var + #initial_app_methods + #group_app_methods + ; #( #args )* - #subcmd #app_var #final_app_methods }} } -fn gen_value_enum_possible_values(ty: &Type) -> TokenStream { - quote_spanned! { ty.span()=> - .possible_values(<#ty as clap::ValueEnum>::value_variants().iter().filter_map(clap::ValueEnum::to_possible_value)) - } -} - -pub fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs) -> TokenStream { - let fields = fields.iter().map(|field| { - let attrs = Attrs::from_field( - field, - parent_attribute.casing(), - parent_attribute.env_casing(), - ); +pub fn gen_constructor(fields: &[(&Field, Item)]) -> TokenStream { + let fields = fields.iter().map(|(field, item)| { let field_name = field.ident.as_ref().unwrap(); - let kind = attrs.kind(); + let kind = item.kind(); let arg_matches = format_ident!("__clap_arg_matches"); match &*kind { - Kind::ExternalSubcommand => { + Kind::Command(_) + | Kind::Value + | Kind::ExternalSubcommand => { abort! { kind.span(), - "`external_subcommand` can be used only on enum variants" + "`{}` cannot be used with `arg`", + kind.name(), } } Kind::Subcommand(ty) => { @@ -511,27 +450,76 @@ pub fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Att } } }, - _ => { + Ty::Other => { quote_spanned! { kind.span()=> #field_name: { <#subcmd_type as clap::FromArgMatches>::from_arg_matches_mut(#arg_matches)? } } }, + Ty::Unit | + Ty::Vec | + Ty::OptionOption | + Ty::OptionVec | + Ty::VecVec | + Ty::OptionVecVec => { + abort!( + ty.span(), + "{} types are not supported for subcommand", + ty.as_str() + ); + } } } - Kind::Flatten => quote_spanned! { kind.span()=> - #field_name: clap::FromArgMatches::from_arg_matches_mut(#arg_matches)? + Kind::Flatten(ty) => { + let inner_type = match (**ty, sub_type(&field.ty)) { + (Ty::Option, Some(sub_type)) => sub_type, + _ => &field.ty, + }; + match **ty { + Ty::Other => { + quote_spanned! { kind.span()=> + #field_name: <#inner_type as clap::FromArgMatches>::from_arg_matches_mut(#arg_matches)? + } + }, + Ty::Option => { + quote_spanned! { kind.span()=> + #field_name: { + let group_id = <#inner_type as clap::Args>::group_id() + .expect("`#[arg(flatten)]`ed field type implements `Args::group_id`"); + if #arg_matches.contains_id(group_id.as_str()) { + Some( + <#inner_type as clap::FromArgMatches>::from_arg_matches_mut(#arg_matches)? + ) + } else { + None + } + } + } + }, + Ty::Unit | + Ty::Vec | + Ty::OptionOption | + Ty::OptionVec | + Ty::VecVec | + Ty::OptionVecVec => { + abort!( + ty.span(), + "{} types are not supported for flatten", + ty.as_str() + ); + } + } }, - Kind::Skip(val) => match val { + Kind::Skip(val, _) => match val { None => quote_spanned!(kind.span()=> #field_name: Default::default()), Some(val) => quote_spanned!(kind.span()=> #field_name: (#val).into()), }, Kind::Arg(ty) | Kind::FromGlobal(ty) => { - gen_parsers(&attrs, ty, field_name, field, None) + gen_parsers(item, ty, field_name, field, None) } } }); @@ -541,19 +529,10 @@ pub fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Att }} } -pub fn gen_updater( - fields: &Punctuated<Field, Comma>, - parent_attribute: &Attrs, - use_self: bool, -) -> TokenStream { - let fields = fields.iter().map(|field| { - let attrs = Attrs::from_field( - field, - parent_attribute.casing(), - parent_attribute.env_casing(), - ); +pub fn gen_updater(fields: &[(&Field, Item)], use_self: bool) -> TokenStream { + let fields = fields.iter().map(|(field, item)| { let field_name = field.ident.as_ref().unwrap(); - let kind = attrs.kind(); + let kind = item.kind(); let access = if use_self { quote! { @@ -566,9 +545,12 @@ pub fn gen_updater( let arg_matches = format_ident!("__clap_arg_matches"); match &*kind { - Kind::ExternalSubcommand => { + Kind::Command(_) + | Kind::Value + | Kind::ExternalSubcommand => { abort! { kind.span(), - "`external_subcommand` can be used only on enum variants" + "`{}` cannot be used with `arg`", + kind.name(), } } Kind::Subcommand(ty) => { @@ -604,15 +586,42 @@ pub fn gen_updater( } } - Kind::Flatten => quote_spanned! { kind.span()=> { - #access - clap::FromArgMatches::update_from_arg_matches_mut(#field_name, #arg_matches)?; + Kind::Flatten(ty) => { + let inner_type = match (**ty, sub_type(&field.ty)) { + (Ty::Option, Some(sub_type)) => sub_type, + _ => &field.ty, + }; + + let updater = quote_spanned! { ty.span()=> + <#inner_type as clap::FromArgMatches>::update_from_arg_matches_mut(#field_name, #arg_matches)?; + }; + + let updater = match **ty { + Ty::Option => quote_spanned! { kind.span()=> + if let Some(#field_name) = #field_name.as_mut() { + #updater + } else { + *#field_name = Some(<#inner_type as clap::FromArgMatches>::from_arg_matches_mut( + #arg_matches + )?); + } + }, + _ => quote_spanned! { kind.span()=> + #updater + }, + }; + + quote_spanned! { kind.span()=> + { + #access + #updater + } } }, - Kind::Skip(_) => quote!(), + Kind::Skip(_, _) => quote!(), - Kind::Arg(ty) | Kind::FromGlobal(ty) => gen_parsers(&attrs, ty, field_name, field, Some(&access)), + Kind::Arg(ty) | Kind::FromGlobal(ty) => gen_parsers(item, ty, field_name, field, Some(&access)), } }); @@ -622,78 +631,18 @@ pub fn gen_updater( } fn gen_parsers( - attrs: &Attrs, + item: &Item, ty: &Sp<Ty>, field_name: &Ident, field: &Field, update: Option<&TokenStream>, ) -> TokenStream { - use self::ParserKind::*; - - let parser = attrs.parser(&field.ty); - let func = &parser.func; - let span = parser.kind.span(); + let span = ty.span(); let convert_type = inner_type(&field.ty); - let id = attrs.id(); - let mut flag = false; - let mut occurrences = false; - let (get_one, get_many, deref, mut parse) = match *parser.kind { - _ if attrs.ignore_parser() => ( - quote_spanned!(span=> remove_one::<#convert_type>), - quote_spanned!(span=> remove_many::<#convert_type>), - quote!(|s| s), - quote_spanned!(func.span()=> |s| ::std::result::Result::Ok::<_, clap::Error>(s)), - ), - FromOccurrences => { - occurrences = true; - ( - quote_spanned!(span=> occurrences_of), - quote!(), - quote!(|s| ::std::ops::Deref::deref(s)), - func.clone(), - ) - } - FromFlag => { - flag = true; - ( - quote!(), - quote!(), - quote!(|s| ::std::ops::Deref::deref(s)), - func.clone(), - ) - } - FromStr => ( - quote_spanned!(span=> get_one::<String>), - quote_spanned!(span=> get_many::<String>), - quote!(|s| ::std::ops::Deref::deref(s)), - quote_spanned!(func.span()=> |s| ::std::result::Result::Ok::<_, clap::Error>(#func(s))), - ), - TryFromStr => ( - quote_spanned!(span=> get_one::<String>), - quote_spanned!(span=> get_many::<String>), - quote!(|s| ::std::ops::Deref::deref(s)), - quote_spanned!(func.span()=> |s| #func(s).map_err(|err| clap::Error::raw(clap::ErrorKind::ValueValidation, format!("Invalid value for {}: {}", #id, err)))), - ), - FromOsStr => ( - quote_spanned!(span=> get_one::<::std::ffi::OsString>), - quote_spanned!(span=> get_many::<::std::ffi::OsString>), - quote!(|s| ::std::ops::Deref::deref(s)), - quote_spanned!(func.span()=> |s| ::std::result::Result::Ok::<_, clap::Error>(#func(s))), - ), - TryFromOsStr => ( - quote_spanned!(span=> get_one::<::std::ffi::OsString>), - quote_spanned!(span=> get_many::<::std::ffi::OsString>), - quote!(|s| ::std::ops::Deref::deref(s)), - quote_spanned!(func.span()=> |s| #func(s).map_err(|err| clap::Error::raw(clap::ErrorKind::ValueValidation, format!("Invalid value for {}: {}", #id, err)))), - ), - }; - if attrs.is_enum() && !attrs.ignore_parser() { - let ci = attrs.ignore_case(); - - parse = quote_spanned! { convert_type.span()=> - |s| <#convert_type as clap::ValueEnum>::from_str(s, #ci).map_err(|err| clap::Error::raw(clap::ErrorKind::ValueValidation, format!("Invalid value for {}: {}", #id, err))) - } - } + let id = item.id(); + let get_one = quote_spanned!(span=> remove_one::<#convert_type>); + let get_many = quote_spanned!(span=> remove_many::<#convert_type>); + let get_occurrences = quote_spanned!(span=> remove_occurrences::<#convert_type>); // Give this identifier the same hygiene // as the `arg_matches` parameter definition. This @@ -701,12 +650,15 @@ fn gen_parsers( let arg_matches = format_ident!("__clap_arg_matches"); let field_value = match **ty { + Ty::Unit => { + quote_spanned! { ty.span()=> + () + } + } + Ty::Option => { quote_spanned! { ty.span()=> #arg_matches.#get_one(#id) - .map(#deref) - .map(#parse) - .transpose()? } } @@ -714,8 +666,6 @@ fn gen_parsers( if #arg_matches.contains_id(#id) { Some( #arg_matches.#get_one(#id) - .map(#deref) - .map(#parse).transpose()? ) } else { None @@ -725,8 +675,7 @@ fn gen_parsers( Ty::OptionVec => quote_spanned! { ty.span()=> if #arg_matches.contains_id(#id) { Some(#arg_matches.#get_many(#id) - .map(|v| v.map(#deref).map::<::std::result::Result<#convert_type, clap::Error>, _>(#parse).collect::<::std::result::Result<Vec<_>, clap::Error>>()) - .transpose()? + .map(|v| v.collect::<Vec<_>>()) .unwrap_or_else(Vec::new)) } else { None @@ -736,36 +685,26 @@ fn gen_parsers( Ty::Vec => { quote_spanned! { ty.span()=> #arg_matches.#get_many(#id) - .map(|v| v.map(#deref).map::<::std::result::Result<#convert_type, clap::Error>, _>(#parse).collect::<::std::result::Result<Vec<_>, clap::Error>>()) - .transpose()? + .map(|v| v.collect::<Vec<_>>()) .unwrap_or_else(Vec::new) } } - Ty::Other if occurrences => quote_spanned! { ty.span()=> - #parse( - #arg_matches.#get_one(#id) - ) + Ty::VecVec => quote_spanned! { ty.span()=> + #arg_matches.#get_occurrences(#id) + .map(|g| g.map(::std::iter::Iterator::collect).collect::<Vec<Vec<_>>>()) + .unwrap_or_else(Vec::new) }, - Ty::Other if flag => { - if update.is_some() && is_simple_ty(&field.ty, "bool") { - quote_spanned! { ty.span()=> - *#field_name || #arg_matches.is_present(#id) - } - } else { - quote_spanned! { ty.span()=> - #parse(#arg_matches.is_present(#id)) - } - } - } + Ty::OptionVecVec => quote_spanned! { ty.span()=> + #arg_matches.#get_occurrences(#id) + .map(|g| g.map(::std::iter::Iterator::collect).collect::<Vec<Vec<_>>>()) + }, Ty::Other => { quote_spanned! { ty.span()=> #arg_matches.#get_one(#id) - .map(#deref) - .ok_or_else(|| clap::Error::raw(clap::ErrorKind::MissingRequiredArgument, format!("The following required argument was not provided: {}", #id))) - .and_then(#parse)? + .ok_or_else(|| clap::Error::raw(clap::error::ErrorKind::MissingRequiredArgument, format!("The following required argument was not provided: {}", #id)))? } } }; diff --git a/vendor/clap_derive/src/derives/into_app.rs b/vendor/clap_derive/src/derives/into_app.rs index 319735753..a45667ab2 100644 --- a/vendor/clap_derive/src/derives/into_app.rs +++ b/vendor/clap_derive/src/derives/into_app.rs @@ -12,36 +12,18 @@ // commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the // MIT/Apache 2.0 license. -use std::env; - use proc_macro2::{Span, TokenStream}; use quote::quote; -use syn::{Attribute, Generics, Ident}; +use syn::{Generics, Ident}; -use crate::{ - attrs::{Attrs, Name, DEFAULT_CASING, DEFAULT_ENV_CASING}, - utils::Sp, -}; +use crate::item::Item; -pub fn gen_for_struct( - struct_name: &Ident, - generics: &Generics, - attrs: &[Attribute], -) -> TokenStream { - let app_name = env::var("CARGO_PKG_NAME").ok().unwrap_or_default(); +pub fn gen_for_struct(item: &Item, item_name: &Ident, generics: &Generics) -> TokenStream { + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - let attrs = Attrs::from_struct( - Span::call_site(), - attrs, - Name::Assigned(quote!(#app_name)), - Sp::call_site(DEFAULT_CASING), - Sp::call_site(DEFAULT_ENV_CASING), - ); - let name = attrs.cased_name(); + let name = item.cased_name(); let app_var = Ident::new("__clap_app", Span::call_site()); - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - let tokens = quote! { #[allow(dead_code, unreachable_code, unused_variables, unused_braces)] #[allow( @@ -56,14 +38,13 @@ pub fn gen_for_struct( clippy::suspicious_else_formatting, )] #[deny(clippy::correctness)] - #[allow(deprecated)] - impl #impl_generics clap::CommandFactory for #struct_name #ty_generics #where_clause { - fn into_app<'b>() -> clap::Command<'b> { + impl #impl_generics clap::CommandFactory for #item_name #ty_generics #where_clause { + fn command<'b>() -> clap::Command { let #app_var = clap::Command::new(#name); <Self as clap::Args>::augment_args(#app_var) } - fn into_app_for_update<'b>() -> clap::Command<'b> { + fn command_for_update<'b>() -> clap::Command { let #app_var = clap::Command::new(#name); <Self as clap::Args>::augment_args_for_update(#app_var) } @@ -73,21 +54,12 @@ pub fn gen_for_struct( tokens } -pub fn gen_for_enum(enum_name: &Ident, generics: &Generics, attrs: &[Attribute]) -> TokenStream { - let app_name = env::var("CARGO_PKG_NAME").ok().unwrap_or_default(); +pub fn gen_for_enum(item: &Item, item_name: &Ident, generics: &Generics) -> TokenStream { + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - let attrs = Attrs::from_struct( - Span::call_site(), - attrs, - Name::Assigned(quote!(#app_name)), - Sp::call_site(DEFAULT_CASING), - Sp::call_site(DEFAULT_ENV_CASING), - ); - let name = attrs.cased_name(); + let name = item.cased_name(); let app_var = Ident::new("__clap_app", Span::call_site()); - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - quote! { #[allow(dead_code, unreachable_code, unused_variables, unused_braces)] #[allow( @@ -102,17 +74,19 @@ pub fn gen_for_enum(enum_name: &Ident, generics: &Generics, attrs: &[Attribute]) clippy::suspicious_else_formatting, )] #[deny(clippy::correctness)] - impl #impl_generics clap::CommandFactory for #enum_name #ty_generics #where_clause { - fn into_app<'b>() -> clap::Command<'b> { - #[allow(deprecated)] + impl #impl_generics clap::CommandFactory for #item_name #ty_generics #where_clause { + fn command<'b>() -> clap::Command { let #app_var = clap::Command::new(#name) - .setting(clap::AppSettings::SubcommandRequiredElseHelp); + .subcommand_required(true) + .arg_required_else_help(true); <Self as clap::Subcommand>::augment_subcommands(#app_var) } - fn into_app_for_update<'b>() -> clap::Command<'b> { + fn command_for_update<'b>() -> clap::Command { let #app_var = clap::Command::new(#name); <Self as clap::Subcommand>::augment_subcommands_for_update(#app_var) + .subcommand_required(false) + .arg_required_else_help(false) } } } diff --git a/vendor/clap_derive/src/derives/parser.rs b/vendor/clap_derive/src/derives/parser.rs index 621430f31..617857cac 100644 --- a/vendor/clap_derive/src/derives/parser.rs +++ b/vendor/clap_derive/src/derives/parser.rs @@ -12,21 +12,24 @@ // commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the // MIT/Apache 2.0 license. -use crate::{ - derives::{args, into_app, subcommand}, - dummies, -}; - use proc_macro2::TokenStream; use proc_macro_error::abort_call_site; use quote::quote; +use syn::Ident; +use syn::Variant; use syn::{ - self, punctuated::Punctuated, token::Comma, Attribute, Data, DataEnum, DataStruct, DeriveInput, - Field, Fields, Generics, Ident, + self, punctuated::Punctuated, token::Comma, Data, DataStruct, DeriveInput, Field, Fields, + Generics, }; +use crate::derives::{args, into_app, subcommand}; +use crate::dummies; +use crate::item::Item; +use crate::item::Name; + pub fn derive_parser(input: &DeriveInput) -> TokenStream { let ident = &input.ident; + let pkg_name = std::env::var("CARGO_PKG_NAME").ok().unwrap_or_default(); match input.data { Data::Struct(DataStruct { @@ -34,41 +37,70 @@ pub fn derive_parser(input: &DeriveInput) -> TokenStream { .. }) => { dummies::parser_struct(ident); - gen_for_struct(ident, &input.generics, &fields.named, &input.attrs) + + let name = Name::Assigned(quote!(#pkg_name)); + let item = Item::from_args_struct(input, name); + let fields = fields + .named + .iter() + .map(|field| { + let item = Item::from_args_field(field, item.casing(), item.env_casing()); + (field, item) + }) + .collect::<Vec<_>>(); + gen_for_struct(&item, ident, &input.generics, &fields) } Data::Struct(DataStruct { fields: Fields::Unit, .. }) => { dummies::parser_struct(ident); - gen_for_struct( - ident, - &input.generics, - &Punctuated::<Field, Comma>::new(), - &input.attrs, - ) + + let name = Name::Assigned(quote!(#pkg_name)); + let item = Item::from_args_struct(input, name); + let fields = Punctuated::<Field, Comma>::new(); + let fields = fields + .iter() + .map(|field| { + let item = Item::from_args_field(field, item.casing(), item.env_casing()); + (field, item) + }) + .collect::<Vec<_>>(); + gen_for_struct(&item, ident, &input.generics, &fields) } Data::Enum(ref e) => { dummies::parser_enum(ident); - gen_for_enum(ident, &input.generics, &input.attrs, e) + + let name = Name::Assigned(quote!(#pkg_name)); + let item = Item::from_subcommand_enum(input, name); + let variants = e + .variants + .iter() + .map(|variant| { + let item = + Item::from_subcommand_variant(variant, item.casing(), item.env_casing()); + (variant, item) + }) + .collect::<Vec<_>>(); + gen_for_enum(&item, ident, &input.generics, &variants) } _ => abort_call_site!("`#[derive(Parser)]` only supports non-tuple structs and enums"), } } fn gen_for_struct( - name: &Ident, + item: &Item, + item_name: &Ident, generics: &Generics, - fields: &Punctuated<Field, Comma>, - attrs: &[Attribute], + fields: &[(&Field, Item)], ) -> TokenStream { - let into_app = into_app::gen_for_struct(name, generics, attrs); - let args = args::gen_for_struct(name, generics, fields, attrs); - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + let into_app = into_app::gen_for_struct(item, item_name, generics); + let args = args::gen_for_struct(item, item_name, generics, fields); + quote! { - impl #impl_generics clap::Parser for #name #ty_generics #where_clause {} + impl #impl_generics clap::Parser for #item_name #ty_generics #where_clause {} #into_app #args @@ -76,18 +108,18 @@ fn gen_for_struct( } fn gen_for_enum( - name: &Ident, + item: &Item, + item_name: &Ident, generics: &Generics, - attrs: &[Attribute], - e: &DataEnum, + variants: &[(&Variant, Item)], ) -> TokenStream { - let into_app = into_app::gen_for_enum(name, generics, attrs); - let subcommand = subcommand::gen_for_enum(name, generics, attrs, e); - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + let into_app = into_app::gen_for_enum(item, item_name, generics); + let subcommand = subcommand::gen_for_enum(item, item_name, generics, variants); + quote! { - impl #impl_generics clap::Parser for #name #ty_generics #where_clause {} + impl #impl_generics clap::Parser for #item_name #ty_generics #where_clause {} #into_app #subcommand diff --git a/vendor/clap_derive/src/derives/subcommand.rs b/vendor/clap_derive/src/derives/subcommand.rs index 07bdce5ec..8a44e0c42 100644 --- a/vendor/clap_derive/src/derives/subcommand.rs +++ b/vendor/clap_derive/src/derives/subcommand.rs @@ -11,20 +11,16 @@ // This work was derived from Structopt (https://github.com/TeXitoi/structopt) // commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the // MIT/Apache 2.0 license. -use crate::{ - attrs::{Attrs, Kind, Name, DEFAULT_CASING, DEFAULT_ENV_CASING}, - derives::args, - dummies, - utils::{is_simple_ty, subty_if_name, Sp}, -}; use proc_macro2::{Ident, Span, TokenStream}; use proc_macro_error::{abort, abort_call_site}; use quote::{format_ident, quote, quote_spanned}; -use syn::{ - punctuated::Punctuated, spanned::Spanned, Attribute, Data, DataEnum, DeriveInput, - FieldsUnnamed, Generics, Token, Variant, -}; +use syn::{spanned::Spanned, Data, DeriveInput, FieldsUnnamed, Generics, Variant}; + +use crate::derives::args; +use crate::dummies; +use crate::item::{Item, Kind, Name}; +use crate::utils::{is_simple_ty, subty_if_name}; pub fn derive_subcommand(input: &DeriveInput) -> TokenStream { let ident = &input.ident; @@ -32,35 +28,47 @@ pub fn derive_subcommand(input: &DeriveInput) -> TokenStream { dummies::subcommand(ident); match input.data { - Data::Enum(ref e) => gen_for_enum(ident, &input.generics, &input.attrs, e), + Data::Enum(ref e) => { + let name = Name::Derived(ident.clone()); + let item = Item::from_subcommand_enum(input, name); + let variants = e + .variants + .iter() + .map(|variant| { + let item = + Item::from_subcommand_variant(variant, item.casing(), item.env_casing()); + (variant, item) + }) + .collect::<Vec<_>>(); + gen_for_enum(&item, ident, &input.generics, &variants) + } _ => abort_call_site!("`#[derive(Subcommand)]` only supports enums"), } } pub fn gen_for_enum( - enum_name: &Ident, + item: &Item, + item_name: &Ident, generics: &Generics, - attrs: &[Attribute], - e: &DataEnum, + variants: &[(&Variant, Item)], ) -> TokenStream { - let from_arg_matches = gen_from_arg_matches_for_enum(enum_name, generics, attrs, e); - - let attrs = Attrs::from_struct( - Span::call_site(), - attrs, - Name::Derived(enum_name.clone()), - Sp::call_site(DEFAULT_CASING), - Sp::call_site(DEFAULT_ENV_CASING), - ); - let augmentation = gen_augment(&e.variants, &attrs, false); - let augmentation_update = gen_augment(&e.variants, &attrs, true); - let has_subcommand = gen_has_subcommand(&e.variants, &attrs); + if !matches!(&*item.kind(), Kind::Command(_)) { + abort! { item.kind().span(), + "`{}` cannot be used with `command`", + item.kind().name(), + } + } let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - quote! { - #from_arg_matches + let from_arg_matches = gen_from_arg_matches(variants); + let update_from_arg_matches = gen_update_from_arg_matches(variants); + + let augmentation = gen_augment(variants, item, false); + let augmentation_update = gen_augment(variants, item, true); + let has_subcommand = gen_has_subcommand(variants); + quote! { #[allow(dead_code, unreachable_code, unused_variables, unused_braces)] #[allow( clippy::style, @@ -74,40 +82,19 @@ pub fn gen_for_enum( clippy::suspicious_else_formatting, )] #[deny(clippy::correctness)] - impl #impl_generics clap::Subcommand for #enum_name #ty_generics #where_clause { - fn augment_subcommands <'b>(__clap_app: clap::Command<'b>) -> clap::Command<'b> { - #augmentation - } - fn augment_subcommands_for_update <'b>(__clap_app: clap::Command<'b>) -> clap::Command<'b> { - #augmentation_update - } - fn has_subcommand(__clap_name: &str) -> bool { - #has_subcommand + impl #impl_generics clap::FromArgMatches for #item_name #ty_generics #where_clause { + fn from_arg_matches(__clap_arg_matches: &clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> { + Self::from_arg_matches_mut(&mut __clap_arg_matches.clone()) } - } - } -} -fn gen_from_arg_matches_for_enum( - name: &Ident, - generics: &Generics, - attrs: &[Attribute], - e: &DataEnum, -) -> TokenStream { - let attrs = Attrs::from_struct( - Span::call_site(), - attrs, - Name::Derived(name.clone()), - Sp::call_site(DEFAULT_CASING), - Sp::call_site(DEFAULT_ENV_CASING), - ); - - let from_arg_matches = gen_from_arg_matches(name, &e.variants, &attrs); - let update_from_arg_matches = gen_update_from_arg_matches(name, &e.variants, &attrs); + #from_arg_matches - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + fn update_from_arg_matches(&mut self, __clap_arg_matches: &clap::ArgMatches) -> ::std::result::Result<(), clap::Error> { + self.update_from_arg_matches_mut(&mut __clap_arg_matches.clone()) + } + #update_from_arg_matches + } - quote! { #[allow(dead_code, unreachable_code, unused_variables, unused_braces)] #[allow( clippy::style, @@ -121,24 +108,23 @@ fn gen_from_arg_matches_for_enum( clippy::suspicious_else_formatting, )] #[deny(clippy::correctness)] - impl #impl_generics clap::FromArgMatches for #name #ty_generics #where_clause { - fn from_arg_matches(__clap_arg_matches: &clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> { - Self::from_arg_matches_mut(&mut __clap_arg_matches.clone()) + impl #impl_generics clap::Subcommand for #item_name #ty_generics #where_clause { + fn augment_subcommands <'b>(__clap_app: clap::Command) -> clap::Command { + #augmentation } - - #from_arg_matches - - fn update_from_arg_matches(&mut self, __clap_arg_matches: &clap::ArgMatches) -> ::std::result::Result<(), clap::Error> { - self.update_from_arg_matches_mut(&mut __clap_arg_matches.clone()) + fn augment_subcommands_for_update <'b>(__clap_app: clap::Command) -> clap::Command { + #augmentation_update + } + fn has_subcommand(__clap_name: &str) -> bool { + #has_subcommand } - #update_from_arg_matches } } } fn gen_augment( - variants: &Punctuated<Variant, Token![,]>, - parent_attribute: &Attrs, + variants: &[(&Variant, Item)], + parent_item: &Item, override_required: bool, ) -> TokenStream { use syn::Fields::*; @@ -147,16 +133,14 @@ fn gen_augment( let subcommands: Vec<_> = variants .iter() - .filter_map(|variant| { - let attrs = Attrs::from_variant( - variant, - parent_attribute.casing(), - parent_attribute.env_casing(), - ); - let kind = attrs.kind(); + .filter_map(|(variant, item)| { + let kind = item.kind(); match &*kind { - Kind::Skip(_) => None, + Kind::Skip(_, _) | + Kind::Arg(_) | + Kind::FromGlobal(_) | + Kind::Value => None, Kind::ExternalSubcommand => { let ty = match variant.fields { @@ -169,47 +153,51 @@ fn gen_augment( or `Vec<OsString>`." ), }; - let subcommand = match subty_if_name(ty, "Vec") { - Some(subty) => { - if is_simple_ty(subty, "OsString") { - quote_spanned! { kind.span()=> - let #app_var = #app_var.allow_external_subcommands(true).allow_invalid_utf8_for_external_subcommands(true); - } - } else { - quote_spanned! { kind.span()=> - let #app_var = #app_var.allow_external_subcommands(true); - } - } - } - - None => abort!( + let deprecations = if !override_required { + item.deprecations() + } else { + quote!() + }; + let subty = subty_if_name(ty, "Vec").unwrap_or_else(|| { + abort!( ty.span(), "The type must be `Vec<_>` \ to be used with `external_subcommand`." - ), + ) + }); + let subcommand = quote_spanned! { kind.span()=> + #deprecations + let #app_var = #app_var + .external_subcommand_value_parser(clap::value_parser!(#subty)); }; Some(subcommand) } - Kind::Flatten => match variant.fields { + Kind::Flatten(_) => match variant.fields { Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => { let ty = &unnamed[0]; - let old_heading_var = format_ident!("__clap_old_heading"); - let next_help_heading = attrs.next_help_heading(); - let next_display_order = attrs.next_display_order(); + let deprecations = if !override_required { + item.deprecations() + } else { + quote!() + }; + let next_help_heading = item.next_help_heading(); + let next_display_order = item.next_display_order(); let subcommand = if override_required { quote! { - let #old_heading_var = #app_var.get_next_help_heading(); - let #app_var = #app_var #next_help_heading #next_display_order; + #deprecations + let #app_var = #app_var + #next_help_heading + #next_display_order; let #app_var = <#ty as clap::Subcommand>::augment_subcommands_for_update(#app_var); - let #app_var = #app_var.next_help_heading(#old_heading_var); } } else { quote! { - let #old_heading_var = #app_var.get_next_help_heading(); - let #app_var = #app_var #next_help_heading #next_display_order; + #deprecations + let #app_var = #app_var + #next_help_heading + #next_display_order; let #app_var = <#ty as clap::Subcommand>::augment_subcommands(#app_var); - let #app_var = #app_var.next_help_heading(#old_heading_var); } }; Some(subcommand) @@ -248,33 +236,56 @@ fn gen_augment( } }; - let name = attrs.cased_name(); - let initial_app_methods = attrs.initial_top_level_methods(); - let final_from_attrs = attrs.final_top_level_methods(); + let name = item.cased_name(); + let deprecations = if !override_required { + item.deprecations() + } else { + quote!() + }; + let initial_app_methods = item.initial_top_level_methods(); + let final_from_attrs = item.final_top_level_methods(); + let override_methods = if override_required { + quote_spanned! { kind.span()=> + .subcommand_required(false) + .arg_required_else_help(false) + } + } else { + quote!() + }; let subcommand = quote! { let #app_var = #app_var.subcommand({ + #deprecations; let #subcommand_var = clap::Command::new(#name); + let #subcommand_var = #subcommand_var + .subcommand_required(true) + .arg_required_else_help(true); let #subcommand_var = #subcommand_var #initial_app_methods; let #subcommand_var = #arg_block; - #[allow(deprecated)] - let #subcommand_var = #subcommand_var.setting(clap::AppSettings::SubcommandRequiredElseHelp); - #subcommand_var #final_from_attrs + #subcommand_var #final_from_attrs #override_methods }); }; Some(subcommand) } - _ => { + Kind::Command(_) => { let subcommand_var = Ident::new("__clap_subcommand", Span::call_site()); let sub_augment = match variant.fields { Named(ref fields) => { // Defer to `gen_augment` for adding cmd methods - args::gen_augment(&fields.named, &subcommand_var, &attrs, override_required) + let fields = fields + .named + .iter() + .map(|field| { + let item = Item::from_args_field(field, item.casing(), item.env_casing()); + (field, item) + }) + .collect::<Vec<_>>(); + args::gen_augment(&fields, &subcommand_var, item, override_required) } Unit => { let arg_block = quote!( #subcommand_var ); - let initial_app_methods = attrs.initial_top_level_methods(); - let final_from_attrs = attrs.final_top_level_methods(); + let initial_app_methods = item.initial_top_level_methods(); + let final_from_attrs = item.final_top_level_methods(); quote! { let #subcommand_var = #subcommand_var #initial_app_methods; let #subcommand_var = #arg_block; @@ -296,8 +307,8 @@ fn gen_augment( } } }; - let initial_app_methods = attrs.initial_top_level_methods(); - let final_from_attrs = attrs.final_top_level_methods(); + let initial_app_methods = item.initial_top_level_methods(); + let final_from_attrs = item.final_top_level_methods(); quote! { let #subcommand_var = #subcommand_var #initial_app_methods; let #subcommand_var = #arg_block; @@ -309,9 +320,15 @@ fn gen_augment( } }; - let name = attrs.cased_name(); + let deprecations = if !override_required { + item.deprecations() + } else { + quote!() + }; + let name = item.cased_name(); let subcommand = quote! { let #app_var = #app_var.subcommand({ + #deprecations let #subcommand_var = clap::Command::new(#name); #sub_augment }); @@ -322,46 +339,47 @@ fn gen_augment( }) .collect(); - let initial_app_methods = parent_attribute.initial_top_level_methods(); - let final_app_methods = parent_attribute.final_top_level_methods(); + let deprecations = if !override_required { + parent_item.deprecations() + } else { + quote!() + }; + let initial_app_methods = parent_item.initial_top_level_methods(); + let final_app_methods = parent_item.final_top_level_methods(); quote! { - let #app_var = #app_var #initial_app_methods; - #( #subcommands )*; - #app_var #final_app_methods + #deprecations; + let #app_var = #app_var #initial_app_methods; + #( #subcommands )*; + #app_var #final_app_methods } } -fn gen_has_subcommand( - variants: &Punctuated<Variant, Token![,]>, - parent_attribute: &Attrs, -) -> TokenStream { +fn gen_has_subcommand(variants: &[(&Variant, Item)]) -> TokenStream { use syn::Fields::*; let mut ext_subcmd = false; let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants .iter() - .filter_map(|variant| { - let attrs = Attrs::from_variant( - variant, - parent_attribute.casing(), - parent_attribute.env_casing(), - ); + .filter_map(|(variant, item)| { + let kind = item.kind(); + match &*kind { + Kind::Skip(_, _) | Kind::Arg(_) | Kind::FromGlobal(_) | Kind::Value => None, - if let Kind::ExternalSubcommand = &*attrs.kind() { - ext_subcmd = true; - None - } else { - Some((variant, attrs)) + Kind::ExternalSubcommand => { + ext_subcmd = true; + None + } + Kind::Flatten(_) | Kind::Subcommand(_) | Kind::Command(_) => Some((variant, item)), } }) - .partition(|(_, attrs)| { - let kind = attrs.kind(); - matches!(&*kind, Kind::Flatten) + .partition(|(_, item)| { + let kind = item.kind(); + matches!(&*kind, Kind::Flatten(_)) }); - let subcommands = variants.iter().map(|(_variant, attrs)| { - let sub_name = attrs.cased_name(); + let subcommands = variants.iter().map(|(_variant, item)| { + let sub_name = item.cased_name(); quote! { if #sub_name == __clap_name { return true @@ -398,11 +416,7 @@ fn gen_has_subcommand( } } -fn gen_from_arg_matches( - name: &Ident, - variants: &Punctuated<Variant, Token![,]>, - parent_attribute: &Attrs, -) -> TokenStream { +fn gen_from_arg_matches(variants: &[(&Variant, Item)]) -> TokenStream { use syn::Fields::*; let mut ext_subcmd = None; @@ -411,71 +425,79 @@ fn gen_from_arg_matches( let sub_arg_matches_var = format_ident!("__clap_arg_matches"); let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants .iter() - .filter_map(|variant| { - let attrs = Attrs::from_variant( - variant, - parent_attribute.casing(), - parent_attribute.env_casing(), - ); - - if let Kind::ExternalSubcommand = &*attrs.kind() { - if ext_subcmd.is_some() { - abort!( - attrs.kind().span(), - "Only one variant can be marked with `external_subcommand`, \ + .filter_map(|(variant, item)| { + let kind = item.kind(); + match &*kind { + Kind::Skip(_, _) | Kind::Arg(_) | Kind::FromGlobal(_) | Kind::Value => None, + + Kind::ExternalSubcommand => { + if ext_subcmd.is_some() { + abort!( + item.kind().span(), + "Only one variant can be marked with `external_subcommand`, \ this is the second" - ); - } + ); + } - let ty = match variant.fields { - Unnamed(ref fields) if fields.unnamed.len() == 1 => &fields.unnamed[0].ty, + let ty = match variant.fields { + Unnamed(ref fields) if fields.unnamed.len() == 1 => &fields.unnamed[0].ty, - _ => abort!( - variant, - "The enum variant marked with `external_subcommand` must be \ + _ => abort!( + variant, + "The enum variant marked with `external_subcommand` must be \ a single-typed tuple, and the type must be either `Vec<String>` \ or `Vec<OsString>`." - ), - }; - - let (span, str_ty) = match subty_if_name(ty, "Vec") { - Some(subty) => { - if is_simple_ty(subty, "String") { - (subty.span(), quote!(::std::string::String)) - } else if is_simple_ty(subty, "OsString") { - (subty.span(), quote!(::std::ffi::OsString)) - } else { - abort!( - ty.span(), - "The type must be either `Vec<String>` or `Vec<OsString>` \ + ), + }; + + let (span, str_ty) = match subty_if_name(ty, "Vec") { + Some(subty) => { + if is_simple_ty(subty, "String") { + (subty.span(), quote!(::std::string::String)) + } else if is_simple_ty(subty, "OsString") { + (subty.span(), quote!(::std::ffi::OsString)) + } else { + abort!( + ty.span(), + "The type must be either `Vec<String>` or `Vec<OsString>` \ to be used with `external_subcommand`." - ); + ); + } } - } - None => abort!( - ty.span(), - "The type must be either `Vec<String>` or `Vec<OsString>` \ + None => abort!( + ty.span(), + "The type must be either `Vec<String>` or `Vec<OsString>` \ to be used with `external_subcommand`." - ), - }; + ), + }; - ext_subcmd = Some((span, &variant.ident, str_ty)); - None - } else { - Some((variant, attrs)) + ext_subcmd = Some((span, &variant.ident, str_ty)); + None + } + Kind::Flatten(_) | Kind::Subcommand(_) | Kind::Command(_) => Some((variant, item)), } }) - .partition(|(_, attrs)| { - let kind = attrs.kind(); - matches!(&*kind, Kind::Flatten) + .partition(|(_, item)| { + let kind = item.kind(); + matches!(&*kind, Kind::Flatten(_)) }); - let subcommands = variants.iter().map(|(variant, attrs)| { - let sub_name = attrs.cased_name(); + let subcommands = variants.iter().map(|(variant, item)| { + let sub_name = item.cased_name(); let variant_name = &variant.ident; let constructor_block = match variant.fields { - Named(ref fields) => args::gen_constructor(&fields.named, attrs), + Named(ref fields) => { + let fields = fields + .named + .iter() + .map(|field| { + let item = Item::from_args_field(field, item.casing(), item.env_casing()); + (field, item) + }) + .collect::<Vec<_>>(); + args::gen_constructor(&fields) + }, Unit => quote!(), Unnamed(ref fields) if fields.unnamed.len() == 1 => { let ty = &fields.unnamed[0]; @@ -484,17 +506,9 @@ fn gen_from_arg_matches( Unnamed(..) => abort_call_site!("{}: tuple enums are not supported", variant.ident), }; - if cfg!(feature = "unstable-v4") { - quote! { - if #sub_name == #subcommand_name_var && !#sub_arg_matches_var.contains_id("") { - return ::std::result::Result::Ok(#name :: #variant_name #constructor_block) - } - } - } else { - quote! { - if #sub_name == #subcommand_name_var { - return ::std::result::Result::Ok(#name :: #variant_name #constructor_block) - } + quote! { + if #subcommand_name_var == #sub_name && !#sub_arg_matches_var.contains_id("") { + return ::std::result::Result::Ok(Self :: #variant_name #constructor_block) } } }); @@ -510,7 +524,7 @@ fn gen_from_arg_matches( .unwrap_or_default() { let __clap_res = <#ty as clap::FromArgMatches>::from_arg_matches_mut(__clap_arg_matches)?; - return ::std::result::Result::Ok(#name :: #variant_name (__clap_res)); + return ::std::result::Result::Ok(Self :: #variant_name (__clap_res)); } } } @@ -523,12 +537,12 @@ fn gen_from_arg_matches( let wildcard = match ext_subcmd { Some((span, var_name, str_ty)) => quote_spanned! { span=> - ::std::result::Result::Ok(#name::#var_name( + ::std::result::Result::Ok(Self::#var_name( ::std::iter::once(#str_ty::from(#subcommand_name_var)) .chain( #sub_arg_matches_var .remove_many::<#str_ty>("") - .into_iter().flatten() // `""` isn't present, bug in `unstable-v4` + .unwrap() .map(#str_ty::from) ) .collect::<::std::vec::Vec<_>>() @@ -536,7 +550,7 @@ fn gen_from_arg_matches( }, None => quote! { - ::std::result::Result::Err(clap::Error::raw(clap::ErrorKind::UnrecognizedSubcommand, format!("The subcommand '{}' wasn't recognized", #subcommand_name_var))) + ::std::result::Result::Err(clap::Error::raw(clap::error::ErrorKind::InvalidSubcommand, format!("The subcommand '{}' wasn't recognized", #subcommand_name_var))) }, }; @@ -553,61 +567,52 @@ fn gen_from_arg_matches( #wildcard } else { - ::std::result::Result::Err(clap::Error::raw(clap::ErrorKind::MissingSubcommand, "A subcommand is required but one was not provided.")) + ::std::result::Result::Err(clap::Error::raw(clap::error::ErrorKind::MissingSubcommand, "A subcommand is required but one was not provided.")) } } } } -fn gen_update_from_arg_matches( - name: &Ident, - variants: &Punctuated<Variant, Token![,]>, - parent_attribute: &Attrs, -) -> TokenStream { +fn gen_update_from_arg_matches(variants: &[(&Variant, Item)]) -> TokenStream { use syn::Fields::*; let (flatten, variants): (Vec<_>, Vec<_>) = variants .iter() - .filter_map(|variant| { - let attrs = Attrs::from_variant( - variant, - parent_attribute.casing(), - parent_attribute.env_casing(), - ); - - match &*attrs.kind() { + .filter_map(|(variant, item)| { + let kind = item.kind(); + match &*kind { // Fallback to `from_arg_matches_mut` - Kind::ExternalSubcommand => None, - _ => Some((variant, attrs)), + Kind::Skip(_, _) + | Kind::Arg(_) + | Kind::FromGlobal(_) + | Kind::Value + | Kind::ExternalSubcommand => None, + Kind::Flatten(_) | Kind::Subcommand(_) | Kind::Command(_) => Some((variant, item)), } }) - .partition(|(_, attrs)| { - let kind = attrs.kind(); - matches!(&*kind, Kind::Flatten) + .partition(|(_, item)| { + let kind = item.kind(); + matches!(&*kind, Kind::Flatten(_)) }); - let subcommands = variants.iter().map(|(variant, attrs)| { - let sub_name = attrs.cased_name(); + let subcommands = variants.iter().map(|(variant, item)| { + let sub_name = item.cased_name(); let variant_name = &variant.ident; let (pattern, updater) = match variant.fields { Named(ref fields) => { - let (fields, update): (Vec<_>, Vec<_>) = fields + let field_names = fields.named.iter().map(|field| { + field.ident.as_ref().unwrap() + }).collect::<Vec<_>>(); + let fields = fields .named .iter() .map(|field| { - let attrs = Attrs::from_field( - field, - parent_attribute.casing(), - parent_attribute.env_casing(), - ); - let field_name = field.ident.as_ref().unwrap(); - ( - quote!( ref mut #field_name ), - args::gen_updater(&fields.named, &attrs, false), - ) + let item = Item::from_args_field(field, item.casing(), item.env_casing()); + (field, item) }) - .unzip(); - (quote!( { #( #fields, )* }), quote!( { #( #update )* } )) + .collect::<Vec<_>>(); + let update = args::gen_updater(&fields, false); + (quote!( { #( #field_names, )* }), quote!( { #update } )) } Unit => (quote!(), quote!({})), Unnamed(ref fields) => { @@ -626,7 +631,7 @@ fn gen_update_from_arg_matches( }; quote! { - #name :: #variant_name #pattern if #sub_name == __clap_name => { + Self :: #variant_name #pattern if #sub_name == __clap_name => { let (_, mut __clap_arg_sub_matches) = __clap_arg_matches.remove_subcommand().unwrap(); let __clap_arg_matches = &mut __clap_arg_sub_matches; #updater @@ -641,7 +646,7 @@ fn gen_update_from_arg_matches( let ty = &fields.unnamed[0]; quote! { if <#ty as clap::Subcommand>::has_subcommand(__clap_name) { - if let #name :: #variant_name (child) = s { + if let Self :: #variant_name (child) = s { <#ty as clap::FromArgMatches>::update_from_arg_matches_mut(child, __clap_arg_matches)?; return ::std::result::Result::Ok(()); } diff --git a/vendor/clap_derive/src/derives/value_enum.rs b/vendor/clap_derive/src/derives/value_enum.rs index 06d514f0e..a1411d02a 100644 --- a/vendor/clap_derive/src/derives/value_enum.rs +++ b/vendor/clap_derive/src/derives/value_enum.rs @@ -8,20 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use crate::{ - attrs::{Attrs, Kind, Name, DEFAULT_CASING, DEFAULT_ENV_CASING}, - dummies, - utils::Sp, -}; - -use proc_macro2::{Span, TokenStream}; +use proc_macro2::TokenStream; use proc_macro_error::{abort, abort_call_site}; use quote::quote; use quote::quote_spanned; -use syn::{ - punctuated::Punctuated, spanned::Spanned, token::Comma, Attribute, Data, DataEnum, DeriveInput, - Fields, Ident, Variant, -}; +use syn::{spanned::Spanned, Data, DeriveInput, Fields, Ident, Variant}; + +use crate::dummies; +use crate::item::{Item, Kind, Name}; pub fn derive_value_enum(input: &DeriveInput) -> TokenStream { let ident = &input.ident; @@ -29,23 +23,35 @@ pub fn derive_value_enum(input: &DeriveInput) -> TokenStream { dummies::value_enum(ident); match input.data { - Data::Enum(ref e) => gen_for_enum(ident, &input.attrs, e), + Data::Enum(ref e) => { + let name = Name::Derived(ident.clone()); + let item = Item::from_value_enum(input, name); + let variants = e + .variants + .iter() + .map(|variant| { + let item = + Item::from_value_enum_variant(variant, item.casing(), item.env_casing()); + (variant, item) + }) + .collect::<Vec<_>>(); + gen_for_enum(&item, ident, &variants) + } _ => abort_call_site!("`#[derive(ValueEnum)]` only supports enums"), } } -pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStream { - let attrs = Attrs::from_struct( - Span::call_site(), - attrs, - Name::Derived(name.clone()), - Sp::call_site(DEFAULT_CASING), - Sp::call_site(DEFAULT_ENV_CASING), - ); +pub fn gen_for_enum(item: &Item, item_name: &Ident, variants: &[(&Variant, Item)]) -> TokenStream { + if !matches!(&*item.kind(), Kind::Value) { + abort! { item.kind().span(), + "`{}` cannot be used with `value`", + item.kind().name(), + } + } - let lits = lits(&e.variants, &attrs); + let lits = lits(variants); let value_variants = gen_value_variants(&lits); - let to_possible_value = gen_to_possible_value(&lits); + let to_possible_value = gen_to_possible_value(item, &lits); quote! { #[allow(dead_code, unreachable_code, unused_variables, unused_braces)] @@ -61,38 +67,32 @@ pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStr clippy::suspicious_else_formatting, )] #[deny(clippy::correctness)] - impl clap::ValueEnum for #name { + impl clap::ValueEnum for #item_name { #value_variants #to_possible_value } } } -fn lits( - variants: &Punctuated<Variant, Comma>, - parent_attribute: &Attrs, -) -> Vec<(TokenStream, Ident)> { +fn lits(variants: &[(&Variant, Item)]) -> Vec<(TokenStream, Ident)> { variants .iter() - .filter_map(|variant| { - let attrs = Attrs::from_value_enum_variant( - variant, - parent_attribute.casing(), - parent_attribute.env_casing(), - ); - if let Kind::Skip(_) = &*attrs.kind() { + .filter_map(|(variant, item)| { + if let Kind::Skip(_, _) = &*item.kind() { None } else { if !matches!(variant.fields, Fields::Unit) { abort!(variant.span(), "`#[derive(ValueEnum)]` only supports unit variants. Non-unit variants must be skipped"); } - let fields = attrs.field_methods(false); - let name = attrs.cased_name(); + let fields = item.field_methods(); + let deprecations = item.deprecations(); + let name = item.cased_name(); Some(( - quote_spanned! { variant.span()=> - clap::PossibleValue::new(#name) + quote_spanned! { variant.span()=> { + #deprecations + clap::builder::PossibleValue::new(#name) #fields - }, + }}, variant.ident.clone(), )) } @@ -110,11 +110,14 @@ fn gen_value_variants(lits: &[(TokenStream, Ident)]) -> TokenStream { } } -fn gen_to_possible_value(lits: &[(TokenStream, Ident)]) -> TokenStream { +fn gen_to_possible_value(item: &Item, lits: &[(TokenStream, Ident)]) -> TokenStream { let (lit, variant): (Vec<TokenStream>, Vec<Ident>) = lits.iter().cloned().unzip(); + let deprecations = item.deprecations(); + quote! { - fn to_possible_value<'a>(&self) -> ::std::option::Option<clap::PossibleValue<'a>> { + fn to_possible_value<'a>(&self) -> ::std::option::Option<clap::builder::PossibleValue> { + #deprecations match self { #(Self::#variant => Some(#lit),)* _ => None |