Merge pull request #2026 from zkat/master

feat(derive): Add support from inheriting global options in subcommands
This commit is contained in:
Pavan Kumar Sunkara 2021-05-20 13:52:24 +01:00 committed by GitHub
commit abe2373cca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 74 additions and 4 deletions

View file

@ -38,6 +38,7 @@ pub const DEFAULT_ENV_CASING: CasingStyle = CasingStyle::ScreamingSnake;
#[derive(Clone)]
pub enum Kind {
Arg(Sp<Ty>),
FromGlobal(Sp<Ty>),
Subcommand(Sp<Ty>),
Flatten,
Skip(Option<Expr>),
@ -316,6 +317,12 @@ impl Attrs {
ArgEnum(_) => self.is_enum = true,
FromGlobal(ident) => {
let ty = Sp::call_site(Ty::Other);
let kind = Sp::new(Kind::FromGlobal(ty), ident.span());
self.set_kind(kind);
}
Subcommand(ident) => {
let ty = Sp::call_site(Ty::Other);
let kind = Sp::new(Kind::Subcommand(ty), ident.span());
@ -452,7 +459,7 @@ impl Attrs {
match &*res.kind {
Kind::Subcommand(_) => abort!(res.kind.span(), "subcommand is only allowed on fields"),
Kind::Skip(_) => abort!(res.kind.span(), "skip is only allowed on fields"),
Kind::Arg(_) | Kind::Flatten | Kind::ExternalSubcommand => res,
Kind::Arg(_) | Kind::FromGlobal(_) | Kind::Flatten | Kind::ExternalSubcommand => res,
}
}
@ -538,6 +545,10 @@ impl Attrs {
);
}
}
Kind::FromGlobal(orig_ty) => {
let ty = Ty::from_syn_ty(&field.ty);
res.kind = Sp::new(Kind::FromGlobal(ty), orig_ty.span());
}
Kind::Arg(orig_ty) => {
let mut ty = Ty::from_syn_ty(&field.ty);
if res.has_custom_parser {

View file

@ -269,7 +269,7 @@ pub fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Att
Some(val) => quote_spanned!(kind.span()=> #field_name: (#val).into()),
},
Kind::Arg(ty) => gen_parsers(&attrs, ty, field_name, field, None),
Kind::Arg(ty) | Kind::FromGlobal(ty) => gen_parsers(&attrs, ty, field_name, field, None),
}
});
@ -349,7 +349,7 @@ pub fn gen_updater(
Kind::Skip(_) => quote!(),
Kind::Arg(ty) => gen_parsers(&attrs, ty, field_name, field, Some(&access)),
Kind::Arg(ty) | Kind::FromGlobal(ty) => gen_parsers(&attrs, ty, field_name, field, Some(&access)),
}
});

View file

@ -231,7 +231,10 @@ pub fn gen_app_augmentation(
);
let kind = attrs.kind();
match &*kind {
Kind::Subcommand(_) | Kind::Skip(_) | Kind::ExternalSubcommand => None,
Kind::Subcommand(_)
| Kind::Skip(_)
| Kind::FromGlobal(_)
| Kind::ExternalSubcommand => None,
Kind::Flatten => {
let ty = &field.ty;
Some(quote_spanned! { kind.span()=>

View file

@ -17,6 +17,7 @@ pub enum ClapAttr {
Env(Ident),
Flatten(Ident),
ArgEnum(Ident),
FromGlobal(Ident),
Subcommand(Ident),
VerbatimDocComment(Ident),
ExternalSubcommand(Ident),
@ -170,6 +171,7 @@ impl Parse for ClapAttr {
"env" => Ok(Env(name)),
"flatten" => Ok(Flatten(name)),
"arg_enum" => Ok(ArgEnum(name)),
"from_global" => Ok(FromGlobal(name)),
"subcommand" => Ok(Subcommand(name)),
"external_subcommand" => Ok(ExternalSubcommand(name)),
"verbatim_doc_comment" => Ok(VerbatimDocComment(name)),

View file

@ -161,6 +161,45 @@ fn test_tuple_commands() {
assert!(!output.contains("Not shown"));
}
#[test]
fn global_passed_down() {
#[derive(Debug, PartialEq, Clap)]
struct Opt {
#[clap(global = true, long)]
other: bool,
#[clap(subcommand)]
sub: Subcommands,
}
#[derive(Debug, PartialEq, Clap)]
enum Subcommands {
Add,
Global(GlobalCmd),
}
#[derive(Debug, PartialEq, Clap)]
struct GlobalCmd {
#[clap(from_global)]
other: bool,
}
assert_eq!(
Opt::parse_from(&["test", "global"]),
Opt {
other: false,
sub: Subcommands::Global(GlobalCmd { other: false })
}
);
assert_eq!(
Opt::parse_from(&["test", "global", "--other"]),
Opt {
other: true,
sub: Subcommands::Global(GlobalCmd { other: true })
}
);
}
#[test]
fn external_subcommand() {
#[derive(Debug, PartialEq, Clap)]

View file

@ -82,3 +82,18 @@ fn propagate_global_arg_to_subcommand_in_subsubcommand_2053() {
m.subcommand_matches("test").unwrap().value_of("sub-str")
);
}
#[test]
fn global_arg_available_in_subcommand() {
let m = App::new("opt")
.args(&[
Arg::new("global").global(true).long("global"),
Arg::new("not").global(false).long("not"),
])
.subcommand(App::new("ping"))
.get_matches_from(&["opt", "ping", "--global"]);
assert!(m.is_present("global"));
assert!(m.subcommand_matches("ping").unwrap().is_present("global"));
assert!(!m.subcommand_matches("ping").unwrap().is_present("not"));
}