mirror of
https://github.com/clap-rs/clap
synced 2024-11-10 14:54:15 +00:00
feat(derive): Allow type-less fields
When overriding other fields, help or version flag, globals, etc, a user might not care about the value, so let's ignore the lookup. Been talking about this for a while but Issue #4367 moved this forward because there wasn't a good way to handle this without changing behavior.
This commit is contained in:
parent
a2f2a9ade1
commit
b26c01aa0e
4 changed files with 38 additions and 6 deletions
|
@ -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)
|
||||
|
|
|
@ -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<T>",
|
||||
Self::Option => "Option<T>",
|
||||
Self::OptionOption => "Option<Option<T>>",
|
||||
|
@ -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<I, T>(mut iter: I) -> Option<T>
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
|
|
|
@ -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<T>` | optional argument | `.action(ArgAction::Set).required(false)` |
|
||||
//! | `Option<Option<T>>` | optional value for optional argument | `.action(ArgAction::Set).required(false).num_args(0..=1)` |
|
||||
//! | `T` | required argument | `.action(ArgAction::Set).required(!has_default)` |
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue