diff --git a/clap_derive/src/derives/args.rs b/clap_derive/src/derives/args.rs index f49883ce..15f676be 100644 --- a/clap_derive/src/derives/args.rs +++ b/clap_derive/src/derives/args.rs @@ -232,6 +232,13 @@ pub fn gen_augment( let value_name = item.value_name(); let implicit_methods = match **ty { + Ty::Unit => { + quote_spanned! { ty.span()=> + .value_name(#value_name) + #value_parser + #action + } + } Ty::Option => { quote_spanned! { ty.span()=> .value_name(#value_name) @@ -421,6 +428,7 @@ pub fn gen_constructor(fields: &[(&Field, Item)]) -> TokenStream { } } }, + Ty::Unit | Ty::Vec | Ty::OptionOption | Ty::OptionVec => { @@ -459,6 +467,7 @@ pub fn gen_constructor(fields: &[(&Field, Item)]) -> TokenStream { } } }, + Ty::Unit | Ty::Vec | Ty::OptionOption | Ty::OptionVec => { @@ -609,6 +618,12 @@ fn gen_parsers( let arg_matches = format_ident!("__clap_arg_matches"); let field_value = match **ty { + Ty::Unit => { + quote_spanned! { ty.span()=> + () + } + } + Ty::Option => { quote_spanned! { ty.span()=> #arg_matches.#get_one(#id) diff --git a/clap_derive/src/utils/ty.rs b/clap_derive/src/utils/ty.rs index a540e5f6..1cf05144 100644 --- a/clap_derive/src/utils/ty.rs +++ b/clap_derive/src/utils/ty.rs @@ -9,6 +9,7 @@ use syn::{ #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum Ty { + Unit, Vec, Option, OptionOption, @@ -21,7 +22,9 @@ impl Ty { use self::Ty::*; let t = |kind| Sp::new(kind, ty.span()); - if is_generic_ty(ty, "Vec") { + if is_unit_ty(ty) { + t(Unit) + } else if is_generic_ty(ty, "Vec") { t(Vec) } else if let Some(subty) = subty_if_name(ty, "Option") { if is_generic_ty(subty, "Option") { @@ -38,6 +41,7 @@ impl Ty { pub fn as_str(&self) -> &'static str { match self { + Self::Unit => "()", Self::Vec => "Vec", Self::Option => "Option", Self::OptionOption => "Option>", @@ -121,6 +125,14 @@ fn is_generic_ty(ty: &syn::Type, name: &str) -> bool { subty_if_name(ty, name).is_some() } +fn is_unit_ty(ty: &syn::Type) -> bool { + if let syn::Type::Tuple(tuple) = ty { + tuple.elems.is_empty() + } else { + false + } +} + fn only_one(mut iter: I) -> Option where I: Iterator, diff --git a/src/_derive/mod.rs b/src/_derive/mod.rs index 42f17824..f2955e50 100644 --- a/src/_derive/mod.rs +++ b/src/_derive/mod.rs @@ -266,7 +266,8 @@ //! //! | Type | Effect | Implies | //! |---------------------|--------------------------------------|-------------------------------------------------------------| -//! | `bool` | flag | `.action(ArgAction::SetTrue) | +//! | `()` | user-defined | `.action(ArgAction::Set).required(false)` | +//! | `bool` | flag | `.action(ArgAction::SetTrue)` | //! | `Option` | optional argument | `.action(ArgAction::Set).required(false)` | //! | `Option>` | optional value for optional argument | `.action(ArgAction::Set).required(false).num_args(0..=1)` | //! | `T` | required argument | `.action(ArgAction::Set).required(!has_default)` | diff --git a/tests/derive/help.rs b/tests/derive/help.rs index 5cdcb9a3..76d5ab6e 100644 --- a/tests/derive/help.rs +++ b/tests/derive/help.rs @@ -431,13 +431,15 @@ fn custom_help_flag() { #[derive(Debug, Clone, Parser)] #[command(disable_help_flag = true)] struct CliOptions { - #[arg(short = 'h', long = "verbose-help", action = ArgAction::Help)] - help: bool, + #[arg(short = 'h', long = "verbose-help", action = ArgAction::Help, value_parser = clap::value_parser!(bool))] + help: (), } let result = CliOptions::try_parse_from(["cmd", "--verbose-help"]); let err = result.unwrap_err(); assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp); + + CliOptions::try_parse_from(["cmd"]).unwrap(); } #[test] @@ -445,11 +447,13 @@ fn custom_version_flag() { #[derive(Debug, Clone, Parser)] #[command(disable_version_flag = true, version = "2.0.0")] struct CliOptions { - #[arg(short = 'V', long = "verbose-version", action = ArgAction::Version)] - version: bool, + #[arg(short = 'V', long = "verbose-version", action = ArgAction::Version, value_parser = clap::value_parser!(bool))] + version: (), } let result = CliOptions::try_parse_from(["cmd", "--verbose-version"]); let err = result.unwrap_err(); assert_eq!(err.kind(), clap::error::ErrorKind::DisplayVersion); + + CliOptions::try_parse_from(["cmd"]).unwrap(); }