Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions clap_derive/src/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,23 @@ impl ClapAttr {
}
}
}

pub(crate) fn lit_bool_or_abort(&self) -> Result<bool, syn::Error> {
Comment thread
epage marked this conversation as resolved.
let value = self.value_or_abort()?;
match value {
AttrValue::Expr(Expr::Lit(syn::ExprLit {
lit: syn::Lit::Bool(lit),
..
})) => Ok(lit.value()),
_ => {
abort!(
self.name,
"attribute `{}` can only accept bool literals",
self.name
)
}
}
}
}

impl Parse for ClapAttr {
Expand Down Expand Up @@ -102,6 +119,7 @@ impl Parse for ClapAttr {
"long_help" => Some(MagicAttrName::LongHelp),
"author" => Some(MagicAttrName::Author),
"version" => Some(MagicAttrName::Version),
"defer" => Some(MagicAttrName::Defer),
_ => None,
};

Expand Down Expand Up @@ -168,6 +186,7 @@ pub(crate) enum MagicAttrName {
DefaultValuesOsT,
NextDisplayOrder,
NextHelpHeading,
Defer,
}

#[derive(Clone)]
Expand Down
15 changes: 9 additions & 6 deletions clap_derive/src/derives/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ pub(crate) fn gen_for_struct(
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 initial_app_methods = item.initial_top_level_methods();
let final_app_methods = item.final_top_level_methods();
Comment on lines +80 to +81
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intention would be that we would do this consistently across all derives

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok both callers now apply initial/final uniformly. Added here 560fef5 (this PR)


let group_id = if item.skip_group() {
quote!(None)
Expand Down Expand Up @@ -155,10 +157,14 @@ pub(crate) fn gen_for_struct(
#group_id
}
fn augment_args<'b>(#app_var: clap::Command) -> clap::Command {
#augmentation
let #app_var = #app_var #initial_app_methods;
let #app_var = #augmentation;
#app_var #final_app_methods
}
fn augment_args_for_update<'b>(#app_var: clap::Command) -> clap::Command {
#augmentation_update
let #app_var = #app_var #initial_app_methods;
let #app_var = #augmentation_update;
#app_var #final_app_methods
}
}
})
Expand Down Expand Up @@ -380,8 +386,6 @@ pub(crate) fn gen_augment(
} 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 {
Expand Down Expand Up @@ -432,11 +436,10 @@ pub(crate) fn gen_augment(
Ok(quote! {{
#deprecations
let #app_var = #app_var
#initial_app_methods
#group_app_methods
;
#( #args )*
#app_var #final_app_methods
#app_var
}})
}

Expand Down
71 changes: 41 additions & 30 deletions clap_derive/src/derives/subcommand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ pub(crate) fn gen_for_enum(
let augmentation = gen_augment(variants, item, false)?;
let augmentation_update = gen_augment(variants, item, true)?;
let has_subcommand = gen_has_subcommand(variants)?;
let initial_app_methods = item.initial_top_level_methods();
let final_app_methods = item.final_top_level_methods();

Ok(quote! {
#[allow(
Expand Down Expand Up @@ -123,10 +125,14 @@ pub(crate) fn gen_for_enum(
#[automatically_derived]
impl #impl_generics clap::Subcommand for #item_name #ty_generics #where_clause {
fn augment_subcommands <'b>(__clap_app: clap::Command) -> clap::Command {
#augmentation
let __clap_app = __clap_app #initial_app_methods;
let __clap_app = #augmentation;
__clap_app #final_app_methods
}
fn augment_subcommands_for_update <'b>(__clap_app: clap::Command) -> clap::Command {
#augmentation_update
let __clap_app = __clap_app #initial_app_methods;
let __clap_app = #augmentation_update;
__clap_app #final_app_methods
}
fn has_subcommand(__clap_name: &str) -> bool {
#has_subcommand
Expand Down Expand Up @@ -275,22 +281,22 @@ fn gen_augment(

Kind::Command(_) => {
let subcommand_var = Ident::new("__clap_subcommand", Span::call_site());
let sub_augment = match variant.fields {
let (sub_augment, initial_app_methods, final_from_attrs) = match variant.fields {
Comment thread
epage marked this conversation as resolved.
Named(ref fields) => {
// Defer to `gen_augment` for adding cmd methods
let fields = collect_args_fields(item, fields)?;
args::gen_augment(&fields, &subcommand_var, item, override_required)?
}
Unit => {
let arg_block = quote!( #subcommand_var );
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;
#subcommand_var #final_from_attrs
}
let sub_augment =
args::gen_augment(&fields, &subcommand_var, item, override_required)?;
(
sub_augment,
item.initial_top_level_methods(),
item.final_top_level_methods(),
)
}
Unit => (
quote! { #subcommand_var },
item.initial_top_level_methods(),
item.final_top_level_methods(),
),
Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
let ty = &unnamed[0].ty;
let arg_block = if override_required {
Expand All @@ -306,19 +312,25 @@ fn gen_augment(
}
}
};
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;
#subcommand_var #final_from_attrs
}
(
arg_block,
item.initial_top_level_methods(),
item.final_top_level_methods(),
)
}
Unnamed(..) => {
abort!(variant, "invalid variant for `#[command(subcommand)]`, expected a newtype variant")
}
};

let sub_augment = if parent_item.defer() {
quote! {
#subcommand_var.defer(|#subcommand_var| { #sub_augment })
}
} else {
sub_augment
};
Comment thread
r-near marked this conversation as resolved.
Comment on lines +326 to +332
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't seem to do this for Args. We're missing a test case for this.

Looking back at #6225, I see deferring of arguments discussed at #6225 (comment)

This is causing me to look back at #4959 where new trait methods are suggested and I'm wondering why I suggested those originally and if there is some missing functionality, e.g. around flatten.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a test case for this.

So for the current scope, I think flatten is covered under deferred subcommands, right?

The extra trait-method ideas from #4959 seem like broader defer semantics. IDK if you wanna add that into this PR?


let deprecations = if !override_required {
item.deprecations()
} else {
Expand All @@ -328,8 +340,10 @@ fn gen_augment(
let subcommand = quote! {
let #app_var = #app_var.subcommand({
#deprecations
let #subcommand_var = clap::Command::new(#name);
#sub_augment
let #subcommand_var = clap::Command::new(#name)
#initial_app_methods;
let #subcommand_var = #sub_augment;
#subcommand_var #final_from_attrs
});
};
Some(subcommand)
Expand All @@ -343,14 +357,11 @@ fn gen_augment(
} else {
quote!()
};
let initial_app_methods = parent_item.initial_top_level_methods();
let final_app_methods = parent_item.final_top_level_methods();
Ok(quote! {
Ok(quote! {{
#deprecations;
let #app_var = #app_var #initial_app_methods;
#( #subcommands )*;
#app_var #final_app_methods
})
#app_var
}})
}

fn gen_has_subcommand(variants: &[(&Variant, Item)]) -> Result<TokenStream, syn::Error> {
Expand Down
11 changes: 11 additions & 0 deletions clap_derive/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pub(crate) struct Item {
group_id: Name,
group_methods: Vec<Method>,
kind: Sp<Kind>,
defer: bool,
}

impl Item {
Expand Down Expand Up @@ -279,6 +280,7 @@ impl Item {
group_id,
group_methods: vec![],
kind,
defer: cfg!(feature = "unstable-v5"),
}
}

Expand Down Expand Up @@ -835,6 +837,11 @@ impl Item {
self.skip_group = true;
}

Some(MagicAttrName::Defer) => {
assert_attr_kind(attr, &[AttrKind::Command])?;
self.defer = attr.lit_bool_or_abort()?;
}

None
// Magic only for the default, otherwise just forward to the builder
| Some(MagicAttrName::Short)
Expand Down Expand Up @@ -1090,6 +1097,10 @@ impl Item {
pub(crate) fn skip_group(&self) -> bool {
self.skip_group
}

pub(crate) fn defer(&self) -> bool {
self.defer
}
}

#[derive(Clone)]
Expand Down
Loading
Loading