mirror of
https://github.com/clap-rs/clap
synced 2024-12-14 14:52:33 +00:00
Merge pull request #4179 from epage/attr
refactor(derive): Prepare for builder attributes
This commit is contained in:
commit
20ba828f21
13 changed files with 360 additions and 121 deletions
|
@ -55,7 +55,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
- *(derive)* Changed the default for arguments from `parse` to `value_parser`., removing `parse` support
|
- *(derive)* Changed the default for arguments from `parse` to `value_parser`., removing `parse` support
|
||||||
- *(derive)* `subcommand_required(true).arg_required_else_help(true)` is set instead of `SubcommandRequiredElseHelp` (#3280)
|
- *(derive)* `subcommand_required(true).arg_required_else_help(true)` is set instead of `SubcommandRequiredElseHelp` (#3280)
|
||||||
- *(derive)* Remove `arg_enum` attribute in favor of `value_enum`
|
- *(derive)* Remove `arg_enum` attribute in favor of `value_enum`
|
||||||
- *(derive)* Remove `structopt()` attributes in favor of `clap()`
|
|
||||||
|
|
||||||
### Compatibility
|
### Compatibility
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ use proc_macro_error::abort;
|
||||||
use proc_macro_error::ResultExt;
|
use proc_macro_error::ResultExt;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
|
use syn::spanned::Spanned;
|
||||||
use syn::{
|
use syn::{
|
||||||
parenthesized,
|
parenthesized,
|
||||||
parse::{Parse, ParseStream},
|
parse::{Parse, ParseStream},
|
||||||
|
@ -12,8 +13,11 @@ use syn::{
|
||||||
Attribute, Expr, Ident, LitStr, Token,
|
Attribute, Expr, Ident, LitStr, Token,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::utils::Sp;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ClapAttr {
|
pub struct ClapAttr {
|
||||||
|
pub kind: Sp<AttrKind>,
|
||||||
pub name: Ident,
|
pub name: Ident,
|
||||||
pub magic: Option<MagicAttrName>,
|
pub magic: Option<MagicAttrName>,
|
||||||
pub value: Option<AttrValue>,
|
pub value: Option<AttrValue>,
|
||||||
|
@ -23,10 +27,24 @@ impl ClapAttr {
|
||||||
pub fn parse_all(all_attrs: &[Attribute]) -> Vec<Self> {
|
pub fn parse_all(all_attrs: &[Attribute]) -> Vec<Self> {
|
||||||
all_attrs
|
all_attrs
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|attr| attr.path.is_ident("clap"))
|
.filter_map(|attr| {
|
||||||
.flat_map(|attr| {
|
let kind = if attr.path.is_ident("clap") {
|
||||||
|
Some(Sp::new(AttrKind::Clap, attr.path.span()))
|
||||||
|
} else if attr.path.is_ident("structopt") {
|
||||||
|
Some(Sp::new(AttrKind::StructOpt, attr.path.span()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
kind.map(|k| (k, attr))
|
||||||
|
})
|
||||||
|
.flat_map(|(k, attr)| {
|
||||||
attr.parse_args_with(Punctuated::<ClapAttr, Token![,]>::parse_terminated)
|
attr.parse_args_with(Punctuated::<ClapAttr, Token![,]>::parse_terminated)
|
||||||
.unwrap_or_abort()
|
.unwrap_or_abort()
|
||||||
|
.into_iter()
|
||||||
|
.map(move |mut a| {
|
||||||
|
a.kind = k;
|
||||||
|
a
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
@ -113,7 +131,12 @@ impl Parse for ClapAttr {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self { name, magic, value })
|
Ok(Self {
|
||||||
|
kind: Sp::new(AttrKind::Clap, name.span()),
|
||||||
|
name,
|
||||||
|
magic,
|
||||||
|
value,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,3 +189,18 @@ impl ToTokens for AttrValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub enum AttrKind {
|
||||||
|
Clap,
|
||||||
|
StructOpt,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AttrKind {
|
||||||
|
pub fn as_str(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Clap => "clap",
|
||||||
|
Self::StructOpt => "structopt",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -72,6 +72,13 @@ pub fn gen_for_struct(
|
||||||
generics: &Generics,
|
generics: &Generics,
|
||||||
fields: &[(&Field, Item)],
|
fields: &[(&Field, Item)],
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
|
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();
|
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
||||||
|
|
||||||
let constructor = gen_constructor(fields);
|
let constructor = gen_constructor(fields);
|
||||||
|
@ -194,7 +201,9 @@ pub fn gen_augment(
|
||||||
let args = fields.iter().filter_map(|(field, item)| {
|
let args = fields.iter().filter_map(|(field, item)| {
|
||||||
let kind = item.kind();
|
let kind = item.kind();
|
||||||
match &*kind {
|
match &*kind {
|
||||||
Kind::Subcommand(_)
|
Kind::Command(_)
|
||||||
|
| Kind::Value(_)
|
||||||
|
| Kind::Subcommand(_)
|
||||||
| Kind::Skip(_)
|
| Kind::Skip(_)
|
||||||
| Kind::FromGlobal(_)
|
| Kind::FromGlobal(_)
|
||||||
| Kind::ExternalSubcommand => None,
|
| Kind::ExternalSubcommand => None,
|
||||||
|
@ -291,9 +300,16 @@ pub fn gen_augment(
|
||||||
|
|
||||||
let id = item.id();
|
let id = item.id();
|
||||||
let explicit_methods = item.field_methods(true);
|
let explicit_methods = item.field_methods(true);
|
||||||
|
let deprecations = if !override_required {
|
||||||
|
item.deprecations()
|
||||||
|
} else {
|
||||||
|
quote!()
|
||||||
|
};
|
||||||
|
|
||||||
Some(quote_spanned! { field.span()=>
|
Some(quote_spanned! { field.span()=>
|
||||||
let #app_var = #app_var.arg({
|
let #app_var = #app_var.arg({
|
||||||
|
#deprecations
|
||||||
|
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
let arg = clap::Arg::new(#id)
|
let arg = clap::Arg::new(#id)
|
||||||
#implicit_methods;
|
#implicit_methods;
|
||||||
|
@ -307,9 +323,15 @@ pub fn gen_augment(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let deprecations = if !override_required {
|
||||||
|
parent_item.deprecations()
|
||||||
|
} else {
|
||||||
|
quote!()
|
||||||
|
};
|
||||||
let initial_app_methods = parent_item.initial_top_level_methods();
|
let initial_app_methods = parent_item.initial_top_level_methods();
|
||||||
let final_app_methods = parent_item.final_top_level_methods();
|
let final_app_methods = parent_item.final_top_level_methods();
|
||||||
quote! {{
|
quote! {{
|
||||||
|
#deprecations
|
||||||
let #app_var = #app_var #initial_app_methods;
|
let #app_var = #app_var #initial_app_methods;
|
||||||
#( #args )*
|
#( #args )*
|
||||||
#subcmd
|
#subcmd
|
||||||
|
@ -323,9 +345,12 @@ pub fn gen_constructor(fields: &[(&Field, Item)]) -> TokenStream {
|
||||||
let kind = item.kind();
|
let kind = item.kind();
|
||||||
let arg_matches = format_ident!("__clap_arg_matches");
|
let arg_matches = format_ident!("__clap_arg_matches");
|
||||||
match &*kind {
|
match &*kind {
|
||||||
Kind::ExternalSubcommand => {
|
Kind::Command(_)
|
||||||
|
| Kind::Value(_)
|
||||||
|
| Kind::ExternalSubcommand => {
|
||||||
abort! { kind.span(),
|
abort! { kind.span(),
|
||||||
"`external_subcommand` can be used only on enum variants"
|
"`{}` cannot be used with `arg`",
|
||||||
|
kind.name(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Kind::Subcommand(ty) => {
|
Kind::Subcommand(ty) => {
|
||||||
|
@ -391,9 +416,12 @@ pub fn gen_updater(fields: &[(&Field, Item)], use_self: bool) -> TokenStream {
|
||||||
let arg_matches = format_ident!("__clap_arg_matches");
|
let arg_matches = format_ident!("__clap_arg_matches");
|
||||||
|
|
||||||
match &*kind {
|
match &*kind {
|
||||||
Kind::ExternalSubcommand => {
|
Kind::Command(_)
|
||||||
|
| Kind::Value(_)
|
||||||
|
| Kind::ExternalSubcommand => {
|
||||||
abort! { kind.span(),
|
abort! { kind.span(),
|
||||||
"`external_subcommand` can be used only on enum variants"
|
"`{}` cannot be used with `arg`",
|
||||||
|
kind.name(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Kind::Subcommand(ty) => {
|
Kind::Subcommand(ty) => {
|
||||||
|
|
|
@ -52,6 +52,13 @@ pub fn gen_for_enum(
|
||||||
generics: &Generics,
|
generics: &Generics,
|
||||||
variants: &[(&Variant, Item)],
|
variants: &[(&Variant, Item)],
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
|
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();
|
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
||||||
|
|
||||||
let from_arg_matches = gen_from_arg_matches(variants);
|
let from_arg_matches = gen_from_arg_matches(variants);
|
||||||
|
@ -143,9 +150,15 @@ fn gen_augment(
|
||||||
or `Vec<OsString>`."
|
or `Vec<OsString>`."
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
let deprecations = if !override_required {
|
||||||
|
item.deprecations()
|
||||||
|
} else {
|
||||||
|
quote!()
|
||||||
|
};
|
||||||
let subcommand = match subty_if_name(ty, "Vec") {
|
let subcommand = match subty_if_name(ty, "Vec") {
|
||||||
Some(subty) => {
|
Some(subty) => {
|
||||||
quote_spanned! { kind.span()=>
|
quote_spanned! { kind.span()=>
|
||||||
|
#deprecations
|
||||||
let #app_var = #app_var.external_subcommand_value_parser(clap::value_parser!(#subty));
|
let #app_var = #app_var.external_subcommand_value_parser(clap::value_parser!(#subty));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,11 +175,17 @@ fn gen_augment(
|
||||||
Kind::Flatten => match variant.fields {
|
Kind::Flatten => match variant.fields {
|
||||||
Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
|
Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
|
||||||
let ty = &unnamed[0];
|
let ty = &unnamed[0];
|
||||||
|
let deprecations = if !override_required {
|
||||||
|
item.deprecations()
|
||||||
|
} else {
|
||||||
|
quote!()
|
||||||
|
};
|
||||||
let old_heading_var = format_ident!("__clap_old_heading");
|
let old_heading_var = format_ident!("__clap_old_heading");
|
||||||
let next_help_heading = item.next_help_heading();
|
let next_help_heading = item.next_help_heading();
|
||||||
let next_display_order = item.next_display_order();
|
let next_display_order = item.next_display_order();
|
||||||
let subcommand = if override_required {
|
let subcommand = if override_required {
|
||||||
quote! {
|
quote! {
|
||||||
|
#deprecations
|
||||||
let #old_heading_var = #app_var.get_next_help_heading().map(|s| clap::builder::Str::from(s.to_owned()));
|
let #old_heading_var = #app_var.get_next_help_heading().map(|s| clap::builder::Str::from(s.to_owned()));
|
||||||
let #app_var = #app_var #next_help_heading #next_display_order;
|
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 = <#ty as clap::Subcommand>::augment_subcommands_for_update(#app_var);
|
||||||
|
@ -174,6 +193,7 @@ fn gen_augment(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
quote! {
|
quote! {
|
||||||
|
#deprecations
|
||||||
let #old_heading_var = #app_var.get_next_help_heading().map(|s| clap::builder::Str::from(s.to_owned()));
|
let #old_heading_var = #app_var.get_next_help_heading().map(|s| clap::builder::Str::from(s.to_owned()));
|
||||||
let #app_var = #app_var #next_help_heading #next_display_order;
|
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 = <#ty as clap::Subcommand>::augment_subcommands(#app_var);
|
||||||
|
@ -217,10 +237,16 @@ fn gen_augment(
|
||||||
};
|
};
|
||||||
|
|
||||||
let name = item.cased_name();
|
let name = item.cased_name();
|
||||||
|
let deprecations = if !override_required {
|
||||||
|
item.deprecations()
|
||||||
|
} else {
|
||||||
|
quote!()
|
||||||
|
};
|
||||||
let initial_app_methods = item.initial_top_level_methods();
|
let initial_app_methods = item.initial_top_level_methods();
|
||||||
let final_from_attrs = item.final_top_level_methods();
|
let final_from_attrs = item.final_top_level_methods();
|
||||||
let subcommand = quote! {
|
let subcommand = quote! {
|
||||||
let #app_var = #app_var.subcommand({
|
let #app_var = #app_var.subcommand({
|
||||||
|
#deprecations;
|
||||||
let #subcommand_var = clap::Command::new(#name);
|
let #subcommand_var = clap::Command::new(#name);
|
||||||
let #subcommand_var = #subcommand_var #initial_app_methods;
|
let #subcommand_var = #subcommand_var #initial_app_methods;
|
||||||
let #subcommand_var = #arg_block;
|
let #subcommand_var = #arg_block;
|
||||||
|
@ -286,9 +312,15 @@ fn gen_augment(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let deprecations = if !override_required {
|
||||||
|
item.deprecations()
|
||||||
|
} else {
|
||||||
|
quote!()
|
||||||
|
};
|
||||||
let name = item.cased_name();
|
let name = item.cased_name();
|
||||||
let subcommand = quote! {
|
let subcommand = quote! {
|
||||||
let #app_var = #app_var.subcommand({
|
let #app_var = #app_var.subcommand({
|
||||||
|
#deprecations
|
||||||
let #subcommand_var = clap::Command::new(#name);
|
let #subcommand_var = clap::Command::new(#name);
|
||||||
#sub_augment
|
#sub_augment
|
||||||
});
|
});
|
||||||
|
@ -299,12 +331,18 @@ fn gen_augment(
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
let deprecations = if !override_required {
|
||||||
|
parent_item.deprecations()
|
||||||
|
} else {
|
||||||
|
quote!()
|
||||||
|
};
|
||||||
let initial_app_methods = parent_item.initial_top_level_methods();
|
let initial_app_methods = parent_item.initial_top_level_methods();
|
||||||
let final_app_methods = parent_item.final_top_level_methods();
|
let final_app_methods = parent_item.final_top_level_methods();
|
||||||
quote! {
|
quote! {
|
||||||
let #app_var = #app_var #initial_app_methods;
|
#deprecations;
|
||||||
#( #subcommands )*;
|
let #app_var = #app_var #initial_app_methods;
|
||||||
#app_var #final_app_methods
|
#( #subcommands )*;
|
||||||
|
#app_var #final_app_methods
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,10 +41,17 @@ pub fn derive_value_enum(input: &DeriveInput) -> TokenStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_for_enum(_item: &Item, item_name: &Ident, variants: &[(&Variant, Item)]) -> TokenStream {
|
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(variants);
|
let lits = lits(variants);
|
||||||
let value_variants = gen_value_variants(&lits);
|
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! {
|
quote! {
|
||||||
#[allow(dead_code, unreachable_code, unused_variables, unused_braces)]
|
#[allow(dead_code, unreachable_code, unused_variables, unused_braces)]
|
||||||
|
@ -78,12 +85,14 @@ fn lits(variants: &[(&Variant, Item)]) -> Vec<(TokenStream, Ident)> {
|
||||||
abort!(variant.span(), "`#[derive(ValueEnum)]` only supports unit variants. Non-unit variants must be skipped");
|
abort!(variant.span(), "`#[derive(ValueEnum)]` only supports unit variants. Non-unit variants must be skipped");
|
||||||
}
|
}
|
||||||
let fields = item.field_methods(false);
|
let fields = item.field_methods(false);
|
||||||
|
let deprecations = item.deprecations();
|
||||||
let name = item.cased_name();
|
let name = item.cased_name();
|
||||||
Some((
|
Some((
|
||||||
quote_spanned! { variant.span()=>
|
quote_spanned! { variant.span()=> {
|
||||||
|
#deprecations
|
||||||
clap::builder::PossibleValue::new(#name)
|
clap::builder::PossibleValue::new(#name)
|
||||||
#fields
|
#fields
|
||||||
},
|
}},
|
||||||
variant.ident.clone(),
|
variant.ident.clone(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -101,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 (lit, variant): (Vec<TokenStream>, Vec<Ident>) = lits.iter().cloned().unzip();
|
||||||
|
|
||||||
|
let deprecations = item.deprecations();
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
fn to_possible_value<'a>(&self) -> ::std::option::Option<clap::builder::PossibleValue> {
|
fn to_possible_value<'a>(&self) -> ::std::option::Option<clap::builder::PossibleValue> {
|
||||||
|
#deprecations
|
||||||
match self {
|
match self {
|
||||||
#(Self::#variant => Some(#lit),)*
|
#(Self::#variant => Some(#lit),)*
|
||||||
_ => None
|
_ => None
|
||||||
|
|
|
@ -41,6 +41,7 @@ pub struct Item {
|
||||||
ty: Option<Type>,
|
ty: Option<Type>,
|
||||||
doc_comment: Vec<Method>,
|
doc_comment: Vec<Method>,
|
||||||
methods: Vec<Method>,
|
methods: Vec<Method>,
|
||||||
|
deprecations: Vec<Deprecation>,
|
||||||
value_parser: Option<ValueParser>,
|
value_parser: Option<ValueParser>,
|
||||||
action: Option<Action>,
|
action: Option<Action>,
|
||||||
verbatim_doc_comment: bool,
|
verbatim_doc_comment: bool,
|
||||||
|
@ -57,7 +58,8 @@ impl Item {
|
||||||
let attrs = &input.attrs;
|
let attrs = &input.attrs;
|
||||||
let argument_casing = Sp::call_site(DEFAULT_CASING);
|
let argument_casing = Sp::call_site(DEFAULT_CASING);
|
||||||
let env_casing = Sp::call_site(DEFAULT_ENV_CASING);
|
let env_casing = Sp::call_site(DEFAULT_ENV_CASING);
|
||||||
Self::from_struct(span, attrs, name, argument_casing, env_casing)
|
let kind = Sp::new(Kind::Command(Sp::new(Ty::Other, span)), span);
|
||||||
|
Self::from_struct(attrs, name, argument_casing, env_casing, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_subcommand_enum(input: &DeriveInput, name: Name) -> Self {
|
pub fn from_subcommand_enum(input: &DeriveInput, name: Name) -> Self {
|
||||||
|
@ -65,7 +67,8 @@ impl Item {
|
||||||
let attrs = &input.attrs;
|
let attrs = &input.attrs;
|
||||||
let argument_casing = Sp::call_site(DEFAULT_CASING);
|
let argument_casing = Sp::call_site(DEFAULT_CASING);
|
||||||
let env_casing = Sp::call_site(DEFAULT_ENV_CASING);
|
let env_casing = Sp::call_site(DEFAULT_ENV_CASING);
|
||||||
Self::from_struct(span, attrs, name, argument_casing, env_casing)
|
let kind = Sp::new(Kind::Command(Sp::new(Ty::Other, span)), span);
|
||||||
|
Self::from_struct(attrs, name, argument_casing, env_casing, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_value_enum(input: &DeriveInput, name: Name) -> Self {
|
pub fn from_value_enum(input: &DeriveInput, name: Name) -> Self {
|
||||||
|
@ -73,17 +76,18 @@ impl Item {
|
||||||
let attrs = &input.attrs;
|
let attrs = &input.attrs;
|
||||||
let argument_casing = Sp::call_site(DEFAULT_CASING);
|
let argument_casing = Sp::call_site(DEFAULT_CASING);
|
||||||
let env_casing = Sp::call_site(DEFAULT_ENV_CASING);
|
let env_casing = Sp::call_site(DEFAULT_ENV_CASING);
|
||||||
Self::from_struct(span, attrs, name, argument_casing, env_casing)
|
let kind = Sp::new(Kind::Value(Sp::new(Ty::Other, span)), span);
|
||||||
|
Self::from_struct(attrs, name, argument_casing, env_casing, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_struct(
|
fn from_struct(
|
||||||
span: Span,
|
|
||||||
attrs: &[Attribute],
|
attrs: &[Attribute],
|
||||||
name: Name,
|
name: Name,
|
||||||
argument_casing: Sp<CasingStyle>,
|
argument_casing: Sp<CasingStyle>,
|
||||||
env_casing: Sp<CasingStyle>,
|
env_casing: Sp<CasingStyle>,
|
||||||
|
kind: Sp<Kind>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut res = Self::new(span, name, None, argument_casing, env_casing);
|
let mut res = Self::new(name, None, argument_casing, env_casing, kind);
|
||||||
res.push_attrs(attrs);
|
res.push_attrs(attrs);
|
||||||
res.push_doc_comment(attrs, "about");
|
res.push_doc_comment(attrs, "about");
|
||||||
|
|
||||||
|
@ -99,17 +103,8 @@ impl Item {
|
||||||
"`action` attribute is only allowed on fields"
|
"`action` attribute is only allowed on fields"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
match &*res.kind {
|
|
||||||
Kind::Subcommand(_) => abort!(res.kind.span(), "subcommand is only allowed on fields"),
|
res
|
||||||
Kind::Skip(_) => abort!(res.kind.span(), "skip is only allowed on fields"),
|
|
||||||
Kind::Arg(_) => res,
|
|
||||||
Kind::FromGlobal(_) => abort!(res.kind.span(), "from_global is only allowed on fields"),
|
|
||||||
Kind::Flatten => abort!(res.kind.span(), "flatten is only allowed on fields"),
|
|
||||||
Kind::ExternalSubcommand => abort!(
|
|
||||||
res.kind.span(),
|
|
||||||
"external_subcommand is only allowed on fields"
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_subcommand_variant(
|
pub fn from_subcommand_variant(
|
||||||
|
@ -118,13 +113,9 @@ impl Item {
|
||||||
env_casing: Sp<CasingStyle>,
|
env_casing: Sp<CasingStyle>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let name = variant.ident.clone();
|
let name = variant.ident.clone();
|
||||||
let mut res = Self::new(
|
let span = variant.span();
|
||||||
variant.span(),
|
let kind = Sp::new(Kind::Command(Sp::new(Ty::Other, span)), span);
|
||||||
Name::Derived(name),
|
let mut res = Self::new(Name::Derived(name), None, struct_casing, env_casing, kind);
|
||||||
None,
|
|
||||||
struct_casing,
|
|
||||||
env_casing,
|
|
||||||
);
|
|
||||||
res.push_attrs(&variant.attrs);
|
res.push_attrs(&variant.attrs);
|
||||||
res.push_doc_comment(&variant.attrs, "about");
|
res.push_doc_comment(&variant.attrs, "about");
|
||||||
|
|
||||||
|
@ -153,8 +144,6 @@ impl Item {
|
||||||
res.doc_comment = vec![];
|
res.doc_comment = vec![];
|
||||||
}
|
}
|
||||||
|
|
||||||
Kind::ExternalSubcommand => (),
|
|
||||||
|
|
||||||
Kind::Subcommand(_) => {
|
Kind::Subcommand(_) => {
|
||||||
if let Some(value_parser) = res.value_parser.as_ref() {
|
if let Some(value_parser) = res.value_parser.as_ref() {
|
||||||
abort!(
|
abort!(
|
||||||
|
@ -205,11 +194,13 @@ impl Item {
|
||||||
|
|
||||||
res.kind = Sp::new(Kind::Subcommand(ty), res.kind.span());
|
res.kind = Sp::new(Kind::Subcommand(ty), res.kind.span());
|
||||||
}
|
}
|
||||||
Kind::Skip(_) => (),
|
|
||||||
Kind::FromGlobal(_) => {
|
Kind::ExternalSubcommand
|
||||||
abort!(res.kind.span(), "from_global is not supported on variants");
|
| Kind::FromGlobal(_)
|
||||||
}
|
| Kind::Skip(_)
|
||||||
Kind::Arg(_) => (),
|
| Kind::Command(_)
|
||||||
|
| Kind::Value(_)
|
||||||
|
| Kind::Arg(_) => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
res
|
res
|
||||||
|
@ -220,12 +211,14 @@ impl Item {
|
||||||
argument_casing: Sp<CasingStyle>,
|
argument_casing: Sp<CasingStyle>,
|
||||||
env_casing: Sp<CasingStyle>,
|
env_casing: Sp<CasingStyle>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let span = variant.span();
|
||||||
|
let kind = Sp::new(Kind::Value(Sp::new(Ty::Other, span)), span);
|
||||||
let mut res = Self::new(
|
let mut res = Self::new(
|
||||||
variant.span(),
|
|
||||||
Name::Derived(variant.ident.clone()),
|
Name::Derived(variant.ident.clone()),
|
||||||
None,
|
None,
|
||||||
argument_casing,
|
argument_casing,
|
||||||
env_casing,
|
env_casing,
|
||||||
|
kind,
|
||||||
);
|
);
|
||||||
res.push_attrs(&variant.attrs);
|
res.push_attrs(&variant.attrs);
|
||||||
res.push_doc_comment(&variant.attrs, "help");
|
res.push_doc_comment(&variant.attrs, "help");
|
||||||
|
@ -242,17 +235,8 @@ impl Item {
|
||||||
"`action` attribute is only allowed on fields"
|
"`action` attribute is only allowed on fields"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
match &*res.kind {
|
|
||||||
Kind::Subcommand(_) => abort!(res.kind.span(), "subcommand is only allowed on fields"),
|
res
|
||||||
Kind::Skip(_) => res,
|
|
||||||
Kind::Arg(_) => res,
|
|
||||||
Kind::FromGlobal(_) => abort!(res.kind.span(), "from_global is only allowed on fields"),
|
|
||||||
Kind::Flatten => abort!(res.kind.span(), "flatten is only allowed on fields"),
|
|
||||||
Kind::ExternalSubcommand => abort!(
|
|
||||||
res.kind.span(),
|
|
||||||
"external_subcommand is only allowed on fields"
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_args_field(
|
pub fn from_args_field(
|
||||||
|
@ -261,12 +245,14 @@ impl Item {
|
||||||
env_casing: Sp<CasingStyle>,
|
env_casing: Sp<CasingStyle>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let name = field.ident.clone().unwrap();
|
let name = field.ident.clone().unwrap();
|
||||||
|
let span = field.span();
|
||||||
|
let kind = Sp::new(Kind::Arg(Sp::new(Ty::Other, span)), span);
|
||||||
let mut res = Self::new(
|
let mut res = Self::new(
|
||||||
field.span(),
|
|
||||||
Name::Derived(name),
|
Name::Derived(name),
|
||||||
Some(field.ty.clone()),
|
Some(field.ty.clone()),
|
||||||
struct_casing,
|
struct_casing,
|
||||||
env_casing,
|
env_casing,
|
||||||
|
kind,
|
||||||
);
|
);
|
||||||
res.push_attrs(&field.attrs);
|
res.push_attrs(&field.attrs);
|
||||||
res.push_doc_comment(&field.attrs, "help");
|
res.push_doc_comment(&field.attrs, "help");
|
||||||
|
@ -296,12 +282,6 @@ impl Item {
|
||||||
res.doc_comment = vec![];
|
res.doc_comment = vec![];
|
||||||
}
|
}
|
||||||
|
|
||||||
Kind::ExternalSubcommand => {
|
|
||||||
abort! { res.kind.span(),
|
|
||||||
"`external_subcommand` can be used only on enum variants"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Kind::Subcommand(_) => {
|
Kind::Subcommand(_) => {
|
||||||
if let Some(value_parser) = res.value_parser.as_ref() {
|
if let Some(value_parser) = res.value_parser.as_ref() {
|
||||||
abort!(
|
abort!(
|
||||||
|
@ -390,17 +370,19 @@ impl Item {
|
||||||
.unwrap_or_else(|| field.ty.span()),
|
.unwrap_or_else(|| field.ty.span()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Kind::Command(_) | Kind::Value(_) | Kind::ExternalSubcommand => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
default_span: Span,
|
|
||||||
name: Name,
|
name: Name,
|
||||||
ty: Option<Type>,
|
ty: Option<Type>,
|
||||||
casing: Sp<CasingStyle>,
|
casing: Sp<CasingStyle>,
|
||||||
env_casing: Sp<CasingStyle>,
|
env_casing: Sp<CasingStyle>,
|
||||||
|
kind: Sp<Kind>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
|
@ -409,6 +391,7 @@ impl Item {
|
||||||
env_casing,
|
env_casing,
|
||||||
doc_comment: vec![],
|
doc_comment: vec![],
|
||||||
methods: vec![],
|
methods: vec![],
|
||||||
|
deprecations: vec![],
|
||||||
value_parser: None,
|
value_parser: None,
|
||||||
action: None,
|
action: None,
|
||||||
verbatim_doc_comment: false,
|
verbatim_doc_comment: false,
|
||||||
|
@ -416,7 +399,7 @@ impl Item {
|
||||||
next_help_heading: None,
|
next_help_heading: None,
|
||||||
is_enum: false,
|
is_enum: false,
|
||||||
is_positional: true,
|
is_positional: true,
|
||||||
kind: Sp::new(Kind::Arg(Sp::new(Ty::Other, default_span)), default_span),
|
kind,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,7 +420,73 @@ impl Item {
|
||||||
|
|
||||||
fn push_attrs(&mut self, attrs: &[Attribute]) {
|
fn push_attrs(&mut self, attrs: &[Attribute]) {
|
||||||
let parsed = ClapAttr::parse_all(attrs);
|
let parsed = ClapAttr::parse_all(attrs);
|
||||||
|
|
||||||
for attr in &parsed {
|
for attr in &parsed {
|
||||||
|
if let Some(AttrValue::Call(_)) = &attr.value {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let kind = match &attr.magic {
|
||||||
|
Some(MagicAttrName::FromGlobal) => {
|
||||||
|
if attr.value.is_some() {
|
||||||
|
let expr = attr.value_or_abort();
|
||||||
|
abort!(expr, "attribute `{}` does not accept a value", attr.name);
|
||||||
|
}
|
||||||
|
let ty = Sp::call_site(Ty::Other);
|
||||||
|
let kind = Sp::new(Kind::FromGlobal(ty), attr.name.clone().span());
|
||||||
|
Some(kind)
|
||||||
|
}
|
||||||
|
Some(MagicAttrName::Subcommand) if attr.value.is_none() => {
|
||||||
|
if attr.value.is_some() {
|
||||||
|
let expr = attr.value_or_abort();
|
||||||
|
abort!(expr, "attribute `{}` does not accept a value", attr.name);
|
||||||
|
}
|
||||||
|
let ty = Sp::call_site(Ty::Other);
|
||||||
|
let kind = Sp::new(Kind::Subcommand(ty), attr.name.clone().span());
|
||||||
|
Some(kind)
|
||||||
|
}
|
||||||
|
Some(MagicAttrName::ExternalSubcommand) if attr.value.is_none() => {
|
||||||
|
if attr.value.is_some() {
|
||||||
|
let expr = attr.value_or_abort();
|
||||||
|
abort!(expr, "attribute `{}` does not accept a value", attr.name);
|
||||||
|
}
|
||||||
|
let kind = Sp::new(Kind::ExternalSubcommand, attr.name.clone().span());
|
||||||
|
Some(kind)
|
||||||
|
}
|
||||||
|
Some(MagicAttrName::Flatten) if attr.value.is_none() => {
|
||||||
|
if attr.value.is_some() {
|
||||||
|
let expr = attr.value_or_abort();
|
||||||
|
abort!(expr, "attribute `{}` does not accept a value", attr.name);
|
||||||
|
}
|
||||||
|
let kind = Sp::new(Kind::Flatten, attr.name.clone().span());
|
||||||
|
Some(kind)
|
||||||
|
}
|
||||||
|
Some(MagicAttrName::Skip) => {
|
||||||
|
let expr = attr.value.clone();
|
||||||
|
let kind = Sp::new(Kind::Skip(expr), attr.name.clone().span());
|
||||||
|
Some(kind)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(kind) = kind {
|
||||||
|
self.set_kind(kind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for attr in &parsed {
|
||||||
|
match attr.kind.get() {
|
||||||
|
AttrKind::Clap => {}
|
||||||
|
AttrKind::StructOpt => {
|
||||||
|
self.deprecations.push(Deprecation::attribute(
|
||||||
|
"4.0.0",
|
||||||
|
*attr.kind.get(),
|
||||||
|
AttrKind::Clap,
|
||||||
|
attr.kind.span(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(AttrValue::Call(tokens)) = &attr.value {
|
if let Some(AttrValue::Call(tokens)) = &attr.value {
|
||||||
// Force raw mode with method call syntax
|
// Force raw mode with method call syntax
|
||||||
self.push_method(attr.name.clone(), quote!(#(#tokens),*));
|
self.push_method(attr.name.clone(), quote!(#(#tokens),*));
|
||||||
|
@ -458,11 +507,23 @@ impl Item {
|
||||||
|
|
||||||
#[cfg(not(feature = "unstable-v5"))]
|
#[cfg(not(feature = "unstable-v5"))]
|
||||||
Some(MagicAttrName::ValueParser) if attr.value.is_none() => {
|
Some(MagicAttrName::ValueParser) if attr.value.is_none() => {
|
||||||
|
self.deprecations.push(Deprecation {
|
||||||
|
span: attr.name.span(),
|
||||||
|
id: "bare_value_parser",
|
||||||
|
version: "4.0.0",
|
||||||
|
description: "`#[clap(value_parser)]` is now the default and is no longer needed`".to_owned(),
|
||||||
|
});
|
||||||
self.value_parser = Some(ValueParser::Implicit(attr.name.clone()));
|
self.value_parser = Some(ValueParser::Implicit(attr.name.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "unstable-v5"))]
|
#[cfg(not(feature = "unstable-v5"))]
|
||||||
Some(MagicAttrName::Action) if attr.value.is_none() => {
|
Some(MagicAttrName::Action) if attr.value.is_none() => {
|
||||||
|
self.deprecations.push(Deprecation {
|
||||||
|
span: attr.name.span(),
|
||||||
|
id: "bare_action",
|
||||||
|
version: "4.0.0",
|
||||||
|
description: "`#[clap(action)]` is now the default and is no longer needed`".to_owned(),
|
||||||
|
});
|
||||||
self.action = Some(Action::Implicit(attr.name.clone()));
|
self.action = Some(Action::Implicit(attr.name.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,28 +534,8 @@ impl Item {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(MagicAttrName::ValueEnum) if attr.value.is_none() => self.is_enum = true,
|
Some(MagicAttrName::ValueEnum) if attr.value.is_none() => {
|
||||||
|
self.is_enum = true
|
||||||
Some(MagicAttrName::FromGlobal) if attr.value.is_none() => {
|
|
||||||
let ty = Sp::call_site(Ty::Other);
|
|
||||||
let kind = Sp::new(Kind::FromGlobal(ty), attr.name.clone().span());
|
|
||||||
self.set_kind(kind);
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(MagicAttrName::Subcommand) if attr.value.is_none() => {
|
|
||||||
let ty = Sp::call_site(Ty::Other);
|
|
||||||
let kind = Sp::new(Kind::Subcommand(ty), attr.name.clone().span());
|
|
||||||
self.set_kind(kind);
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(MagicAttrName::ExternalSubcommand) if attr.value.is_none() => {
|
|
||||||
let kind = Sp::new(Kind::ExternalSubcommand, attr.name.clone().span());
|
|
||||||
self.set_kind(kind);
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(MagicAttrName::Flatten) if attr.value.is_none() => {
|
|
||||||
let kind = Sp::new(Kind::Flatten, attr.name.clone().span());
|
|
||||||
self.set_kind(kind);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(MagicAttrName::VerbatimDocComment) if attr.value.is_none() => {
|
Some(MagicAttrName::VerbatimDocComment) if attr.value.is_none() => {
|
||||||
|
@ -521,12 +562,6 @@ impl Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(MagicAttrName::Skip) => {
|
|
||||||
let expr = attr.value.clone();
|
|
||||||
let kind = Sp::new(Kind::Skip(expr), attr.name.clone().span());
|
|
||||||
self.set_kind(kind);
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(MagicAttrName::DefaultValueT) => {
|
Some(MagicAttrName::DefaultValueT) => {
|
||||||
let ty = if let Some(ty) = self.ty.as_ref() {
|
let ty = if let Some(ty) = self.ty.as_ref() {
|
||||||
ty
|
ty
|
||||||
|
@ -791,14 +826,18 @@ impl Item {
|
||||||
|
|
||||||
// Directives that never receive a value
|
// Directives that never receive a value
|
||||||
Some(MagicAttrName::ValueEnum)
|
Some(MagicAttrName::ValueEnum)
|
||||||
| Some(MagicAttrName::FromGlobal)
|
|
||||||
| Some(MagicAttrName::Subcommand)
|
|
||||||
| Some(MagicAttrName::ExternalSubcommand)
|
|
||||||
| Some(MagicAttrName::Flatten)
|
|
||||||
| Some(MagicAttrName::VerbatimDocComment) => {
|
| Some(MagicAttrName::VerbatimDocComment) => {
|
||||||
let expr = attr.value_or_abort();
|
let expr = attr.value_or_abort();
|
||||||
abort!(expr, "attribute `{}` does not accept a value", attr.name);
|
abort!(expr, "attribute `{}` does not accept a value", attr.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Kinds
|
||||||
|
Some(MagicAttrName::FromGlobal)
|
||||||
|
| Some(MagicAttrName::Subcommand)
|
||||||
|
| Some(MagicAttrName::ExternalSubcommand)
|
||||||
|
| Some(MagicAttrName::Flatten)
|
||||||
|
| Some(MagicAttrName::Skip) => {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -825,13 +864,24 @@ impl Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_kind(&mut self, kind: Sp<Kind>) {
|
fn set_kind(&mut self, kind: Sp<Kind>) {
|
||||||
if let Kind::Arg(_) = *self.kind {
|
match (self.kind.get(), kind.get()) {
|
||||||
self.kind = kind;
|
(Kind::Arg(_), Kind::FromGlobal(_))
|
||||||
} else {
|
| (Kind::Arg(_), Kind::Subcommand(_))
|
||||||
abort!(
|
| (Kind::Arg(_), Kind::Flatten)
|
||||||
kind.span(),
|
| (Kind::Arg(_), Kind::Skip(_))
|
||||||
"`subcommand`, `flatten`, `external_subcommand` and `skip` cannot be used together"
|
| (Kind::Command(_), Kind::Subcommand(_))
|
||||||
);
|
| (Kind::Command(_), Kind::Flatten)
|
||||||
|
| (Kind::Command(_), Kind::Skip(_))
|
||||||
|
| (Kind::Command(_), Kind::ExternalSubcommand)
|
||||||
|
| (Kind::Value(_), Kind::Skip(_)) => {
|
||||||
|
self.kind = kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
(_, _) => {
|
||||||
|
let old = self.kind.name();
|
||||||
|
let new = kind.name();
|
||||||
|
abort!(kind.span(), "`{}` cannot be used with `{}`", new, old);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -876,6 +926,11 @@ impl Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deprecations(&self) -> proc_macro2::TokenStream {
|
||||||
|
let deprecations = &self.deprecations;
|
||||||
|
quote!( #(#deprecations)* )
|
||||||
|
}
|
||||||
|
|
||||||
pub fn next_display_order(&self) -> TokenStream {
|
pub fn next_display_order(&self) -> TokenStream {
|
||||||
let next_display_order = self.next_display_order.as_ref().into_iter();
|
let next_display_order = self.next_display_order.as_ref().into_iter();
|
||||||
quote!( #(#next_display_order)* )
|
quote!( #(#next_display_order)* )
|
||||||
|
@ -949,11 +1004,11 @@ impl Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn casing(&self) -> Sp<CasingStyle> {
|
pub fn casing(&self) -> Sp<CasingStyle> {
|
||||||
self.casing.clone()
|
self.casing
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn env_casing(&self) -> Sp<CasingStyle> {
|
pub fn env_casing(&self) -> Sp<CasingStyle> {
|
||||||
self.env_casing.clone()
|
self.env_casing
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_explicit_methods(&self) -> bool {
|
pub fn has_explicit_methods(&self) -> bool {
|
||||||
|
@ -1057,6 +1112,8 @@ fn default_action(field_type: &Type, span: Span) -> Method {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Kind {
|
pub enum Kind {
|
||||||
Arg(Sp<Ty>),
|
Arg(Sp<Ty>),
|
||||||
|
Command(Sp<Ty>),
|
||||||
|
Value(Sp<Ty>),
|
||||||
FromGlobal(Sp<Ty>),
|
FromGlobal(Sp<Ty>),
|
||||||
Subcommand(Sp<Ty>),
|
Subcommand(Sp<Ty>),
|
||||||
Flatten,
|
Flatten,
|
||||||
|
@ -1064,6 +1121,21 @@ pub enum Kind {
|
||||||
ExternalSubcommand,
|
ExternalSubcommand,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Kind {
|
||||||
|
pub fn name(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Arg(_) => "arg",
|
||||||
|
Self::Command(_) => "command",
|
||||||
|
Self::Value(_) => "value",
|
||||||
|
Self::FromGlobal(_) => "from_global",
|
||||||
|
Self::Subcommand(_) => "subcommand",
|
||||||
|
Self::Flatten => "flatten",
|
||||||
|
Self::Skip(_) => "skip",
|
||||||
|
Self::ExternalSubcommand => "external_subcommand",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Method {
|
pub struct Method {
|
||||||
name: Ident,
|
name: Ident,
|
||||||
|
@ -1115,6 +1187,54 @@ impl ToTokens for Method {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Deprecation {
|
||||||
|
pub span: Span,
|
||||||
|
pub id: &'static str,
|
||||||
|
pub version: &'static str,
|
||||||
|
pub description: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deprecation {
|
||||||
|
fn attribute(version: &'static str, old: AttrKind, new: AttrKind, span: Span) -> Self {
|
||||||
|
Self {
|
||||||
|
span,
|
||||||
|
id: "old_attribute",
|
||||||
|
version,
|
||||||
|
description: format!(
|
||||||
|
"Attribute `#[{}(...)]` has been deprecated in favor of `#[{}(...)]`",
|
||||||
|
old.as_str(),
|
||||||
|
new.as_str()
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for Deprecation {
|
||||||
|
fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
|
||||||
|
let tokens = if cfg!(feature = "deprecated") {
|
||||||
|
let Deprecation {
|
||||||
|
span,
|
||||||
|
id,
|
||||||
|
version,
|
||||||
|
description,
|
||||||
|
} = self;
|
||||||
|
let span = *span;
|
||||||
|
let id = Ident::new(id, span);
|
||||||
|
|
||||||
|
quote_spanned!(span=> {
|
||||||
|
#[deprecated(since = #version, note = #description)]
|
||||||
|
fn #id() {}
|
||||||
|
#id();
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
quote!()
|
||||||
|
};
|
||||||
|
|
||||||
|
tokens.to_tokens(ts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// replace all `:` with `, ` when not inside the `<>`
|
/// replace all `:` with `, ` when not inside the `<>`
|
||||||
///
|
///
|
||||||
/// `"author1:author2:author3" => "author1, author2, author3"`
|
/// `"author1:author2:author3" => "author1, author2, author3"`
|
||||||
|
|
|
@ -42,7 +42,7 @@ pub fn value_enum(input: TokenStream) -> TokenStream {
|
||||||
/// receiving an instance of `clap::ArgMatches` from conducting parsing, and then
|
/// receiving an instance of `clap::ArgMatches` from conducting parsing, and then
|
||||||
/// implementing a conversion code to instantiate an instance of the user
|
/// implementing a conversion code to instantiate an instance of the user
|
||||||
/// context struct.
|
/// context struct.
|
||||||
#[proc_macro_derive(Parser, attributes(clap))]
|
#[proc_macro_derive(Parser, attributes(clap, structopt))]
|
||||||
#[proc_macro_error]
|
#[proc_macro_error]
|
||||||
pub fn parser(input: TokenStream) -> TokenStream {
|
pub fn parser(input: TokenStream) -> TokenStream {
|
||||||
let input: DeriveInput = parse_macro_input!(input);
|
let input: DeriveInput = parse_macro_input!(input);
|
||||||
|
|
|
@ -5,7 +5,7 @@ use syn::LitStr;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
/// An entity with a span attached.
|
/// An entity with a span attached.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct Sp<T> {
|
pub struct Sp<T> {
|
||||||
val: T,
|
val: T,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
@ -23,6 +23,10 @@ impl<T> Sp<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get(&self) -> &T {
|
||||||
|
&self.val
|
||||||
|
}
|
||||||
|
|
||||||
pub fn span(&self) -> Span {
|
pub fn span(&self) -> Span {
|
||||||
self.span
|
self.span
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: `external_subcommand` can be used only on enum variants
|
error: `external_subcommand` cannot be used with `arg`
|
||||||
--> $DIR/external_subcommand_misuse.rs:5:12
|
--> tests/derive_ui/external_subcommand_misuse.rs:5:12
|
||||||
|
|
|
|
||||||
5 | #[clap(external_subcommand)]
|
5 | #[clap(external_subcommand)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: `subcommand`, `flatten`, `external_subcommand` and `skip` cannot be used together
|
error: `flatten` cannot be used with `skip`
|
||||||
--> $DIR/skip_flatten.rs:17:18
|
--> tests/derive_ui/skip_flatten.rs:17:18
|
||||||
|
|
|
|
||||||
17 | #[clap(skip, flatten)]
|
17 | #[clap(skip, flatten)]
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: `subcommand`, `flatten`, `external_subcommand` and `skip` cannot be used together
|
error: `skip` cannot be used with `subcommand`
|
||||||
--> $DIR/skip_subcommand.rs:17:24
|
--> tests/derive_ui/skip_subcommand.rs:17:24
|
||||||
|
|
|
|
||||||
17 | #[clap(subcommand, skip)]
|
17 | #[clap(subcommand, skip)]
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: subcommand is only allowed on fields
|
error: `subcommand` cannot be used with `command`
|
||||||
--> $DIR/struct_subcommand.rs:12:24
|
--> tests/derive_ui/struct_subcommand.rs:12:24
|
||||||
|
|
|
|
||||||
12 | #[clap(name = "basic", subcommand)]
|
12 | #[clap(name = "basic", subcommand)]
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: `subcommand`, `flatten`, `external_subcommand` and `skip` cannot be used together
|
error: `flatten` cannot be used with `subcommand`
|
||||||
--> $DIR/subcommand_and_flatten.rs:16:24
|
--> tests/derive_ui/subcommand_and_flatten.rs:16:24
|
||||||
|
|
|
|
||||||
16 | #[clap(subcommand, flatten)]
|
16 | #[clap(subcommand, flatten)]
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
Loading…
Reference in a new issue