mirror of
https://github.com/clap-rs/clap
synced 2025-03-04 23:37:32 +00:00
Merge pull request #2595 from epage/move
refactor: Move code to future trait locations
This commit is contained in:
commit
fbcf079e78
5 changed files with 378 additions and 380 deletions
|
@ -21,7 +21,7 @@ use crate::{
|
|||
utils::{sub_type, subty_if_name, Sp, Ty},
|
||||
};
|
||||
|
||||
pub fn gen_for_struct(
|
||||
pub fn gen_from_arg_matches_for_struct(
|
||||
struct_name: &Ident,
|
||||
fields: &Punctuated<Field, Comma>,
|
||||
parent_attribute: &Attrs,
|
||||
|
@ -54,36 +54,342 @@ pub fn gen_for_struct(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn gen_for_enum(name: &Ident) -> TokenStream {
|
||||
quote! {
|
||||
#[allow(dead_code, unreachable_code, unused_variables)]
|
||||
#[allow(
|
||||
clippy::style,
|
||||
clippy::complexity,
|
||||
clippy::pedantic,
|
||||
clippy::restriction,
|
||||
clippy::perf,
|
||||
clippy::deprecated,
|
||||
clippy::nursery,
|
||||
clippy::cargo
|
||||
)]
|
||||
#[deny(clippy::correctness)]
|
||||
impl clap::FromArgMatches for #name {
|
||||
fn from_arg_matches(arg_matches: &clap::ArgMatches) -> Self {
|
||||
<#name as clap::Subcommand>::from_subcommand(arg_matches.subcommand()).unwrap()
|
||||
/// Generate a block of code to add arguments/subcommands corresponding to
|
||||
/// the `fields` to an app.
|
||||
pub fn gen_augment(
|
||||
fields: &Punctuated<Field, Comma>,
|
||||
app_var: &Ident,
|
||||
parent_attribute: &Attrs,
|
||||
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()=>
|
||||
let #app_var = #app_var.setting(
|
||||
clap::AppSettings::SubcommandRequiredElseHelp
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
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 #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 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;
|
||||
Some(quote_spanned! { kind.span()=>
|
||||
let #app_var = <#ty as clap::IntoApp>::augment_clap(#app_var);
|
||||
})
|
||||
}
|
||||
fn update_from_arg_matches(&mut self, arg_matches: &clap::ArgMatches) {
|
||||
<#name as clap::Subcommand>::update_from_subcommand(self, arg_matches.subcommand());
|
||||
Kind::Arg(ty) => {
|
||||
let convert_type = match **ty {
|
||||
Ty::Vec | Ty::Option => sub_type(&field.ty).unwrap_or(&field.ty),
|
||||
Ty::OptionOption | Ty::OptionVec => {
|
||||
sub_type(&field.ty).and_then(sub_type).unwrap_or(&field.ty)
|
||||
}
|
||||
_ => &field.ty,
|
||||
};
|
||||
|
||||
let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
|
||||
let flag = *attrs.parser().kind == ParserKind::FromFlag;
|
||||
|
||||
let parser = attrs.parser();
|
||||
let func = &parser.func;
|
||||
|
||||
let validator = match *parser.kind {
|
||||
_ if 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| ()))
|
||||
},
|
||||
_ => quote!(),
|
||||
};
|
||||
|
||||
let modifier = match **ty {
|
||||
Ty::Bool => quote!(),
|
||||
|
||||
Ty::Option => {
|
||||
let mut possible_values = quote!();
|
||||
|
||||
if attrs.is_enum() {
|
||||
if let Some(subty) = subty_if_name(&field.ty, "Option") {
|
||||
possible_values = gen_arg_enum_possible_values(subty);
|
||||
}
|
||||
};
|
||||
|
||||
quote_spanned! { ty.span()=>
|
||||
.takes_value(true)
|
||||
#possible_values
|
||||
#validator
|
||||
}
|
||||
}
|
||||
|
||||
Ty::OptionOption => quote_spanned! { ty.span()=>
|
||||
.takes_value(true)
|
||||
.multiple_values(false)
|
||||
.min_values(0)
|
||||
.max_values(1)
|
||||
#validator
|
||||
},
|
||||
|
||||
Ty::OptionVec => quote_spanned! { ty.span()=>
|
||||
.takes_value(true)
|
||||
.multiple_values(true)
|
||||
.min_values(0)
|
||||
#validator
|
||||
},
|
||||
|
||||
Ty::Vec => {
|
||||
let mut possible_values = quote!();
|
||||
|
||||
if attrs.is_enum() {
|
||||
if let Some(subty) = subty_if_name(&field.ty, "Vec") {
|
||||
possible_values = gen_arg_enum_possible_values(subty);
|
||||
}
|
||||
};
|
||||
|
||||
quote_spanned! { ty.span()=>
|
||||
.takes_value(true)
|
||||
.multiple_values(true)
|
||||
#possible_values
|
||||
#validator
|
||||
}
|
||||
}
|
||||
|
||||
Ty::Other if occurrences => quote_spanned! { ty.span()=>
|
||||
.multiple_occurrences(true)
|
||||
},
|
||||
|
||||
Ty::Other if flag => quote_spanned! { ty.span()=>
|
||||
.takes_value(false)
|
||||
.multiple_values(false)
|
||||
},
|
||||
|
||||
Ty::Other => {
|
||||
let required = !attrs.has_method("default_value") && !override_required;
|
||||
let mut possible_values = quote!();
|
||||
|
||||
if attrs.is_enum() {
|
||||
possible_values = gen_arg_enum_possible_values(&field.ty);
|
||||
};
|
||||
|
||||
quote_spanned! { ty.span()=>
|
||||
.takes_value(true)
|
||||
.required(#required)
|
||||
#possible_values
|
||||
#validator
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let name = attrs.cased_name();
|
||||
let methods = attrs.field_methods();
|
||||
|
||||
Some(quote_spanned! { field.span()=>
|
||||
let #app_var = #app_var.arg(
|
||||
clap::Arg::new(#name)
|
||||
#modifier
|
||||
#methods
|
||||
);
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let app_methods = parent_attribute.top_level_methods();
|
||||
let version = parent_attribute.version();
|
||||
quote! {{
|
||||
let #app_var = #app_var#app_methods;
|
||||
#( #args )*
|
||||
#subcmd
|
||||
#app_var#version
|
||||
}}
|
||||
}
|
||||
|
||||
fn gen_arg_enum_possible_values(ty: &Type) -> TokenStream {
|
||||
quote_spanned! { ty.span()=>
|
||||
.possible_values(&<#ty as clap::ArgEnum>::VARIANTS)
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_arg_enum_parse(ty: &Type, attrs: &Attrs) -> TokenStream {
|
||||
let ci = attrs.case_insensitive();
|
||||
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(),
|
||||
);
|
||||
let field_name = field.ident.as_ref().unwrap();
|
||||
let kind = attrs.kind();
|
||||
let arg_matches = quote! { arg_matches };
|
||||
match &*kind {
|
||||
Kind::ExternalSubcommand => {
|
||||
abort! { kind.span(),
|
||||
"`external_subcommand` can be used only on enum variants"
|
||||
}
|
||||
}
|
||||
Kind::Subcommand(ty) => {
|
||||
let subcmd_type = match (**ty, sub_type(&field.ty)) {
|
||||
(Ty::Option, Some(sub_type)) => sub_type,
|
||||
_ => &field.ty,
|
||||
};
|
||||
let unwrapper = match **ty {
|
||||
Ty::Option => quote!(),
|
||||
_ => quote_spanned!( ty.span()=> .unwrap() ),
|
||||
};
|
||||
quote_spanned! { kind.span()=>
|
||||
#field_name: {
|
||||
<#subcmd_type as clap::Subcommand>::from_subcommand(#arg_matches.subcommand())
|
||||
#unwrapper
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
quote_spanned! { ty.span()=>
|
||||
|s| <#ty as clap::ArgEnum>::from_str(s, #ci).unwrap()
|
||||
Kind::Flatten => quote_spanned! { kind.span()=>
|
||||
#field_name: clap::FromArgMatches::from_arg_matches(#arg_matches)
|
||||
},
|
||||
|
||||
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),
|
||||
}
|
||||
});
|
||||
|
||||
quote! {{
|
||||
#( #fields ),*
|
||||
}}
|
||||
}
|
||||
|
||||
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(),
|
||||
);
|
||||
let field_name = field.ident.as_ref().unwrap();
|
||||
let kind = attrs.kind();
|
||||
|
||||
let access = if use_self {
|
||||
quote! {
|
||||
#[allow(non_snake_case)]
|
||||
let #field_name = &mut self.#field_name;
|
||||
}
|
||||
} else {
|
||||
quote!()
|
||||
};
|
||||
let arg_matches = quote! { arg_matches };
|
||||
|
||||
match &*kind {
|
||||
Kind::ExternalSubcommand => {
|
||||
abort! { kind.span(),
|
||||
"`external_subcommand` can be used only on enum variants"
|
||||
}
|
||||
}
|
||||
Kind::Subcommand(ty) => {
|
||||
let subcmd_type = match (**ty, sub_type(&field.ty)) {
|
||||
(Ty::Option, Some(sub_type)) => sub_type,
|
||||
_ => &field.ty,
|
||||
};
|
||||
|
||||
let updater = quote_spanned! { ty.span()=>
|
||||
<#subcmd_type as clap::Subcommand>::update_from_subcommand(#field_name, #arg_matches.subcommand());
|
||||
};
|
||||
|
||||
let updater = match **ty {
|
||||
Ty::Option => quote_spanned! { kind.span()=>
|
||||
if let Some(#field_name) = #field_name.as_mut() {
|
||||
#updater
|
||||
} else {
|
||||
*#field_name = <#subcmd_type as clap::Subcommand>::from_subcommand(
|
||||
#arg_matches.subcommand()
|
||||
)
|
||||
}
|
||||
},
|
||||
_ => quote_spanned! { kind.span()=>
|
||||
#updater
|
||||
},
|
||||
};
|
||||
|
||||
quote_spanned! { kind.span()=>
|
||||
{
|
||||
#access
|
||||
#updater
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Kind::Flatten => quote_spanned! { kind.span()=> {
|
||||
#access
|
||||
clap::FromArgMatches::update_from_arg_matches(#field_name, #arg_matches);
|
||||
}
|
||||
},
|
||||
|
||||
Kind::Skip(_) => quote!(),
|
||||
|
||||
Kind::Arg(ty) | Kind::FromGlobal(ty) => gen_parsers(&attrs, ty, field_name, field, Some(&access)),
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
#( #fields )*
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,133 +533,10 @@ fn gen_parsers(
|
|||
}
|
||||
}
|
||||
|
||||
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(),
|
||||
);
|
||||
let field_name = field.ident.as_ref().unwrap();
|
||||
let kind = attrs.kind();
|
||||
let arg_matches = quote! { arg_matches };
|
||||
match &*kind {
|
||||
Kind::ExternalSubcommand => {
|
||||
abort! { kind.span(),
|
||||
"`external_subcommand` can be used only on enum variants"
|
||||
}
|
||||
}
|
||||
Kind::Subcommand(ty) => {
|
||||
let subcmd_type = match (**ty, sub_type(&field.ty)) {
|
||||
(Ty::Option, Some(sub_type)) => sub_type,
|
||||
_ => &field.ty,
|
||||
};
|
||||
let unwrapper = match **ty {
|
||||
Ty::Option => quote!(),
|
||||
_ => quote_spanned!( ty.span()=> .unwrap() ),
|
||||
};
|
||||
quote_spanned! { kind.span()=>
|
||||
#field_name: {
|
||||
<#subcmd_type as clap::Subcommand>::from_subcommand(#arg_matches.subcommand())
|
||||
#unwrapper
|
||||
}
|
||||
}
|
||||
}
|
||||
fn gen_arg_enum_parse(ty: &Type, attrs: &Attrs) -> TokenStream {
|
||||
let ci = attrs.case_insensitive();
|
||||
|
||||
Kind::Flatten => quote_spanned! { kind.span()=>
|
||||
#field_name: clap::FromArgMatches::from_arg_matches(#arg_matches)
|
||||
},
|
||||
|
||||
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),
|
||||
}
|
||||
});
|
||||
|
||||
quote! {{
|
||||
#( #fields ),*
|
||||
}}
|
||||
}
|
||||
|
||||
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(),
|
||||
);
|
||||
let field_name = field.ident.as_ref().unwrap();
|
||||
let kind = attrs.kind();
|
||||
|
||||
let access = if use_self {
|
||||
quote! {
|
||||
#[allow(non_snake_case)]
|
||||
let #field_name = &mut self.#field_name;
|
||||
}
|
||||
} else {
|
||||
quote!()
|
||||
};
|
||||
let arg_matches = quote! { arg_matches };
|
||||
|
||||
match &*kind {
|
||||
Kind::ExternalSubcommand => {
|
||||
abort! { kind.span(),
|
||||
"`external_subcommand` can be used only on enum variants"
|
||||
}
|
||||
}
|
||||
Kind::Subcommand(ty) => {
|
||||
let subcmd_type = match (**ty, sub_type(&field.ty)) {
|
||||
(Ty::Option, Some(sub_type)) => sub_type,
|
||||
_ => &field.ty,
|
||||
};
|
||||
|
||||
let updater = quote_spanned! { ty.span()=>
|
||||
<#subcmd_type as clap::Subcommand>::update_from_subcommand(#field_name, #arg_matches.subcommand());
|
||||
};
|
||||
|
||||
let updater = match **ty {
|
||||
Ty::Option => quote_spanned! { kind.span()=>
|
||||
if let Some(#field_name) = #field_name.as_mut() {
|
||||
#updater
|
||||
} else {
|
||||
*#field_name = <#subcmd_type as clap::Subcommand>::from_subcommand(
|
||||
#arg_matches.subcommand()
|
||||
)
|
||||
}
|
||||
},
|
||||
_ => quote_spanned! { kind.span()=>
|
||||
#updater
|
||||
},
|
||||
};
|
||||
|
||||
quote_spanned! { kind.span()=>
|
||||
{
|
||||
#access
|
||||
#updater
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Kind::Flatten => quote_spanned! { kind.span()=> {
|
||||
#access
|
||||
clap::FromArgMatches::update_from_arg_matches(#field_name, #arg_matches);
|
||||
}
|
||||
},
|
||||
|
||||
Kind::Skip(_) => quote!(),
|
||||
|
||||
Kind::Arg(ty) | Kind::FromGlobal(ty) => gen_parsers(&attrs, ty, field_name, field, Some(&access)),
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
#( #fields )*
|
||||
quote_spanned! { ty.span()=>
|
||||
|s| <#ty as clap::ArgEnum>::from_str(s, #ci).unwrap()
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
// MIT/Apache 2.0 license.
|
||||
|
||||
use crate::{
|
||||
derives::{from_arg_matches, into_app, subcommand},
|
||||
derives::{args, into_app, subcommand},
|
||||
dummies,
|
||||
};
|
||||
|
||||
|
@ -57,7 +57,7 @@ fn gen_for_struct(
|
|||
attrs: &[Attribute],
|
||||
) -> TokenStream {
|
||||
let (into_app, attrs) = into_app::gen_for_struct(name, fields, attrs);
|
||||
let from_arg_matches = from_arg_matches::gen_for_struct(name, fields, &attrs);
|
||||
let from_arg_matches = args::gen_from_arg_matches_for_struct(name, fields, &attrs);
|
||||
|
||||
quote! {
|
||||
impl clap::Clap for #name {}
|
||||
|
@ -69,7 +69,7 @@ fn gen_for_struct(
|
|||
|
||||
fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStream {
|
||||
let into_app = into_app::gen_for_enum(name, attrs);
|
||||
let from_arg_matches = from_arg_matches::gen_for_enum(name);
|
||||
let from_arg_matches = subcommand::gen_from_arg_matches_for_enum(name);
|
||||
let subcommand = subcommand::gen_for_enum(name, attrs, e);
|
||||
|
||||
quote! {
|
||||
|
|
|
@ -15,17 +15,18 @@
|
|||
use std::env;
|
||||
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use proc_macro_error::{abort, abort_call_site};
|
||||
use quote::{quote, quote_spanned};
|
||||
use proc_macro_error::abort_call_site;
|
||||
use quote::quote;
|
||||
use syn::{
|
||||
punctuated::Punctuated, spanned::Spanned, token::Comma, Attribute, Data, DataStruct,
|
||||
DeriveInput, Field, Fields, Ident, Type,
|
||||
punctuated::Punctuated, token::Comma, Attribute, Data, DataStruct, DeriveInput, Field, Fields,
|
||||
Ident,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
attrs::{Attrs, GenOutput, Kind, Name, ParserKind, DEFAULT_CASING, DEFAULT_ENV_CASING},
|
||||
attrs::{Attrs, GenOutput, Name, DEFAULT_CASING, DEFAULT_ENV_CASING},
|
||||
derives::args,
|
||||
dummies,
|
||||
utils::{sub_type, subty_if_name, Sp, Ty},
|
||||
utils::Sp,
|
||||
};
|
||||
|
||||
pub fn derive_into_app(input: &DeriveInput) -> TokenStream {
|
||||
|
@ -151,8 +152,8 @@ fn gen_into_app_fn(attrs: &[Attribute]) -> GenOutput {
|
|||
|
||||
fn gen_augment_clap_fn(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs) -> TokenStream {
|
||||
let app_var = Ident::new("app", Span::call_site());
|
||||
let augmentation = gen_app_augmentation(fields, &app_var, parent_attribute, false);
|
||||
let augmentation_update = gen_app_augmentation(fields, &app_var, parent_attribute, true);
|
||||
let augmentation = args::gen_augment(fields, &app_var, parent_attribute, false);
|
||||
let augmentation_update = args::gen_augment(fields, &app_var, parent_attribute, true);
|
||||
quote! {
|
||||
fn augment_clap<'b>(#app_var: clap::App<'b>) -> clap::App<'b> {
|
||||
#augmentation
|
||||
|
@ -162,211 +163,3 @@ fn gen_augment_clap_fn(fields: &Punctuated<Field, Comma>, parent_attribute: &Att
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_arg_enum_possible_values(ty: &Type) -> TokenStream {
|
||||
quote_spanned! { ty.span()=>
|
||||
.possible_values(&<#ty as clap::ArgEnum>::VARIANTS)
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a block of code to add arguments/subcommands corresponding to
|
||||
/// the `fields` to an app.
|
||||
pub fn gen_app_augmentation(
|
||||
fields: &Punctuated<Field, Comma>,
|
||||
app_var: &Ident,
|
||||
parent_attribute: &Attrs,
|
||||
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()=>
|
||||
let #app_var = #app_var.setting(
|
||||
clap::AppSettings::SubcommandRequiredElseHelp
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
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 #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 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;
|
||||
Some(quote_spanned! { kind.span()=>
|
||||
let #app_var = <#ty as clap::IntoApp>::augment_clap(#app_var);
|
||||
})
|
||||
}
|
||||
Kind::Arg(ty) => {
|
||||
let convert_type = match **ty {
|
||||
Ty::Vec | Ty::Option => sub_type(&field.ty).unwrap_or(&field.ty),
|
||||
Ty::OptionOption | Ty::OptionVec => {
|
||||
sub_type(&field.ty).and_then(sub_type).unwrap_or(&field.ty)
|
||||
}
|
||||
_ => &field.ty,
|
||||
};
|
||||
|
||||
let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
|
||||
let flag = *attrs.parser().kind == ParserKind::FromFlag;
|
||||
|
||||
let parser = attrs.parser();
|
||||
let func = &parser.func;
|
||||
|
||||
let validator = match *parser.kind {
|
||||
_ if 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| ()))
|
||||
},
|
||||
_ => quote!(),
|
||||
};
|
||||
|
||||
let modifier = match **ty {
|
||||
Ty::Bool => quote!(),
|
||||
|
||||
Ty::Option => {
|
||||
let mut possible_values = quote!();
|
||||
|
||||
if attrs.is_enum() {
|
||||
if let Some(subty) = subty_if_name(&field.ty, "Option") {
|
||||
possible_values = gen_arg_enum_possible_values(subty);
|
||||
}
|
||||
};
|
||||
|
||||
quote_spanned! { ty.span()=>
|
||||
.takes_value(true)
|
||||
#possible_values
|
||||
#validator
|
||||
}
|
||||
}
|
||||
|
||||
Ty::OptionOption => quote_spanned! { ty.span()=>
|
||||
.takes_value(true)
|
||||
.multiple_values(false)
|
||||
.min_values(0)
|
||||
.max_values(1)
|
||||
#validator
|
||||
},
|
||||
|
||||
Ty::OptionVec => quote_spanned! { ty.span()=>
|
||||
.takes_value(true)
|
||||
.multiple_values(true)
|
||||
.min_values(0)
|
||||
#validator
|
||||
},
|
||||
|
||||
Ty::Vec => {
|
||||
let mut possible_values = quote!();
|
||||
|
||||
if attrs.is_enum() {
|
||||
if let Some(subty) = subty_if_name(&field.ty, "Vec") {
|
||||
possible_values = gen_arg_enum_possible_values(subty);
|
||||
}
|
||||
};
|
||||
|
||||
quote_spanned! { ty.span()=>
|
||||
.takes_value(true)
|
||||
.multiple_values(true)
|
||||
#possible_values
|
||||
#validator
|
||||
}
|
||||
}
|
||||
|
||||
Ty::Other if occurrences => quote_spanned! { ty.span()=>
|
||||
.multiple_occurrences(true)
|
||||
},
|
||||
|
||||
Ty::Other if flag => quote_spanned! { ty.span()=>
|
||||
.takes_value(false)
|
||||
.multiple_values(false)
|
||||
},
|
||||
|
||||
Ty::Other => {
|
||||
let required = !attrs.has_method("default_value") && !override_required;
|
||||
let mut possible_values = quote!();
|
||||
|
||||
if attrs.is_enum() {
|
||||
possible_values = gen_arg_enum_possible_values(&field.ty);
|
||||
};
|
||||
|
||||
quote_spanned! { ty.span()=>
|
||||
.takes_value(true)
|
||||
.required(#required)
|
||||
#possible_values
|
||||
#validator
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let name = attrs.cased_name();
|
||||
let methods = attrs.field_methods();
|
||||
|
||||
Some(quote_spanned! { field.span()=>
|
||||
let #app_var = #app_var.arg(
|
||||
clap::Arg::new(#name)
|
||||
#modifier
|
||||
#methods
|
||||
);
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let app_methods = parent_attribute.top_level_methods();
|
||||
let version = parent_attribute.version();
|
||||
quote! {{
|
||||
let #app_var = #app_var#app_methods;
|
||||
#( #args )*
|
||||
#subcmd
|
||||
#app_var#version
|
||||
}}
|
||||
}
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
|
||||
// MIT/Apache 2.0 license.
|
||||
mod arg_enum;
|
||||
mod args;
|
||||
mod clap;
|
||||
mod from_arg_matches;
|
||||
mod into_app;
|
||||
mod subcommand;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
attrs::{Attrs, Kind, Name, DEFAULT_CASING, DEFAULT_ENV_CASING},
|
||||
derives::{from_arg_matches, into_app},
|
||||
derives::args,
|
||||
dummies,
|
||||
utils::{is_simple_ty, subty_if_name, Sp},
|
||||
};
|
||||
|
@ -61,6 +61,31 @@ pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStr
|
|||
}
|
||||
}
|
||||
|
||||
pub fn gen_from_arg_matches_for_enum(name: &Ident) -> TokenStream {
|
||||
quote! {
|
||||
#[allow(dead_code, unreachable_code, unused_variables)]
|
||||
#[allow(
|
||||
clippy::style,
|
||||
clippy::complexity,
|
||||
clippy::pedantic,
|
||||
clippy::restriction,
|
||||
clippy::perf,
|
||||
clippy::deprecated,
|
||||
clippy::nursery,
|
||||
clippy::cargo
|
||||
)]
|
||||
#[deny(clippy::correctness)]
|
||||
impl clap::FromArgMatches for #name {
|
||||
fn from_arg_matches(arg_matches: &clap::ArgMatches) -> Self {
|
||||
<#name as clap::Subcommand>::from_subcommand(arg_matches.subcommand()).unwrap()
|
||||
}
|
||||
fn update_from_arg_matches(&mut self, arg_matches: &clap::ArgMatches) {
|
||||
<#name as clap::Subcommand>::update_from_subcommand(self, arg_matches.subcommand());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_augment(
|
||||
fn_name: &str,
|
||||
variants: &Punctuated<Variant, Token![,]>,
|
||||
|
@ -104,12 +129,9 @@ fn gen_augment(
|
|||
_ => {
|
||||
let app_var = Ident::new("subcommand", Span::call_site());
|
||||
let arg_block = match variant.fields {
|
||||
Named(ref fields) => into_app::gen_app_augmentation(
|
||||
&fields.named,
|
||||
&app_var,
|
||||
&attrs,
|
||||
override_required,
|
||||
),
|
||||
Named(ref fields) => {
|
||||
args::gen_augment(&fields.named, &app_var, &attrs, override_required)
|
||||
}
|
||||
Unit => quote!( #app_var ),
|
||||
Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
|
||||
let ty = &unnamed[0];
|
||||
|
@ -236,7 +258,7 @@ fn gen_from_subcommand(
|
|||
let sub_name = attrs.cased_name();
|
||||
let variant_name = &variant.ident;
|
||||
let constructor_block = match variant.fields {
|
||||
Named(ref fields) => from_arg_matches::gen_constructor(&fields.named, attrs),
|
||||
Named(ref fields) => args::gen_constructor(&fields.named, attrs),
|
||||
Unit => quote!(),
|
||||
Unnamed(ref fields) if fields.unnamed.len() == 1 => {
|
||||
let ty = &fields.unnamed[0];
|
||||
|
@ -349,7 +371,7 @@ fn gen_update_from_subcommand(
|
|||
let field_name = field.ident.as_ref().unwrap();
|
||||
(
|
||||
quote!( ref mut #field_name ),
|
||||
from_arg_matches::gen_updater(&fields.named, &attrs, false),
|
||||
args::gen_updater(&fields.named, &attrs, false),
|
||||
)
|
||||
})
|
||||
.unzip();
|
||||
|
|
Loading…
Add table
Reference in a new issue