Skip to content

Commit d8f6878

Browse files
authored
Merge pull request #2593 from epage/skip
feat(derive): Allow skipping ArgEnum variants
2 parents 060c6da + c1e272e commit d8f6878

File tree

3 files changed

+64
-9
lines changed

3 files changed

+64
-9
lines changed

clap_derive/src/attrs.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,40 @@ impl Attrs {
561561
res
562562
}
563563

564+
pub fn from_arg_enum_variant(
565+
variant: &Variant,
566+
argument_casing: Sp<CasingStyle>,
567+
env_casing: Sp<CasingStyle>,
568+
) -> Self {
569+
let mut res = Self::new(
570+
variant.span(),
571+
Name::Derived(variant.ident.clone()),
572+
None,
573+
argument_casing,
574+
env_casing,
575+
);
576+
res.push_attrs(&variant.attrs);
577+
res.push_doc_comment(&variant.attrs, "about");
578+
579+
if res.has_custom_parser {
580+
abort!(
581+
res.parser.span(),
582+
"`parse` attribute is only allowed on fields"
583+
);
584+
}
585+
match &*res.kind {
586+
Kind::Subcommand(_) => abort!(res.kind.span(), "subcommand is only allowed on fields"),
587+
Kind::Skip(_) => res,
588+
Kind::Arg(_) => res,
589+
Kind::FromGlobal(_) => abort!(res.kind.span(), "from_global is only allowed on fields"),
590+
Kind::Flatten => abort!(res.kind.span(), "flatten is only allowed on fields"),
591+
Kind::ExternalSubcommand => abort!(
592+
res.kind.span(),
593+
"external_subcommand is only allowed on fields"
594+
),
595+
}
596+
}
597+
564598
pub fn from_field(
565599
field: &Field,
566600
struct_casing: Sp<CasingStyle>,

clap_derive/src/derives/arg_enum.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// except according to those terms.
1010

1111
use crate::{
12-
attrs::{Attrs, Name, DEFAULT_CASING, DEFAULT_ENV_CASING},
12+
attrs::{Attrs, Kind, Name, DEFAULT_CASING, DEFAULT_ENV_CASING},
1313
dummies,
1414
utils::Sp,
1515
};
@@ -18,8 +18,8 @@ use proc_macro2::{Span, TokenStream};
1818
use proc_macro_error::abort_call_site;
1919
use quote::quote;
2020
use syn::{
21-
punctuated::Punctuated, spanned::Spanned, token::Comma, Attribute, Data, DataEnum, DeriveInput,
22-
Fields, Ident, Variant,
21+
punctuated::Punctuated, token::Comma, Attribute, Data, DataEnum, DeriveInput, Fields, Ident,
22+
Variant,
2323
};
2424

2525
pub fn derive_arg_enum(input: &DeriveInput) -> TokenStream {
@@ -76,15 +76,19 @@ fn lits(
7676
) -> Vec<(TokenStream, Ident)> {
7777
variants
7878
.iter()
79-
.flat_map(|variant| {
80-
let attrs = Attrs::from_struct(
81-
variant.span(),
82-
&variant.attrs,
83-
Name::Derived(variant.ident.clone()),
79+
.filter_map(|variant| {
80+
let attrs = Attrs::from_arg_enum_variant(
81+
variant,
8482
parent_attribute.casing(),
8583
parent_attribute.env_casing(),
8684
);
87-
85+
if let Kind::Skip(_) = &*attrs.kind() {
86+
None
87+
} else {
88+
Some((variant, attrs))
89+
}
90+
})
91+
.flat_map(|(variant, attrs)| {
8892
let mut ret = vec![(attrs.cased_name(), variant.ident.clone())];
8993

9094
attrs

clap_derive/tests/arg_enum.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,23 @@ fn vector() {
310310
assert!(Opt::try_parse_from(&["", "-a", "fOo"]).is_err());
311311
}
312312

313+
#[test]
314+
fn skip_variant() {
315+
#[derive(ArgEnum, PartialEq, Debug)]
316+
#[allow(dead_code)] // silence warning about `Baz` being unused
317+
enum ArgChoice {
318+
Foo,
319+
Bar,
320+
#[clap(skip)]
321+
Baz,
322+
}
323+
324+
assert_eq!(ArgChoice::VARIANTS, ["foo", "bar"]);
325+
assert!(ArgChoice::from_str("foo", true).is_ok());
326+
assert!(ArgChoice::from_str("bar", true).is_ok());
327+
assert!(ArgChoice::from_str("baz", true).is_err());
328+
}
329+
313330
#[test]
314331
fn from_str_invalid() {
315332
#[derive(ArgEnum, PartialEq, Debug)]

0 commit comments

Comments
 (0)