mirror of
https://github.com/clap-rs/clap
synced 2024-12-13 22:32:33 +00:00
Merge pull request #2026 from zkat/master
feat(derive): Add support from inheriting global options in subcommands
This commit is contained in:
commit
abe2373cca
6 changed files with 74 additions and 4 deletions
|
@ -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 {
|
||||
|
|
|
@ -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)),
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -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()=>
|
||||
|
|
|
@ -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)),
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue