mirror of
https://github.com/clap-rs/clap
synced 2025-03-04 15:27:16 +00:00
feat(derive): Reserve the T group name
Since the `name` is changed to be the package name, we can't use it as (1) its not as predictable and (2) it can lead to conflicts if a `Parser` is flattened into a `Parser`
This commit is contained in:
parent
01c0975678
commit
d3bf5450ff
6 changed files with 58 additions and 6 deletions
|
@ -198,6 +198,7 @@ Subtle changes (i.e. compiler won't catch):
|
||||||
- *(env)* Parse `--help` and `--version` like any `ArgAction::SetTrue` flag (#3776)
|
- *(env)* Parse `--help` and `--version` like any `ArgAction::SetTrue` flag (#3776)
|
||||||
- *(derive)* Leave `Arg::id` as `verbatim` casing, requiring updating of string references to other args like in `conflicts_with` or `requires` (#3282)
|
- *(derive)* Leave `Arg::id` as `verbatim` casing, requiring updating of string references to other args like in `conflicts_with` or `requires` (#3282)
|
||||||
- *(derive)* Doc comments for `ValueEnum` variants will now show up in `--help` (#3312)
|
- *(derive)* Doc comments for `ValueEnum` variants will now show up in `--help` (#3312)
|
||||||
|
- *(derive)* When deriving `Args`, and `ArgGroup` is created using the type's name, reserving it for future use (#2621, #4209)
|
||||||
|
|
||||||
Easier to catch changes:
|
Easier to catch changes:
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
use proc_macro2::{Ident, Span, TokenStream};
|
use proc_macro2::{Ident, Span, TokenStream};
|
||||||
use proc_macro_error::{abort, abort_call_site};
|
use proc_macro_error::{abort, abort_call_site};
|
||||||
use quote::{format_ident, quote, quote_spanned};
|
use quote::{format_ident, quote, quote_spanned};
|
||||||
|
use syn::ext::IdentExt;
|
||||||
use syn::{
|
use syn::{
|
||||||
punctuated::Punctuated, spanned::Spanned, token::Comma, Data, DataStruct, DeriveInput, Field,
|
punctuated::Punctuated, spanned::Spanned, token::Comma, Data, DataStruct, DeriveInput, Field,
|
||||||
Fields, Generics,
|
Fields, Generics,
|
||||||
|
@ -317,10 +318,13 @@ pub fn gen_augment(
|
||||||
quote!()
|
quote!()
|
||||||
};
|
};
|
||||||
let initial_app_methods = parent_item.initial_top_level_methods();
|
let initial_app_methods = parent_item.initial_top_level_methods();
|
||||||
|
let group_id = parent_item.ident().unraw().to_string();
|
||||||
let final_app_methods = parent_item.final_top_level_methods();
|
let final_app_methods = parent_item.final_top_level_methods();
|
||||||
quote! {{
|
quote! {{
|
||||||
#deprecations
|
#deprecations
|
||||||
let #app_var = #app_var #initial_app_methods;
|
let #app_var = #app_var
|
||||||
|
#initial_app_methods
|
||||||
|
.group(clap::ArgGroup::new(#group_id).multiple(true));
|
||||||
#( #args )*
|
#( #args )*
|
||||||
#app_var #final_app_methods
|
#app_var #final_app_methods
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -36,6 +36,7 @@ pub const DEFAULT_ENV_CASING: CasingStyle = CasingStyle::ScreamingSnake;
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Item {
|
pub struct Item {
|
||||||
name: Name,
|
name: Name,
|
||||||
|
ident: Ident,
|
||||||
casing: Sp<CasingStyle>,
|
casing: Sp<CasingStyle>,
|
||||||
env_casing: Sp<CasingStyle>,
|
env_casing: Sp<CasingStyle>,
|
||||||
ty: Option<Type>,
|
ty: Option<Type>,
|
||||||
|
@ -54,13 +55,14 @@ pub struct Item {
|
||||||
|
|
||||||
impl Item {
|
impl Item {
|
||||||
pub fn from_args_struct(input: &DeriveInput, name: Name) -> Self {
|
pub fn from_args_struct(input: &DeriveInput, name: Name) -> Self {
|
||||||
|
let ident = input.ident.clone();
|
||||||
let span = input.ident.span();
|
let span = input.ident.span();
|
||||||
let attrs = &input.attrs;
|
let attrs = &input.attrs;
|
||||||
let argument_casing = Sp::new(DEFAULT_CASING, span);
|
let argument_casing = Sp::new(DEFAULT_CASING, span);
|
||||||
let env_casing = Sp::new(DEFAULT_ENV_CASING, span);
|
let env_casing = Sp::new(DEFAULT_ENV_CASING, span);
|
||||||
let kind = Sp::new(Kind::Command(Sp::new(Ty::Other, span)), span);
|
let kind = Sp::new(Kind::Command(Sp::new(Ty::Other, span)), span);
|
||||||
|
|
||||||
let mut res = Self::new(name, None, argument_casing, env_casing, kind);
|
let mut res = Self::new(name, ident, None, argument_casing, env_casing, kind);
|
||||||
let parsed_attrs = ClapAttr::parse_all(attrs);
|
let parsed_attrs = ClapAttr::parse_all(attrs);
|
||||||
res.infer_kind(&parsed_attrs);
|
res.infer_kind(&parsed_attrs);
|
||||||
res.push_attrs(&parsed_attrs);
|
res.push_attrs(&parsed_attrs);
|
||||||
|
@ -70,13 +72,14 @@ impl Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_subcommand_enum(input: &DeriveInput, name: Name) -> Self {
|
pub fn from_subcommand_enum(input: &DeriveInput, name: Name) -> Self {
|
||||||
|
let ident = input.ident.clone();
|
||||||
let span = input.ident.span();
|
let span = input.ident.span();
|
||||||
let attrs = &input.attrs;
|
let attrs = &input.attrs;
|
||||||
let argument_casing = Sp::new(DEFAULT_CASING, span);
|
let argument_casing = Sp::new(DEFAULT_CASING, span);
|
||||||
let env_casing = Sp::new(DEFAULT_ENV_CASING, span);
|
let env_casing = Sp::new(DEFAULT_ENV_CASING, span);
|
||||||
let kind = Sp::new(Kind::Command(Sp::new(Ty::Other, span)), span);
|
let kind = Sp::new(Kind::Command(Sp::new(Ty::Other, span)), span);
|
||||||
|
|
||||||
let mut res = Self::new(name, None, argument_casing, env_casing, kind);
|
let mut res = Self::new(name, ident, None, argument_casing, env_casing, kind);
|
||||||
let parsed_attrs = ClapAttr::parse_all(attrs);
|
let parsed_attrs = ClapAttr::parse_all(attrs);
|
||||||
res.infer_kind(&parsed_attrs);
|
res.infer_kind(&parsed_attrs);
|
||||||
res.push_attrs(&parsed_attrs);
|
res.push_attrs(&parsed_attrs);
|
||||||
|
@ -86,13 +89,14 @@ impl Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_value_enum(input: &DeriveInput, name: Name) -> Self {
|
pub fn from_value_enum(input: &DeriveInput, name: Name) -> Self {
|
||||||
|
let ident = input.ident.clone();
|
||||||
let span = input.ident.span();
|
let span = input.ident.span();
|
||||||
let attrs = &input.attrs;
|
let attrs = &input.attrs;
|
||||||
let argument_casing = Sp::new(DEFAULT_CASING, span);
|
let argument_casing = Sp::new(DEFAULT_CASING, span);
|
||||||
let env_casing = Sp::new(DEFAULT_ENV_CASING, span);
|
let env_casing = Sp::new(DEFAULT_ENV_CASING, span);
|
||||||
let kind = Sp::new(Kind::Value, span);
|
let kind = Sp::new(Kind::Value, span);
|
||||||
|
|
||||||
let mut res = Self::new(name, None, argument_casing, env_casing, kind);
|
let mut res = Self::new(name, ident, None, argument_casing, env_casing, kind);
|
||||||
let parsed_attrs = ClapAttr::parse_all(attrs);
|
let parsed_attrs = ClapAttr::parse_all(attrs);
|
||||||
res.infer_kind(&parsed_attrs);
|
res.infer_kind(&parsed_attrs);
|
||||||
res.push_attrs(&parsed_attrs);
|
res.push_attrs(&parsed_attrs);
|
||||||
|
@ -116,6 +120,7 @@ impl Item {
|
||||||
env_casing: Sp<CasingStyle>,
|
env_casing: Sp<CasingStyle>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let name = variant.ident.clone();
|
let name = variant.ident.clone();
|
||||||
|
let ident = variant.ident.clone();
|
||||||
let span = variant.span();
|
let span = variant.span();
|
||||||
let ty = match variant.fields {
|
let ty = match variant.fields {
|
||||||
syn::Fields::Unnamed(syn::FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
|
syn::Fields::Unnamed(syn::FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
|
||||||
|
@ -126,7 +131,14 @@ impl Item {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let kind = Sp::new(Kind::Command(ty), span);
|
let kind = Sp::new(Kind::Command(ty), span);
|
||||||
let mut res = Self::new(Name::Derived(name), None, struct_casing, env_casing, kind);
|
let mut res = Self::new(
|
||||||
|
Name::Derived(name),
|
||||||
|
ident,
|
||||||
|
None,
|
||||||
|
struct_casing,
|
||||||
|
env_casing,
|
||||||
|
kind,
|
||||||
|
);
|
||||||
let parsed_attrs = ClapAttr::parse_all(&variant.attrs);
|
let parsed_attrs = ClapAttr::parse_all(&variant.attrs);
|
||||||
res.infer_kind(&parsed_attrs);
|
res.infer_kind(&parsed_attrs);
|
||||||
res.push_attrs(&parsed_attrs);
|
res.push_attrs(&parsed_attrs);
|
||||||
|
@ -161,10 +173,12 @@ impl Item {
|
||||||
argument_casing: Sp<CasingStyle>,
|
argument_casing: Sp<CasingStyle>,
|
||||||
env_casing: Sp<CasingStyle>,
|
env_casing: Sp<CasingStyle>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let ident = variant.ident.clone();
|
||||||
let span = variant.span();
|
let span = variant.span();
|
||||||
let kind = Sp::new(Kind::Value, span);
|
let kind = Sp::new(Kind::Value, span);
|
||||||
let mut res = Self::new(
|
let mut res = Self::new(
|
||||||
Name::Derived(variant.ident.clone()),
|
Name::Derived(variant.ident.clone()),
|
||||||
|
ident,
|
||||||
None,
|
None,
|
||||||
argument_casing,
|
argument_casing,
|
||||||
env_casing,
|
env_casing,
|
||||||
|
@ -186,11 +200,13 @@ 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 ident = field.ident.clone().unwrap();
|
||||||
let span = field.span();
|
let span = field.span();
|
||||||
let ty = Ty::from_syn_ty(&field.ty);
|
let ty = Ty::from_syn_ty(&field.ty);
|
||||||
let kind = Sp::new(Kind::Arg(ty), span);
|
let kind = Sp::new(Kind::Arg(ty), span);
|
||||||
let mut res = Self::new(
|
let mut res = Self::new(
|
||||||
Name::Derived(name),
|
Name::Derived(name),
|
||||||
|
ident,
|
||||||
Some(field.ty.clone()),
|
Some(field.ty.clone()),
|
||||||
struct_casing,
|
struct_casing,
|
||||||
env_casing,
|
env_casing,
|
||||||
|
@ -234,6 +250,7 @@ impl Item {
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
name: Name,
|
name: Name,
|
||||||
|
ident: Ident,
|
||||||
ty: Option<Type>,
|
ty: Option<Type>,
|
||||||
casing: Sp<CasingStyle>,
|
casing: Sp<CasingStyle>,
|
||||||
env_casing: Sp<CasingStyle>,
|
env_casing: Sp<CasingStyle>,
|
||||||
|
@ -241,6 +258,7 @@ impl Item {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
|
ident,
|
||||||
ty,
|
ty,
|
||||||
casing,
|
casing,
|
||||||
env_casing,
|
env_casing,
|
||||||
|
@ -894,6 +912,10 @@ impl Item {
|
||||||
quote!( #(#next_help_heading)* )
|
quote!( #(#next_help_heading)* )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ident(&self) -> &Ident {
|
||||||
|
&self.ident
|
||||||
|
}
|
||||||
|
|
||||||
pub fn id(&self) -> TokenStream {
|
pub fn id(&self) -> TokenStream {
|
||||||
self.name.clone().raw()
|
self.name.clone().raw()
|
||||||
}
|
}
|
||||||
|
|
23
tests/derive/groups.rs
Normal file
23
tests/derive/groups.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
use clap::Parser;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_safely_nest_parser() {
|
||||||
|
#[derive(Parser, Debug, PartialEq)]
|
||||||
|
struct Opt {
|
||||||
|
#[command(flatten)]
|
||||||
|
foo: Foo,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Parser, Debug, PartialEq)]
|
||||||
|
struct Foo {
|
||||||
|
#[arg(long)]
|
||||||
|
foo: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Opt {
|
||||||
|
foo: Foo { foo: true }
|
||||||
|
},
|
||||||
|
Opt::try_parse_from(&["test", "--foo"]).unwrap()
|
||||||
|
);
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ mod explicit_name_no_renaming;
|
||||||
mod flags;
|
mod flags;
|
||||||
mod flatten;
|
mod flatten;
|
||||||
mod generic;
|
mod generic;
|
||||||
|
mod groups;
|
||||||
mod help;
|
mod help;
|
||||||
mod issues;
|
mod issues;
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use clap::Args;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -251,7 +252,7 @@ fn test_rename_all_is_not_propagated_from_struct_into_flattened() {
|
||||||
foo: Foo,
|
foo: Foo,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Parser, Debug, PartialEq)]
|
#[derive(Args, Debug, PartialEq)]
|
||||||
struct Foo {
|
struct Foo {
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
foo: bool,
|
foo: bool,
|
||||||
|
|
Loading…
Add table
Reference in a new issue