mirror of
https://github.com/clap-rs/clap
synced 2024-12-15 07:12:32 +00:00
Merge pull request #1878 from lu-zero/update_from_arg_matches
Add update_from_arg_matches to FromArgMatches
This commit is contained in:
commit
821d79aac7
10 changed files with 562 additions and 166 deletions
|
@ -18,7 +18,7 @@ use syn::{punctuated::Punctuated, spanned::Spanned, token::Comma, Field, Ident,
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
attrs::{Attrs, Kind, ParserKind},
|
attrs::{Attrs, Kind, ParserKind},
|
||||||
utils::{sub_type, subty_if_name, Ty},
|
utils::{sub_type, subty_if_name, Sp, Ty},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn gen_for_struct(
|
pub fn gen_for_struct(
|
||||||
|
@ -27,6 +27,7 @@ pub fn gen_for_struct(
|
||||||
parent_attribute: &Attrs,
|
parent_attribute: &Attrs,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let constructor = gen_constructor(fields, parent_attribute);
|
let constructor = gen_constructor(fields, parent_attribute);
|
||||||
|
let updater = gen_updater(fields, parent_attribute, true);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#[allow(dead_code, unreachable_code, unused_variables)]
|
#[allow(dead_code, unreachable_code, unused_variables)]
|
||||||
|
@ -45,6 +46,10 @@ pub fn gen_for_struct(
|
||||||
fn from_arg_matches(matches: &::clap::ArgMatches) -> Self {
|
fn from_arg_matches(matches: &::clap::ArgMatches) -> Self {
|
||||||
#struct_name #constructor
|
#struct_name #constructor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_from_arg_matches(&mut self, matches: &::clap::ArgMatches) {
|
||||||
|
#updater
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,6 +72,9 @@ pub fn gen_for_enum(name: &Ident) -> TokenStream {
|
||||||
fn from_arg_matches(matches: &::clap::ArgMatches) -> Self {
|
fn from_arg_matches(matches: &::clap::ArgMatches) -> Self {
|
||||||
<#name as ::clap::Subcommand>::from_subcommand(matches.subcommand()).unwrap()
|
<#name as ::clap::Subcommand>::from_subcommand(matches.subcommand()).unwrap()
|
||||||
}
|
}
|
||||||
|
fn update_from_arg_matches(&mut self, matches: &::clap::ArgMatches) {
|
||||||
|
<#name as ::clap::Subcommand>::update_from_subcommand(self, matches.subcommand());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,6 +87,142 @@ fn gen_arg_enum_parse(ty: &Type, attrs: &Attrs) -> TokenStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn gen_parsers(
|
||||||
|
attrs: &Attrs,
|
||||||
|
ty: &Sp<Ty>,
|
||||||
|
field_name: &Ident,
|
||||||
|
field: &Field,
|
||||||
|
update: Option<&TokenStream>,
|
||||||
|
) -> TokenStream {
|
||||||
|
use self::ParserKind::*;
|
||||||
|
|
||||||
|
let parser = attrs.parser();
|
||||||
|
let func = &parser.func;
|
||||||
|
let span = parser.kind.span();
|
||||||
|
let (value_of, values_of, mut parse) = match *parser.kind {
|
||||||
|
FromStr => (
|
||||||
|
quote_spanned!(span=> value_of),
|
||||||
|
quote_spanned!(span=> values_of),
|
||||||
|
func.clone(),
|
||||||
|
),
|
||||||
|
TryFromStr => (
|
||||||
|
quote_spanned!(span=> value_of),
|
||||||
|
quote_spanned!(span=> values_of),
|
||||||
|
quote_spanned!(func.span()=> |s| #func(s).unwrap()),
|
||||||
|
),
|
||||||
|
FromOsStr => (
|
||||||
|
quote_spanned!(span=> value_of_os),
|
||||||
|
quote_spanned!(span=> values_of_os),
|
||||||
|
func.clone(),
|
||||||
|
),
|
||||||
|
TryFromOsStr => (
|
||||||
|
quote_spanned!(span=> value_of_os),
|
||||||
|
quote_spanned!(span=> values_of_os),
|
||||||
|
quote_spanned!(func.span()=> |s| #func(s).unwrap()),
|
||||||
|
),
|
||||||
|
FromOccurrences => (
|
||||||
|
quote_spanned!(span=> occurrences_of),
|
||||||
|
quote!(),
|
||||||
|
func.clone(),
|
||||||
|
),
|
||||||
|
FromFlag => (quote!(), quote!(), func.clone()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let flag = *attrs.parser().kind == ParserKind::FromFlag;
|
||||||
|
let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
|
||||||
|
let name = attrs.cased_name();
|
||||||
|
|
||||||
|
let field_value = match **ty {
|
||||||
|
Ty::Bool => {
|
||||||
|
if update.is_some() {
|
||||||
|
quote_spanned! { ty.span()=>
|
||||||
|
*#field_name || matches.is_present(#name)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote_spanned! { ty.span()=>
|
||||||
|
matches.is_present(#name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ty::Option => {
|
||||||
|
if attrs.is_enum() {
|
||||||
|
if let Some(subty) = subty_if_name(&field.ty, "Option") {
|
||||||
|
parse = gen_arg_enum_parse(subty, &attrs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quote_spanned! { ty.span()=>
|
||||||
|
matches.#value_of(#name)
|
||||||
|
.map(#parse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ty::OptionOption => quote_spanned! { ty.span()=>
|
||||||
|
if matches.is_present(#name) {
|
||||||
|
Some(matches.#value_of(#name).map(#parse))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
Ty::OptionVec => quote_spanned! { ty.span()=>
|
||||||
|
if matches.is_present(#name) {
|
||||||
|
Some(matches.#values_of(#name)
|
||||||
|
.map(|v| v.map(#parse).collect())
|
||||||
|
.unwrap_or_else(Vec::new))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
Ty::Vec => {
|
||||||
|
if attrs.is_enum() {
|
||||||
|
if let Some(subty) = subty_if_name(&field.ty, "Vec") {
|
||||||
|
parse = gen_arg_enum_parse(subty, &attrs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quote_spanned! { ty.span()=>
|
||||||
|
matches.#values_of(#name)
|
||||||
|
.map(|v| v.map(#parse).collect())
|
||||||
|
.unwrap_or_else(Vec::new)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ty::Other if occurrences => quote_spanned! { ty.span()=>
|
||||||
|
#parse(matches.#value_of(#name))
|
||||||
|
},
|
||||||
|
|
||||||
|
Ty::Other if flag => quote_spanned! { ty.span()=>
|
||||||
|
#parse(matches.is_present(#name))
|
||||||
|
},
|
||||||
|
|
||||||
|
Ty::Other => {
|
||||||
|
if attrs.is_enum() {
|
||||||
|
parse = gen_arg_enum_parse(&field.ty, &attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
quote_spanned! { ty.span()=>
|
||||||
|
matches.#value_of(#name)
|
||||||
|
.map(#parse)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(access) = update {
|
||||||
|
quote_spanned! { field.span()=>
|
||||||
|
if matches.is_present(#name) {
|
||||||
|
#access
|
||||||
|
*#field_name = #field_value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote_spanned!(field.span()=> #field_name: #field_value )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs) -> TokenStream {
|
pub fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs) -> TokenStream {
|
||||||
let fields = fields.iter().map(|field| {
|
let fields = fields.iter().map(|field| {
|
||||||
let attrs = Attrs::from_field(
|
let attrs = Attrs::from_field(
|
||||||
|
@ -120,118 +264,7 @@ pub fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Att
|
||||||
Some(val) => quote_spanned!(kind.span()=> #field_name: (#val).into()),
|
Some(val) => quote_spanned!(kind.span()=> #field_name: (#val).into()),
|
||||||
},
|
},
|
||||||
|
|
||||||
Kind::Arg(ty) => {
|
Kind::Arg(ty) => gen_parsers(&attrs, ty, field_name, field, None),
|
||||||
use self::ParserKind::*;
|
|
||||||
|
|
||||||
let parser = attrs.parser();
|
|
||||||
let func = &parser.func;
|
|
||||||
let span = parser.kind.span();
|
|
||||||
let (value_of, values_of, mut parse) = match *parser.kind {
|
|
||||||
FromStr => (
|
|
||||||
quote_spanned!(span=> value_of),
|
|
||||||
quote_spanned!(span=> values_of),
|
|
||||||
func.clone(),
|
|
||||||
),
|
|
||||||
TryFromStr => (
|
|
||||||
quote_spanned!(span=> value_of),
|
|
||||||
quote_spanned!(span=> values_of),
|
|
||||||
quote_spanned!(func.span()=> |s| #func(s).unwrap()),
|
|
||||||
),
|
|
||||||
FromOsStr => (
|
|
||||||
quote_spanned!(span=> value_of_os),
|
|
||||||
quote_spanned!(span=> values_of_os),
|
|
||||||
func.clone(),
|
|
||||||
),
|
|
||||||
TryFromOsStr => (
|
|
||||||
quote_spanned!(span=> value_of_os),
|
|
||||||
quote_spanned!(span=> values_of_os),
|
|
||||||
quote_spanned!(func.span()=> |s| #func(s).unwrap()),
|
|
||||||
),
|
|
||||||
FromOccurrences => (
|
|
||||||
quote_spanned!(span=> occurrences_of),
|
|
||||||
quote!(),
|
|
||||||
func.clone(),
|
|
||||||
),
|
|
||||||
FromFlag => (quote!(), quote!(), func.clone()),
|
|
||||||
};
|
|
||||||
|
|
||||||
let flag = *attrs.parser().kind == ParserKind::FromFlag;
|
|
||||||
let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
|
|
||||||
let name = attrs.cased_name();
|
|
||||||
|
|
||||||
let field_value = match **ty {
|
|
||||||
Ty::Bool => quote_spanned! { ty.span()=>
|
|
||||||
matches.is_present(#name)
|
|
||||||
},
|
|
||||||
|
|
||||||
Ty::Option => {
|
|
||||||
if attrs.is_enum() {
|
|
||||||
if let Some(subty) = subty_if_name(&field.ty, "Option") {
|
|
||||||
parse = gen_arg_enum_parse(subty, &attrs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
quote_spanned! { ty.span()=>
|
|
||||||
matches.#value_of(#name)
|
|
||||||
.map(#parse)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ty::OptionOption => quote_spanned! { ty.span()=>
|
|
||||||
if matches.is_present(#name) {
|
|
||||||
Some(matches.#value_of(#name).map(#parse))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
Ty::OptionVec => quote_spanned! { ty.span()=>
|
|
||||||
if matches.is_present(#name) {
|
|
||||||
Some(matches.#values_of(#name)
|
|
||||||
.map(|v| v.map(#parse).collect())
|
|
||||||
.unwrap_or_else(Vec::new))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
Ty::Vec => {
|
|
||||||
if attrs.is_enum() {
|
|
||||||
if let Some(subty) = subty_if_name(&field.ty, "Vec") {
|
|
||||||
parse = gen_arg_enum_parse(subty, &attrs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
quote_spanned! { ty.span()=>
|
|
||||||
matches.#values_of(#name)
|
|
||||||
.map(|v| v.map(#parse).collect())
|
|
||||||
.unwrap_or_else(Vec::new)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ty::Other if occurrences => quote_spanned! { ty.span()=>
|
|
||||||
#parse(matches.#value_of(#name))
|
|
||||||
},
|
|
||||||
|
|
||||||
Ty::Other if flag => quote_spanned! { ty.span()=>
|
|
||||||
#parse(matches.is_present(#name))
|
|
||||||
},
|
|
||||||
|
|
||||||
Ty::Other => {
|
|
||||||
if attrs.is_enum() {
|
|
||||||
parse = gen_arg_enum_parse(&field.ty, &attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
quote_spanned! { ty.span()=>
|
|
||||||
matches.#value_of(#name)
|
|
||||||
.map(#parse)
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
quote_spanned!(field.span()=> #field_name: #field_value )
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -239,3 +272,85 @@ pub fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Att
|
||||||
#( #fields ),*
|
#( #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!()
|
||||||
|
};
|
||||||
|
|
||||||
|
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, subcmd);
|
||||||
|
};
|
||||||
|
|
||||||
|
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(
|
||||||
|
subcmd
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => quote_spanned!{ kind.span()=>
|
||||||
|
#updater
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
quote_spanned! { kind.span()=>
|
||||||
|
{
|
||||||
|
let subcmd = matches.subcommand();
|
||||||
|
#access
|
||||||
|
#updater
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Kind::Flatten => quote_spanned! { kind.span()=> {
|
||||||
|
#access
|
||||||
|
::clap::FromArgMatches::update_from_arg_matches(#field_name, matches);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
Kind::Skip(_) => quote!(),
|
||||||
|
|
||||||
|
Kind::Arg(ty) => {
|
||||||
|
gen_parsers(&attrs, ty, field_name, field, Some(&access))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#( #fields )*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -103,6 +103,15 @@ pub fn gen_for_enum(name: &Ident) -> TokenStream {
|
||||||
fn augment_clap<'b>(app: ::clap::App<'b>) -> ::clap::App<'b> {
|
fn augment_clap<'b>(app: ::clap::App<'b>) -> ::clap::App<'b> {
|
||||||
<#name as ::clap::Subcommand>::augment_subcommands(app)
|
<#name as ::clap::Subcommand>::augment_subcommands(app)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn into_app_for_update<'b>() -> ::clap::App<'b> {
|
||||||
|
let app = ::clap::App::new(#app_name);
|
||||||
|
<#name as ::clap::IntoApp>::augment_clap_for_update(app)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn augment_clap_for_update<'b>(app: ::clap::App<'b>) -> ::clap::App<'b> {
|
||||||
|
<#name as ::clap::Subcommand>::augment_subcommands_for_update(app)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,6 +132,9 @@ fn gen_into_app_fn(attrs: &[Attribute]) -> GenOutput {
|
||||||
fn into_app<'b>() -> ::clap::App<'b> {
|
fn into_app<'b>() -> ::clap::App<'b> {
|
||||||
Self::augment_clap(::clap::App::new(#name))
|
Self::augment_clap(::clap::App::new(#name))
|
||||||
}
|
}
|
||||||
|
fn into_app_for_update<'b>() -> ::clap::App<'b> {
|
||||||
|
Self::augment_clap_for_update(::clap::App::new(#name))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
(tokens, attrs)
|
(tokens, attrs)
|
||||||
|
@ -130,11 +142,15 @@ fn gen_into_app_fn(attrs: &[Attribute]) -> GenOutput {
|
||||||
|
|
||||||
fn gen_augment_clap_fn(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs) -> TokenStream {
|
fn gen_augment_clap_fn(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs) -> TokenStream {
|
||||||
let app_var = Ident::new("app", Span::call_site());
|
let app_var = Ident::new("app", Span::call_site());
|
||||||
let augmentation = gen_app_augmentation(fields, &app_var, parent_attribute);
|
let augmentation = gen_app_augmentation(fields, &app_var, parent_attribute, false);
|
||||||
|
let augmentation_update = gen_app_augmentation(fields, &app_var, parent_attribute, true);
|
||||||
quote! {
|
quote! {
|
||||||
fn augment_clap<'b>(#app_var: ::clap::App<'b>) -> ::clap::App<'b> {
|
fn augment_clap<'b>(#app_var: ::clap::App<'b>) -> ::clap::App<'b> {
|
||||||
#augmentation
|
#augmentation
|
||||||
}
|
}
|
||||||
|
fn augment_clap_for_update<'b>(#app_var: ::clap::App<'b>) -> ::clap::App<'b> {
|
||||||
|
#augmentation_update
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,6 +166,7 @@ pub fn gen_app_augmentation(
|
||||||
fields: &Punctuated<Field, Comma>,
|
fields: &Punctuated<Field, Comma>,
|
||||||
app_var: &Ident,
|
app_var: &Ident,
|
||||||
parent_attribute: &Attrs,
|
parent_attribute: &Attrs,
|
||||||
|
override_required: bool,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let mut subcmds = fields.iter().filter_map(|field| {
|
let mut subcmds = fields.iter().filter_map(|field| {
|
||||||
let attrs = Attrs::from_field(
|
let attrs = Attrs::from_field(
|
||||||
|
@ -174,9 +191,15 @@ pub fn gen_app_augmentation(
|
||||||
};
|
};
|
||||||
|
|
||||||
let span = field.span();
|
let span = field.span();
|
||||||
let ts = quote! {
|
let ts = if override_required {
|
||||||
let #app_var = <#subcmd_type as ::clap::Subcommand>::augment_subcommands( #app_var );
|
quote! {
|
||||||
#required
|
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))
|
Some((span, ts))
|
||||||
} else {
|
} else {
|
||||||
|
@ -296,7 +319,7 @@ pub fn gen_app_augmentation(
|
||||||
},
|
},
|
||||||
|
|
||||||
Ty::Other => {
|
Ty::Other => {
|
||||||
let required = !attrs.has_method("default_value");
|
let required = !attrs.has_method("default_value") && !override_required;
|
||||||
let mut possible_values = quote!();
|
let mut possible_values = quote!();
|
||||||
|
|
||||||
if attrs.is_enum() {
|
if attrs.is_enum() {
|
||||||
|
|
|
@ -33,8 +33,11 @@ pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStr
|
||||||
Sp::call_site(DEFAULT_ENV_CASING),
|
Sp::call_site(DEFAULT_ENV_CASING),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let augment_subcommands = gen_augment("augment_subcommands", &e.variants, &attrs, false);
|
||||||
|
let augment_subcommands_for_update =
|
||||||
|
gen_augment("augment_subcommands_for_update", &e.variants, &attrs, true);
|
||||||
let from_subcommand = gen_from_subcommand(name, &e.variants, &attrs);
|
let from_subcommand = gen_from_subcommand(name, &e.variants, &attrs);
|
||||||
let augment_subcommands = gen_augment_subcommands(&e.variants, &attrs);
|
let update_from_subcommand = gen_update_from_subcommand(name, &e.variants, &attrs);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#[allow(dead_code, unreachable_code, unused_variables)]
|
#[allow(dead_code, unreachable_code, unused_variables)]
|
||||||
|
@ -52,13 +55,17 @@ pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStr
|
||||||
impl ::clap::Subcommand for #name {
|
impl ::clap::Subcommand for #name {
|
||||||
#augment_subcommands
|
#augment_subcommands
|
||||||
#from_subcommand
|
#from_subcommand
|
||||||
|
#augment_subcommands_for_update
|
||||||
|
#update_from_subcommand
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_augment_subcommands(
|
fn gen_augment(
|
||||||
|
fn_name: &str,
|
||||||
variants: &Punctuated<Variant, Token![,]>,
|
variants: &Punctuated<Variant, Token![,]>,
|
||||||
parent_attribute: &Attrs,
|
parent_attribute: &Attrs,
|
||||||
|
override_required: bool,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
use syn::Fields::*;
|
use syn::Fields::*;
|
||||||
|
|
||||||
|
@ -97,9 +104,12 @@ fn gen_augment_subcommands(
|
||||||
_ => {
|
_ => {
|
||||||
let app_var = Ident::new("subcommand", Span::call_site());
|
let app_var = Ident::new("subcommand", Span::call_site());
|
||||||
let arg_block = match variant.fields {
|
let arg_block = match variant.fields {
|
||||||
Named(ref fields) => {
|
Named(ref fields) => into_app::gen_app_augmentation(
|
||||||
into_app::gen_app_augmentation(&fields.named, &app_var, &attrs)
|
&fields.named,
|
||||||
}
|
&app_var,
|
||||||
|
&attrs,
|
||||||
|
override_required,
|
||||||
|
),
|
||||||
Unit => quote!( #app_var ),
|
Unit => quote!( #app_var ),
|
||||||
Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
|
Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
|
||||||
let ty = &unnamed[0];
|
let ty = &unnamed[0];
|
||||||
|
@ -131,8 +141,9 @@ fn gen_augment_subcommands(
|
||||||
|
|
||||||
let app_methods = parent_attribute.top_level_methods();
|
let app_methods = parent_attribute.top_level_methods();
|
||||||
let version = parent_attribute.version();
|
let version = parent_attribute.version();
|
||||||
|
let fn_name = Ident::new(fn_name, Span::call_site());
|
||||||
quote! {
|
quote! {
|
||||||
fn augment_subcommands<'b>(app: ::clap::App<'b>) -> ::clap::App<'b> {
|
fn #fn_name <'b>(app: ::clap::App<'b>) -> ::clap::App<'b> {
|
||||||
let app = app #app_methods;
|
let app = app #app_methods;
|
||||||
#( #subcommands )*;
|
#( #subcommands )*;
|
||||||
app #version
|
app #version
|
||||||
|
@ -291,3 +302,116 @@ fn gen_from_subcommand(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn gen_update_from_subcommand(
|
||||||
|
name: &Ident,
|
||||||
|
variants: &Punctuated<Variant, Token![,]>,
|
||||||
|
parent_attribute: &Attrs,
|
||||||
|
) -> TokenStream {
|
||||||
|
use syn::Fields::*;
|
||||||
|
|
||||||
|
let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants
|
||||||
|
.iter()
|
||||||
|
.filter_map(|variant| {
|
||||||
|
let attrs = Attrs::from_struct(
|
||||||
|
variant.span(),
|
||||||
|
&variant.attrs,
|
||||||
|
Name::Derived(variant.ident.clone()),
|
||||||
|
parent_attribute.casing(),
|
||||||
|
parent_attribute.env_casing(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Kind::ExternalSubcommand = &*attrs.kind() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some((variant, attrs))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.partition(|(_, attrs)| {
|
||||||
|
let kind = attrs.kind();
|
||||||
|
matches!(&*kind, Kind::Flatten)
|
||||||
|
});
|
||||||
|
|
||||||
|
let subcommands = variants.iter().map(|(variant, attrs)| {
|
||||||
|
let sub_name = attrs.cased_name();
|
||||||
|
let variant_name = &variant.ident;
|
||||||
|
let (pattern, updater) = match variant.fields {
|
||||||
|
Named(ref fields) => {
|
||||||
|
let (fields, update): (Vec<_>, Vec<_>) = fields
|
||||||
|
.named
|
||||||
|
.iter()
|
||||||
|
.map(|field| {
|
||||||
|
let attrs = Attrs::from_field(
|
||||||
|
field,
|
||||||
|
parent_attribute.casing(),
|
||||||
|
parent_attribute.env_casing(),
|
||||||
|
);
|
||||||
|
let field_name = field.ident.as_ref().unwrap();
|
||||||
|
(
|
||||||
|
quote!( ref mut #field_name ),
|
||||||
|
from_arg_matches::gen_updater(&fields.named, &attrs, false),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unzip();
|
||||||
|
(quote!( { #( #fields, )* }), quote!( { #( #update )* } ))
|
||||||
|
}
|
||||||
|
Unit => (quote!(), quote!({})),
|
||||||
|
Unnamed(ref fields) => {
|
||||||
|
if fields.unnamed.len() == 1 {
|
||||||
|
(
|
||||||
|
quote!((ref mut arg)),
|
||||||
|
quote!(::clap::FromArgMatches::update_from_arg_matches(
|
||||||
|
arg, matches
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
abort_call_site!("{}: tuple enums are not supported", variant.ident)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
(#sub_name, #name :: #variant_name #pattern) => { #updater }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let child_subcommands = flatten_variants.iter().map(|(variant, attrs)| {
|
||||||
|
let sub_name = attrs.cased_name();
|
||||||
|
let variant_name = &variant.ident;
|
||||||
|
let (pattern, updater) = match variant.fields {
|
||||||
|
Unnamed(ref fields) if fields.unnamed.len() == 1 => {
|
||||||
|
let ty = &fields.unnamed[0];
|
||||||
|
(
|
||||||
|
quote!((ref mut arg)),
|
||||||
|
quote! {
|
||||||
|
<#ty as ::clap::Subcommand>::update_from_subcommand(arg, Some((name, matches)));
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => abort!(
|
||||||
|
variant,
|
||||||
|
"`flatten` is usable only with single-typed tuple variants"
|
||||||
|
),
|
||||||
|
};
|
||||||
|
quote! {
|
||||||
|
(#sub_name, #name :: #variant_name #pattern) => { #updater }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
fn update_from_subcommand<'b>(
|
||||||
|
&mut self,
|
||||||
|
subcommand: Option<(&str, &::clap::ArgMatches)>
|
||||||
|
) {
|
||||||
|
if let Some((name, matches)) = subcommand {
|
||||||
|
match (name, self) {
|
||||||
|
#( #subcommands ),*
|
||||||
|
#( #child_subcommands ),*
|
||||||
|
(_, s) => if let Some(sub) = <Self as ::clap::Subcommand>::from_subcommand(Some((name, matches))) {
|
||||||
|
*s = sub;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,12 @@ pub fn into_app(name: &Ident) {
|
||||||
fn augment_clap<'b>(_app: ::clap::App<'b>) -> ::clap::App<'b> {
|
fn augment_clap<'b>(_app: ::clap::App<'b>) -> ::clap::App<'b> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
fn into_app_for_update<'b>() -> ::clap::App<'b> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
fn augment_clap_for_update<'b>(_app: ::clap::App<'b>) -> ::clap::App<'b> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -37,6 +43,9 @@ pub fn from_arg_matches(name: &Ident) {
|
||||||
fn from_arg_matches(_m: &::clap::ArgMatches) -> Self {
|
fn from_arg_matches(_m: &::clap::ArgMatches) -> Self {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
fn update_from_arg_matches(&mut self, matches: &::clap::ArgMatches) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -47,9 +56,15 @@ pub fn subcommand(name: &Ident) {
|
||||||
fn from_subcommand(_sub: Option<(&str, &::clap::ArgMatches)>) -> Option<Self> {
|
fn from_subcommand(_sub: Option<(&str, &::clap::ArgMatches)>) -> Option<Self> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
fn update_from_subcommand(&mut self, _sub: Option<(&str, &::clap::ArgMatches)>) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
fn augment_subcommands(_app: ::clap::App<'_>) -> ::clap::App<'_> {
|
fn augment_subcommands(_app: ::clap::App<'_>) -> ::clap::App<'_> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
fn augment_subcommands_for_update(_app: ::clap::App<'_>) -> ::clap::App<'_> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,21 @@ fn basic() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn update_basic() {
|
||||||
|
#[derive(Clap, PartialEq, Debug)]
|
||||||
|
struct Opt {
|
||||||
|
#[clap(short = 'a', long = "arg")]
|
||||||
|
single_value: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut opt = Opt::parse_from(&["test", "-a0"]);
|
||||||
|
|
||||||
|
opt.update_from(&["test", "-a42"]);
|
||||||
|
|
||||||
|
assert_eq!(Opt { single_value: 42 }, opt);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn unit_struct() {
|
fn unit_struct() {
|
||||||
#[derive(Clap, PartialEq, Debug)]
|
#[derive(Clap, PartialEq, Debug)]
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
use clap::Clap;
|
use clap::Clap;
|
||||||
|
|
||||||
|
#[derive(Clap, PartialEq, Debug)]
|
||||||
|
struct Opt {
|
||||||
|
#[clap(subcommand)]
|
||||||
|
sub: Box<Sub>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clap, PartialEq, Debug)]
|
||||||
|
enum Sub {
|
||||||
|
Flame {
|
||||||
|
#[clap(flatten)]
|
||||||
|
arg: Box<Ext>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clap, PartialEq, Debug)]
|
||||||
|
struct Ext {
|
||||||
|
arg: u32,
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn boxed_flatten_subcommand() {
|
fn boxed_flatten_subcommand() {
|
||||||
#[derive(Clap, PartialEq, Debug)]
|
|
||||||
struct Opt {
|
|
||||||
#[clap(subcommand)]
|
|
||||||
sub: Box<Sub>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clap, PartialEq, Debug)]
|
|
||||||
enum Sub {
|
|
||||||
Flame {
|
|
||||||
#[clap(flatten)]
|
|
||||||
arg: Box<Ext>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clap, PartialEq, Debug)]
|
|
||||||
struct Ext {
|
|
||||||
arg: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Opt {
|
Opt {
|
||||||
sub: Box::new(Sub::Flame {
|
sub: Box::new(Sub::Flame {
|
||||||
|
@ -30,3 +30,19 @@ fn boxed_flatten_subcommand() {
|
||||||
Opt::parse_from(&["test", "flame", "1"])
|
Opt::parse_from(&["test", "flame", "1"])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn update_boxed_flatten_subcommand() {
|
||||||
|
let mut opt = Opt::parse_from(&["test", "flame", "1"]);
|
||||||
|
|
||||||
|
opt.update_from(&["test", "flame", "42"]);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Opt {
|
||||||
|
sub: Box::new(Sub::Flame {
|
||||||
|
arg: Box::new(Ext { arg: 42 })
|
||||||
|
})
|
||||||
|
},
|
||||||
|
opt
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -133,6 +133,28 @@ fn test_every_custom_parser() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn update_every_custom_parser() {
|
||||||
|
let mut opt = NoOpOpt {
|
||||||
|
a: "0",
|
||||||
|
b: "0",
|
||||||
|
c: "0",
|
||||||
|
d: "D",
|
||||||
|
};
|
||||||
|
|
||||||
|
opt.update_from(&["test", "-a=?", "-b=?", "-d=?"]);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
NoOpOpt {
|
||||||
|
a: "A",
|
||||||
|
b: "B",
|
||||||
|
c: "0",
|
||||||
|
d: "D"
|
||||||
|
},
|
||||||
|
opt
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Note: can't use `Vec<u8>` directly, as clap would instead look for
|
// Note: can't use `Vec<u8>` directly, as clap would instead look for
|
||||||
// conversion function from `&str` to `u8`.
|
// conversion function from `&str` to `u8`.
|
||||||
type Bytes = Vec<u8>;
|
type Bytes = Vec<u8>;
|
||||||
|
|
|
@ -99,30 +99,30 @@ fn flatten_in_subcommand() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clap, PartialEq, Debug)]
|
||||||
|
enum BaseCli {
|
||||||
|
Command1(Command1),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clap, PartialEq, Debug)]
|
||||||
|
struct Command1 {
|
||||||
|
arg1: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clap, PartialEq, Debug)]
|
||||||
|
struct Command2 {
|
||||||
|
arg2: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clap, PartialEq, Debug)]
|
||||||
|
enum Opt {
|
||||||
|
#[clap(flatten)]
|
||||||
|
BaseCli(BaseCli),
|
||||||
|
Command2(Command2),
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn merge_subcommands_with_flatten() {
|
fn merge_subcommands_with_flatten() {
|
||||||
#[derive(Clap, PartialEq, Debug)]
|
|
||||||
enum BaseCli {
|
|
||||||
Command1(Command1),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clap, PartialEq, Debug)]
|
|
||||||
struct Command1 {
|
|
||||||
arg1: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clap, PartialEq, Debug)]
|
|
||||||
struct Command2 {
|
|
||||||
arg2: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clap, PartialEq, Debug)]
|
|
||||||
enum Opt {
|
|
||||||
#[clap(flatten)]
|
|
||||||
BaseCli(BaseCli),
|
|
||||||
Command2(Command2),
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Opt::BaseCli(BaseCli::Command1(Command1 { arg1: 42 })),
|
Opt::BaseCli(BaseCli::Command1(Command1 { arg1: 42 })),
|
||||||
Opt::parse_from(&["test", "command1", "42"])
|
Opt::parse_from(&["test", "command1", "42"])
|
||||||
|
@ -151,3 +151,12 @@ fn flatten_with_doc_comment() {
|
||||||
opts: DaemonOpts,
|
opts: DaemonOpts,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn update_subcommands_with_flatten() {
|
||||||
|
let mut opt = Opt::BaseCli(BaseCli::Command1(Command1 { arg1: 12 }));
|
||||||
|
opt.update_from(&["test", "command1", "42"]);
|
||||||
|
assert_eq!(Opt::parse_from(&["test", "command1", "42"]), opt);
|
||||||
|
opt.update_from(&["test", "command2", "43"]);
|
||||||
|
assert_eq!(Opt::parse_from(&["test", "command2", "43"]), opt);
|
||||||
|
}
|
||||||
|
|
|
@ -19,13 +19,20 @@ fn skip_1() {
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(Opt::try_parse_from(&["test", "-x", "10", "20"]).is_err());
|
assert!(Opt::try_parse_from(&["test", "-x", "10", "20"]).is_err());
|
||||||
|
|
||||||
|
let mut opt = Opt::parse_from(&["test", "-x", "10"]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Opt::parse_from(&["test", "-x", "10"]),
|
opt,
|
||||||
Opt {
|
Opt {
|
||||||
x: 10,
|
x: 10,
|
||||||
s: 0, // default
|
s: 0, // default
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
opt.s = 42;
|
||||||
|
|
||||||
|
opt.update_from(&["test", "-x", "22"]);
|
||||||
|
|
||||||
|
assert_eq!(opt, Opt { x: 22, s: 42 });
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -104,6 +104,30 @@ pub trait Clap: FromArgMatches + IntoApp + Sized {
|
||||||
let matches = <Self as IntoApp>::into_app().try_get_matches_from(itr)?;
|
let matches = <Self as IntoApp>::into_app().try_get_matches_from(itr)?;
|
||||||
Ok(<Self as FromArgMatches>::from_arg_matches(&matches))
|
Ok(<Self as FromArgMatches>::from_arg_matches(&matches))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update from iterator, exit on error
|
||||||
|
fn update_from<I, T>(&mut self, itr: I)
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = T>,
|
||||||
|
// TODO (@CreepySkeleton): discover a way to avoid cloning here
|
||||||
|
T: Into<OsString> + Clone,
|
||||||
|
{
|
||||||
|
// TODO find a way to get partial matches
|
||||||
|
let matches = <Self as IntoApp>::into_app_for_update().get_matches_from(itr);
|
||||||
|
<Self as FromArgMatches>::update_from_arg_matches(self, &matches);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update from iterator, return Err on error.
|
||||||
|
fn try_update_from<I, T>(&mut self, itr: I) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = T>,
|
||||||
|
// TODO (@CreepySkeleton): discover a way to avoid cloning here
|
||||||
|
T: Into<OsString> + Clone,
|
||||||
|
{
|
||||||
|
let matches = <Self as IntoApp>::into_app_for_update().try_get_matches_from(itr)?;
|
||||||
|
<Self as FromArgMatches>::update_from_arg_matches(self, &matches);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build an App according to the struct
|
/// Build an App according to the struct
|
||||||
|
@ -114,6 +138,10 @@ pub trait IntoApp: Sized {
|
||||||
fn into_app<'help>() -> App<'help>;
|
fn into_app<'help>() -> App<'help>;
|
||||||
/// @TODO @release @docs
|
/// @TODO @release @docs
|
||||||
fn augment_clap(app: App<'_>) -> App<'_>;
|
fn augment_clap(app: App<'_>) -> App<'_>;
|
||||||
|
/// @TODO @release @docs
|
||||||
|
fn into_app_for_update<'help>() -> App<'help>;
|
||||||
|
/// @TODO @release @docs
|
||||||
|
fn augment_clap_for_update(app: App<'_>) -> App<'_>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts an instance of [`ArgMatches`] to a consumer defined struct.
|
/// Converts an instance of [`ArgMatches`] to a consumer defined struct.
|
||||||
|
@ -154,6 +182,9 @@ pub trait FromArgMatches: Sized {
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
fn from_arg_matches(matches: &ArgMatches) -> Self;
|
fn from_arg_matches(matches: &ArgMatches) -> Self;
|
||||||
|
|
||||||
|
/// @TODO@ @release @docs
|
||||||
|
fn update_from_arg_matches(&mut self, matches: &ArgMatches);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @TODO @release @docs
|
/// @TODO @release @docs
|
||||||
|
@ -161,7 +192,11 @@ pub trait Subcommand: Sized {
|
||||||
/// @TODO @release @docs
|
/// @TODO @release @docs
|
||||||
fn from_subcommand(subcommand: Option<(&str, &ArgMatches)>) -> Option<Self>;
|
fn from_subcommand(subcommand: Option<(&str, &ArgMatches)>) -> Option<Self>;
|
||||||
/// @TODO @release @docs
|
/// @TODO @release @docs
|
||||||
|
fn update_from_subcommand(&mut self, subcommand: Option<(&str, &ArgMatches)>);
|
||||||
|
/// @TODO @release @docs
|
||||||
fn augment_subcommands(app: App<'_>) -> App<'_>;
|
fn augment_subcommands(app: App<'_>) -> App<'_>;
|
||||||
|
/// @TODO @release @docs
|
||||||
|
fn augment_subcommands_for_update(app: App<'_>) -> App<'_>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @TODO @release @docs
|
/// @TODO @release @docs
|
||||||
|
@ -208,19 +243,34 @@ impl<T: IntoApp> IntoApp for Box<T> {
|
||||||
fn augment_clap(app: App<'_>) -> App<'_> {
|
fn augment_clap(app: App<'_>) -> App<'_> {
|
||||||
<T as IntoApp>::augment_clap(app)
|
<T as IntoApp>::augment_clap(app)
|
||||||
}
|
}
|
||||||
|
fn into_app_for_update<'help>() -> App<'help> {
|
||||||
|
<T as IntoApp>::into_app_for_update()
|
||||||
|
}
|
||||||
|
fn augment_clap_for_update(app: App<'_>) -> App<'_> {
|
||||||
|
<T as IntoApp>::augment_clap_for_update(app)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: FromArgMatches> FromArgMatches for Box<T> {
|
impl<T: FromArgMatches> FromArgMatches for Box<T> {
|
||||||
fn from_arg_matches(matches: &ArgMatches) -> Self {
|
fn from_arg_matches(matches: &ArgMatches) -> Self {
|
||||||
Box::new(<T as FromArgMatches>::from_arg_matches(matches))
|
Box::new(<T as FromArgMatches>::from_arg_matches(matches))
|
||||||
}
|
}
|
||||||
|
fn update_from_arg_matches(&mut self, matches: &ArgMatches) {
|
||||||
|
<T as FromArgMatches>::update_from_arg_matches(self, matches);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Subcommand> Subcommand for Box<T> {
|
impl<T: Subcommand> Subcommand for Box<T> {
|
||||||
fn from_subcommand(subcommand: Option<(&str, &ArgMatches)>) -> Option<Self> {
|
fn from_subcommand(subcommand: Option<(&str, &ArgMatches)>) -> Option<Self> {
|
||||||
<T as Subcommand>::from_subcommand(subcommand).map(Box::new)
|
<T as Subcommand>::from_subcommand(subcommand).map(Box::new)
|
||||||
}
|
}
|
||||||
|
fn update_from_subcommand(&mut self, subcommand: Option<(&str, &ArgMatches)>) {
|
||||||
|
<T as Subcommand>::update_from_subcommand(self, subcommand);
|
||||||
|
}
|
||||||
fn augment_subcommands(app: App<'_>) -> App<'_> {
|
fn augment_subcommands(app: App<'_>) -> App<'_> {
|
||||||
<T as Subcommand>::augment_subcommands(app)
|
<T as Subcommand>::augment_subcommands(app)
|
||||||
}
|
}
|
||||||
|
fn augment_subcommands_for_update(app: App<'_>) -> App<'_> {
|
||||||
|
<T as Subcommand>::augment_subcommands_for_update(app)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue