-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat(derive): Add #[command(defer)] for lazy subcommand initialization #6256
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
057aef7
e6e635d
33ab745
2f7917c
531fdd5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok both callers now apply initial/final uniformly. Added here |
||
|
|
||
| let group_id = if item.skip_group() { | ||
| quote!(None) | ||
|
|
@@ -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 | ||
| } | ||
| } | ||
| }) | ||
|
|
@@ -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 { | ||
|
|
@@ -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 | ||
| }}) | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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( | ||
|
|
@@ -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 | ||
|
|
@@ -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 { | ||
|
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 { | ||
|
|
@@ -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 | ||
| }; | ||
|
r-near marked this conversation as resolved.
Comment on lines
+326
to
+332
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't seem to do this for 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.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 { | ||
|
|
@@ -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) | ||
|
|
@@ -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> { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.