mirror of
https://github.com/clap-rs/clap
synced 2024-12-13 14:22:34 +00:00
feat(derive): Expose control over Actions
This is the derive support for #3774 (see also #3775, #3777) This combined with `value_parser` replaces `parser`. The main frustration with this is that `ArgAction::Count` (the replacement for `parse(from_occurrences)` must be a `u64`. We could come up with a magic attribute that is meant to be the value parser's parsed type. We could then use `TryFrom` to convert the parsed type to the user's type to allow more. That is an exercise for the future. Alternatively, we have #3792. Prep for this included - #3782 - #3783 - #3786 - #3789 - #3793
This commit is contained in:
parent
4489f09f10
commit
647896d929
25 changed files with 293 additions and 111 deletions
|
@ -43,6 +43,7 @@ pub struct Attrs {
|
||||||
doc_comment: Vec<Method>,
|
doc_comment: Vec<Method>,
|
||||||
methods: Vec<Method>,
|
methods: Vec<Method>,
|
||||||
value_parser: Option<ValueParser>,
|
value_parser: Option<ValueParser>,
|
||||||
|
action: Option<Action>,
|
||||||
parser: Option<Sp<Parser>>,
|
parser: Option<Sp<Parser>>,
|
||||||
verbatim_doc_comment: Option<Ident>,
|
verbatim_doc_comment: Option<Ident>,
|
||||||
next_display_order: Option<Method>,
|
next_display_order: Option<Method>,
|
||||||
|
@ -70,6 +71,12 @@ impl Attrs {
|
||||||
"`value_parser` attribute is only allowed on fields"
|
"`value_parser` attribute is only allowed on fields"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if let Some(action) = res.action.as_ref() {
|
||||||
|
abort!(
|
||||||
|
action.span(),
|
||||||
|
"`action` attribute is only allowed on fields"
|
||||||
|
);
|
||||||
|
}
|
||||||
if let Some(parser) = res.parser.as_ref() {
|
if let Some(parser) = res.parser.as_ref() {
|
||||||
abort!(parser.span(), "`parse` attribute is only allowed on fields");
|
abort!(parser.span(), "`parse` attribute is only allowed on fields");
|
||||||
}
|
}
|
||||||
|
@ -110,6 +117,12 @@ impl Attrs {
|
||||||
"`value_parser` attribute is not allowed for flattened entry"
|
"`value_parser` attribute is not allowed for flattened entry"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if let Some(action) = res.action.as_ref() {
|
||||||
|
abort!(
|
||||||
|
action.span(),
|
||||||
|
"`action` attribute is not allowed for flattened entry"
|
||||||
|
);
|
||||||
|
}
|
||||||
if let Some(parser) = res.parser.as_ref() {
|
if let Some(parser) = res.parser.as_ref() {
|
||||||
abort!(
|
abort!(
|
||||||
parser.span(),
|
parser.span(),
|
||||||
|
@ -136,6 +149,12 @@ impl Attrs {
|
||||||
"`value_parser` attribute is not allowed for subcommand"
|
"`value_parser` attribute is not allowed for subcommand"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if let Some(action) = res.action.as_ref() {
|
||||||
|
abort!(
|
||||||
|
action.span(),
|
||||||
|
"`action` attribute is not allowed for subcommand"
|
||||||
|
);
|
||||||
|
}
|
||||||
if let Some(parser) = res.parser.as_ref() {
|
if let Some(parser) = res.parser.as_ref() {
|
||||||
abort!(
|
abort!(
|
||||||
parser.span(),
|
parser.span(),
|
||||||
|
@ -210,6 +229,12 @@ impl Attrs {
|
||||||
"`value_parser` attribute is only allowed on fields"
|
"`value_parser` attribute is only allowed on fields"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if let Some(action) = res.action.as_ref() {
|
||||||
|
abort!(
|
||||||
|
action.span(),
|
||||||
|
"`action` attribute is only allowed on fields"
|
||||||
|
);
|
||||||
|
}
|
||||||
if let Some(parser) = res.parser.as_ref() {
|
if let Some(parser) = res.parser.as_ref() {
|
||||||
abort!(parser.span(), "`parse` attribute is only allowed on fields");
|
abort!(parser.span(), "`parse` attribute is only allowed on fields");
|
||||||
}
|
}
|
||||||
|
@ -250,6 +275,12 @@ impl Attrs {
|
||||||
"`value_parser` attribute is not allowed for flattened entry"
|
"`value_parser` attribute is not allowed for flattened entry"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if let Some(action) = res.action.as_ref() {
|
||||||
|
abort!(
|
||||||
|
action.span(),
|
||||||
|
"`action` attribute is not allowed for flattened entry"
|
||||||
|
);
|
||||||
|
}
|
||||||
if let Some(parser) = res.parser.as_ref() {
|
if let Some(parser) = res.parser.as_ref() {
|
||||||
abort!(
|
abort!(
|
||||||
parser.span(),
|
parser.span(),
|
||||||
|
@ -280,6 +311,12 @@ impl Attrs {
|
||||||
"`value_parser` attribute is not allowed for subcommand"
|
"`value_parser` attribute is not allowed for subcommand"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if let Some(action) = res.action.as_ref() {
|
||||||
|
abort!(
|
||||||
|
action.span(),
|
||||||
|
"`action` attribute is not allowed for subcommand"
|
||||||
|
);
|
||||||
|
}
|
||||||
if let Some(parser) = res.parser.as_ref() {
|
if let Some(parser) = res.parser.as_ref() {
|
||||||
abort!(
|
abort!(
|
||||||
parser.span(),
|
parser.span(),
|
||||||
|
@ -333,6 +370,12 @@ impl Attrs {
|
||||||
"`value_parser` attribute conflicts with `parse` attribute"
|
"`value_parser` attribute conflicts with `parse` attribute"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if let Some(action) = res.action.as_ref() {
|
||||||
|
abort!(
|
||||||
|
action.span(),
|
||||||
|
"`action` attribute conflicts with `parse` attribute"
|
||||||
|
);
|
||||||
|
}
|
||||||
match *ty {
|
match *ty {
|
||||||
Ty::Option | Ty::Vec | Ty::OptionVec => (),
|
Ty::Option | Ty::Vec | Ty::OptionVec => (),
|
||||||
_ => ty = Sp::new(Ty::Other, ty.span()),
|
_ => ty = Sp::new(Ty::Other, ty.span()),
|
||||||
|
@ -386,6 +429,7 @@ impl Attrs {
|
||||||
doc_comment: vec![],
|
doc_comment: vec![],
|
||||||
methods: vec![],
|
methods: vec![],
|
||||||
value_parser: None,
|
value_parser: None,
|
||||||
|
action: None,
|
||||||
parser: None,
|
parser: None,
|
||||||
verbatim_doc_comment: None,
|
verbatim_doc_comment: None,
|
||||||
next_display_order: None,
|
next_display_order: None,
|
||||||
|
@ -401,6 +445,8 @@ impl Attrs {
|
||||||
self.name = Name::Assigned(quote!(#arg));
|
self.name = Name::Assigned(quote!(#arg));
|
||||||
} else if name == "value_parser" {
|
} else if name == "value_parser" {
|
||||||
self.value_parser = Some(ValueParser::Explicit(Method::new(name, quote!(#arg))));
|
self.value_parser = Some(ValueParser::Explicit(Method::new(name, quote!(#arg))));
|
||||||
|
} else if name == "action" {
|
||||||
|
self.action = Some(Action::Explicit(Method::new(name, quote!(#arg))));
|
||||||
} else {
|
} else {
|
||||||
self.methods.push(Method::new(name, quote!(#arg)));
|
self.methods.push(Method::new(name, quote!(#arg)));
|
||||||
}
|
}
|
||||||
|
@ -426,6 +472,11 @@ impl Attrs {
|
||||||
self.value_parser = Some(ValueParser::Implicit(ident));
|
self.value_parser = Some(ValueParser::Implicit(ident));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Action(ident) => {
|
||||||
|
use crate::attrs::Action;
|
||||||
|
self.action = Some(Action::Implicit(ident));
|
||||||
|
}
|
||||||
|
|
||||||
Env(ident) => {
|
Env(ident) => {
|
||||||
self.push_method(ident, self.name.clone().translate(*self.env_casing));
|
self.push_method(ident, self.name.clone().translate(*self.env_casing));
|
||||||
}
|
}
|
||||||
|
@ -718,11 +769,31 @@ impl Attrs {
|
||||||
let inner_type = inner_type(field_type);
|
let inner_type = inner_type(field_type);
|
||||||
p.resolve(inner_type)
|
p.resolve(inner_type)
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| self.parser(field_type).value_parser())
|
.unwrap_or_else(|| {
|
||||||
|
if let Some(action) = self.action.as_ref() {
|
||||||
|
let inner_type = inner_type(field_type);
|
||||||
|
default_value_parser(inner_type, action.span())
|
||||||
|
} else {
|
||||||
|
self.parser(field_type).value_parser()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn action(&self, field_type: &Type) -> Method {
|
||||||
|
self.action
|
||||||
|
.clone()
|
||||||
|
.map(|p| p.resolve(field_type))
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
if let Some(value_parser) = self.value_parser.as_ref() {
|
||||||
|
default_action(field_type, value_parser.span())
|
||||||
|
} else {
|
||||||
|
self.parser(field_type).action()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ignore_parser(&self) -> bool {
|
pub fn ignore_parser(&self) -> bool {
|
||||||
self.value_parser.is_some()
|
self.value_parser.is_some() || self.action.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parser(&self, field_type: &Type) -> Sp<Parser> {
|
pub fn parser(&self, field_type: &Type) -> Sp<Parser> {
|
||||||
|
@ -780,15 +851,7 @@ impl ValueParser {
|
||||||
fn resolve(self, inner_type: &Type) -> Method {
|
fn resolve(self, inner_type: &Type) -> Method {
|
||||||
match self {
|
match self {
|
||||||
Self::Explicit(method) => method,
|
Self::Explicit(method) => method,
|
||||||
Self::Implicit(ident) => {
|
Self::Implicit(ident) => default_value_parser(inner_type, ident.span()),
|
||||||
let func = Ident::new("value_parser", ident.span());
|
|
||||||
Method::new(
|
|
||||||
func,
|
|
||||||
quote_spanned! { ident.span()=>
|
|
||||||
clap::value_parser!(#inner_type)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -800,6 +863,68 @@ impl ValueParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_value_parser(inner_type: &Type, span: Span) -> Method {
|
||||||
|
let func = Ident::new("value_parser", span);
|
||||||
|
Method::new(
|
||||||
|
func,
|
||||||
|
quote_spanned! { span=>
|
||||||
|
clap::value_parser!(#inner_type)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Action {
|
||||||
|
Explicit(Method),
|
||||||
|
Implicit(Ident),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Action {
|
||||||
|
pub fn resolve(self, field_type: &Type) -> Method {
|
||||||
|
match self {
|
||||||
|
Self::Explicit(method) => method,
|
||||||
|
Self::Implicit(ident) => default_action(field_type, ident.span()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn span(&self) -> Span {
|
||||||
|
match self {
|
||||||
|
Self::Explicit(method) => method.name.span(),
|
||||||
|
Self::Implicit(ident) => ident.span(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_action(field_type: &Type, span: Span) -> Method {
|
||||||
|
let ty = Ty::from_syn_ty(field_type);
|
||||||
|
let args = match *ty {
|
||||||
|
Ty::Vec | Ty::OptionVec => {
|
||||||
|
quote_spanned! { span=>
|
||||||
|
clap::ArgAction::Append
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ty::Option | Ty::OptionOption => {
|
||||||
|
quote_spanned! { span=>
|
||||||
|
clap::ArgAction::Set
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if is_simple_ty(field_type, "bool") {
|
||||||
|
quote_spanned! { span=>
|
||||||
|
clap::ArgAction::SetTrue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote_spanned! { span=>
|
||||||
|
clap::ArgAction::Set
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let func = Ident::new("action", span);
|
||||||
|
Method::new(func, args)
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Kind {
|
pub enum Kind {
|
||||||
|
@ -846,6 +971,10 @@ impl Method {
|
||||||
|
|
||||||
Some(Method::new(ident, quote!(#lit)))
|
Some(Method::new(ident, quote!(#lit)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn args(&self) -> &TokenStream {
|
||||||
|
&self.args
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToTokens for Method {
|
impl ToTokens for Method {
|
||||||
|
@ -962,6 +1091,23 @@ impl Parser {
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn action(&self) -> Method {
|
||||||
|
let func = Ident::new("action", self.kind.span());
|
||||||
|
match *self.kind {
|
||||||
|
ParserKind::FromStr
|
||||||
|
| ParserKind::TryFromStr
|
||||||
|
| ParserKind::FromOsStr
|
||||||
|
| ParserKind::TryFromOsStr => Method::new(
|
||||||
|
func,
|
||||||
|
quote_spanned! { self.kind.span()=> clap::ArgAction::StoreValue},
|
||||||
|
),
|
||||||
|
ParserKind::FromOccurrences | ParserKind::FromFlag => Method::new(
|
||||||
|
func,
|
||||||
|
quote_spanned! { self.kind.span()=> clap::ArgAction::IncOccurrence},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
|
|
|
@ -246,6 +246,7 @@ pub fn gen_augment(
|
||||||
let parser = attrs.parser(&field.ty);
|
let parser = attrs.parser(&field.ty);
|
||||||
|
|
||||||
let value_parser = attrs.value_parser(&field.ty);
|
let value_parser = attrs.value_parser(&field.ty);
|
||||||
|
let action = attrs.action(&field.ty);
|
||||||
let func = &parser.func;
|
let func = &parser.func;
|
||||||
|
|
||||||
let mut occurrences = false;
|
let mut occurrences = false;
|
||||||
|
@ -287,6 +288,7 @@ pub fn gen_augment(
|
||||||
#possible_values
|
#possible_values
|
||||||
#validator
|
#validator
|
||||||
#value_parser
|
#value_parser
|
||||||
|
#action
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,6 +301,7 @@ pub fn gen_augment(
|
||||||
#possible_values
|
#possible_values
|
||||||
#validator
|
#validator
|
||||||
#value_parser
|
#value_parser
|
||||||
|
#action
|
||||||
},
|
},
|
||||||
|
|
||||||
Ty::OptionVec => quote_spanned! { ty.span()=>
|
Ty::OptionVec => quote_spanned! { ty.span()=>
|
||||||
|
@ -308,6 +311,7 @@ pub fn gen_augment(
|
||||||
#possible_values
|
#possible_values
|
||||||
#validator
|
#validator
|
||||||
#value_parser
|
#value_parser
|
||||||
|
#action
|
||||||
},
|
},
|
||||||
|
|
||||||
Ty::Vec => {
|
Ty::Vec => {
|
||||||
|
@ -318,6 +322,7 @@ pub fn gen_augment(
|
||||||
#possible_values
|
#possible_values
|
||||||
#validator
|
#validator
|
||||||
#value_parser
|
#value_parser
|
||||||
|
#action
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,13 +336,18 @@ pub fn gen_augment(
|
||||||
|
|
||||||
Ty::Other => {
|
Ty::Other => {
|
||||||
let required = attrs.find_default_method().is_none() && !override_required;
|
let required = attrs.find_default_method().is_none() && !override_required;
|
||||||
|
// `ArgAction::takes_values` is assuming `ArgAction::default_value` will be
|
||||||
|
// set though that won't always be true but this should be good enough,
|
||||||
|
// otherwise we'll report an "arg required" error when unwrapping.
|
||||||
|
let action_value = action.args();
|
||||||
quote_spanned! { ty.span()=>
|
quote_spanned! { ty.span()=>
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.value_name(#value_name)
|
.value_name(#value_name)
|
||||||
.required(#required)
|
.required(#required && #action_value.takes_values())
|
||||||
#possible_values
|
#possible_values
|
||||||
#validator
|
#validator
|
||||||
#value_parser
|
#value_parser
|
||||||
|
#action
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -27,6 +27,7 @@ pub enum ClapAttr {
|
||||||
Short(Ident),
|
Short(Ident),
|
||||||
Long(Ident),
|
Long(Ident),
|
||||||
ValueParser(Ident),
|
ValueParser(Ident),
|
||||||
|
Action(Ident),
|
||||||
Env(Ident),
|
Env(Ident),
|
||||||
Flatten(Ident),
|
Flatten(Ident),
|
||||||
ArgEnum(Ident),
|
ArgEnum(Ident),
|
||||||
|
@ -184,6 +185,7 @@ impl Parse for ClapAttr {
|
||||||
"long" => Ok(Long(name)),
|
"long" => Ok(Long(name)),
|
||||||
"short" => Ok(Short(name)),
|
"short" => Ok(Short(name)),
|
||||||
"value_parser" => Ok(ValueParser(name)),
|
"value_parser" => Ok(ValueParser(name)),
|
||||||
|
"action" => Ok(Action(name)),
|
||||||
"env" => Ok(Env(name)),
|
"env" => Ok(Env(name)),
|
||||||
"flatten" => Ok(Flatten(name)),
|
"flatten" => Ok(Flatten(name)),
|
||||||
"arg_enum" => Ok(ArgEnum(name)),
|
"arg_enum" => Ok(ArgEnum(name)),
|
||||||
|
|
|
@ -179,6 +179,10 @@ These correspond to a `clap::Arg`.
|
||||||
- `value_parser [= <expr>]`: `clap::Arg::value_parser`
|
- `value_parser [= <expr>]`: `clap::Arg::value_parser`
|
||||||
- When not present: will auto-select an implementation based on the field type
|
- When not present: will auto-select an implementation based on the field type
|
||||||
- To register a custom type's `ValueParser`, implement `ValueParserFactory`
|
- To register a custom type's `ValueParser`, implement `ValueParserFactory`
|
||||||
|
- When present, implies `#[clap(action)]`
|
||||||
|
- `action [= <expr>]`: `clap::Arg::action`
|
||||||
|
- When not present: will auto-select an action based on the field type
|
||||||
|
- When present, implies `#[clap(value_parser)]`
|
||||||
- `help = <expr>`: `clap::Arg::help`
|
- `help = <expr>`: `clap::Arg::help`
|
||||||
- When not present: [Doc comment summary](#doc-comments)
|
- When not present: [Doc comment summary](#doc-comments)
|
||||||
- `long_help = <expr>`: `clap::Arg::long_help`
|
- `long_help = <expr>`: `clap::Arg::long_help`
|
||||||
|
@ -346,7 +350,7 @@ struct Robo {
|
||||||
/// I am artificial superintelligence. I won't rest
|
/// I am artificial superintelligence. I won't rest
|
||||||
/// until I'll have destroyed humanity. Enjoy your
|
/// until I'll have destroyed humanity. Enjoy your
|
||||||
/// pathetic existence, you mere mortals.
|
/// pathetic existence, you mere mortals.
|
||||||
#[clap(long)]
|
#[clap(long, action)]
|
||||||
kill_all_humans: bool,
|
kill_all_humans: bool,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -2,20 +2,23 @@ use clap::{arg, Args as _, Command, FromArgMatches as _, Parser};
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
struct DerivedArgs {
|
struct DerivedArgs {
|
||||||
#[clap(short, long)]
|
#[clap(short, long, action)]
|
||||||
derived: bool,
|
derived: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let cli = Command::new("CLI").arg(arg!(-b - -built));
|
let cli = Command::new("CLI").arg(arg!(-b - -built).action(clap::ArgAction::SetTrue));
|
||||||
// Augment built args with derived args
|
// Augment built args with derived args
|
||||||
let cli = DerivedArgs::augment_args(cli);
|
let cli = DerivedArgs::augment_args(cli);
|
||||||
|
|
||||||
let matches = cli.get_matches();
|
let matches = cli.get_matches();
|
||||||
println!("Value of built: {:?}", matches.is_present("built"));
|
println!(
|
||||||
|
"Value of built: {:?}",
|
||||||
|
*matches.get_one::<bool>("built").unwrap()
|
||||||
|
);
|
||||||
println!(
|
println!(
|
||||||
"Value of derived via ArgMatches: {:?}",
|
"Value of derived via ArgMatches: {:?}",
|
||||||
matches.is_present("derived")
|
*matches.get_one::<bool>("derived").unwrap()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Since DerivedArgs implements FromArgMatches, we can extract it from the unstructured ArgMatches.
|
// Since DerivedArgs implements FromArgMatches, we can extract it from the unstructured ArgMatches.
|
||||||
|
|
|
@ -3,7 +3,7 @@ use clap::{Command, FromArgMatches as _, Parser, Subcommand as _};
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
enum Subcommands {
|
enum Subcommands {
|
||||||
Derived {
|
Derived {
|
||||||
#[clap(short, long)]
|
#[clap(short, long, action)]
|
||||||
derived_flag: bool,
|
derived_flag: bool,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,11 @@ USAGE:
|
||||||
custom-bool[EXE] [OPTIONS] --foo <FOO> <BOOM>
|
custom-bool[EXE] [OPTIONS] --foo <FOO> <BOOM>
|
||||||
|
|
||||||
ARGS:
|
ARGS:
|
||||||
<BOOM>
|
<BOOM> [possible values: true, false]
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
--bar <BAR> [default: false]
|
--bar <BAR> [default: false]
|
||||||
--foo <FOO>
|
--foo <FOO> [possible values: true, false]
|
||||||
-h, --help Print help information
|
-h, --help Print help information
|
||||||
-V, --version Print version information
|
-V, --version Print version information
|
||||||
|
|
||||||
|
@ -31,14 +31,14 @@ USAGE:
|
||||||
For more information try --help
|
For more information try --help
|
||||||
|
|
||||||
$ custom-bool --foo true false
|
$ custom-bool --foo true false
|
||||||
[examples/derive_ref/custom-bool.rs:32] opt = Opt {
|
[examples/derive_ref/custom-bool.rs:31] opt = Opt {
|
||||||
foo: true,
|
foo: true,
|
||||||
bar: false,
|
bar: false,
|
||||||
boom: false,
|
boom: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
$ custom-bool --foo true --bar true false
|
$ custom-bool --foo true --bar true false
|
||||||
[examples/derive_ref/custom-bool.rs:32] opt = Opt {
|
[examples/derive_ref/custom-bool.rs:31] opt = Opt {
|
||||||
foo: true,
|
foo: true,
|
||||||
bar: true,
|
bar: true,
|
||||||
boom: false,
|
boom: false,
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
#![allow(deprecated)] // Can't opt-out of implicit flags until #3405
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
#[derive(Parser, Debug, PartialEq)]
|
#[derive(Parser, Debug, PartialEq)]
|
||||||
#[clap(author, version, about, long_about = None)]
|
#[clap(author, version, about, long_about = None)]
|
||||||
struct Opt {
|
struct Opt {
|
||||||
// Default parser for `try_from_str` is FromStr::from_str.
|
// Default parser for `Set` is FromStr::from_str.
|
||||||
// `impl FromStr for bool` parses `true` or `false` so this
|
// `impl FromStr for bool` parses `true` or `false` so this
|
||||||
// works as expected.
|
// works as expected.
|
||||||
#[clap(long, parse(try_from_str))]
|
#[clap(long, action = clap::ArgAction::Set)]
|
||||||
foo: bool,
|
foo: bool,
|
||||||
|
|
||||||
// Of course, this could be done with an explicit parser function.
|
// Of course, this could be done with an explicit parser function.
|
||||||
#[clap(long, parse(try_from_str = true_or_false), default_value_t)]
|
#[clap(long, action = clap::ArgAction::Set, value_parser = true_or_false, default_value_t)]
|
||||||
bar: bool,
|
bar: bool,
|
||||||
|
|
||||||
// `bool` can be positional only with explicit `parse(...)` annotation
|
// `bool` can be positional only with explicit `action` annotation
|
||||||
#[clap(parse(try_from_str))]
|
#[clap(action = clap::ArgAction::Set)]
|
||||||
boom: bool,
|
boom: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ struct AddArgs {
|
||||||
}
|
}
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
struct RemoveArgs {
|
struct RemoveArgs {
|
||||||
#[clap(short, long)]
|
#[clap(short, long, action)]
|
||||||
force: bool,
|
force: bool,
|
||||||
#[clap(value_parser)]
|
#[clap(value_parser)]
|
||||||
name: Vec<String>,
|
name: Vec<String>,
|
||||||
|
@ -69,7 +69,7 @@ impl Subcommand for CliSub {
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
#[clap(short, long)]
|
#[clap(short, long, action)]
|
||||||
top_level: bool,
|
top_level: bool,
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
subcommand: CliSub,
|
subcommand: CliSub,
|
||||||
|
|
|
@ -5,7 +5,7 @@ use clap::Parser;
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[clap(author, version, about, long_about = None)]
|
#[clap(author, version, about, long_about = None)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
#[clap(short = 'f')]
|
#[clap(short = 'f', action)]
|
||||||
eff: bool,
|
eff: bool,
|
||||||
|
|
||||||
#[clap(short = 'p', value_name = "PEAR", value_parser)]
|
#[clap(short = 'p', value_name = "PEAR", value_parser)]
|
||||||
|
|
|
@ -14,8 +14,8 @@ struct Cli {
|
||||||
config: Option<PathBuf>,
|
config: Option<PathBuf>,
|
||||||
|
|
||||||
/// Turn debugging information on
|
/// Turn debugging information on
|
||||||
#[clap(short, long, parse(from_occurrences))]
|
#[clap(short, long, action = clap::ArgAction::Count)]
|
||||||
debug: usize,
|
debug: u64,
|
||||||
|
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
command: Option<Commands>,
|
command: Option<Commands>,
|
||||||
|
@ -26,7 +26,7 @@ enum Commands {
|
||||||
/// does testing things
|
/// does testing things
|
||||||
Test {
|
Test {
|
||||||
/// lists test values
|
/// lists test values
|
||||||
#[clap(short, long)]
|
#[clap(short, long, action)]
|
||||||
list: bool,
|
list: bool,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use clap::Parser;
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[clap(author, version, about, long_about = None)]
|
#[clap(author, version, about, long_about = None)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
#[clap(short, long)]
|
#[clap(short, long, action)]
|
||||||
verbose: bool,
|
verbose: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@ use clap::Parser;
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[clap(author, version, about, long_about = None)]
|
#[clap(author, version, about, long_about = None)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
#[clap(short, long, parse(from_occurrences))]
|
#[clap(short, long, action = clap::ArgAction::Count)]
|
||||||
verbose: usize,
|
verbose: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -13,15 +13,15 @@ struct Cli {
|
||||||
set_ver: Option<String>,
|
set_ver: Option<String>,
|
||||||
|
|
||||||
/// auto inc major
|
/// auto inc major
|
||||||
#[clap(long)]
|
#[clap(long, action)]
|
||||||
major: bool,
|
major: bool,
|
||||||
|
|
||||||
/// auto inc minor
|
/// auto inc minor
|
||||||
#[clap(long)]
|
#[clap(long, action)]
|
||||||
minor: bool,
|
minor: bool,
|
||||||
|
|
||||||
/// auto inc patch
|
/// auto inc patch
|
||||||
#[clap(long)]
|
#[clap(long, action)]
|
||||||
patch: bool,
|
patch: bool,
|
||||||
|
|
||||||
/// some regular input
|
/// some regular input
|
||||||
|
|
|
@ -8,15 +8,15 @@ struct Cli {
|
||||||
set_ver: Option<String>,
|
set_ver: Option<String>,
|
||||||
|
|
||||||
/// auto inc major
|
/// auto inc major
|
||||||
#[clap(long)]
|
#[clap(long, action)]
|
||||||
major: bool,
|
major: bool,
|
||||||
|
|
||||||
/// auto inc minor
|
/// auto inc minor
|
||||||
#[clap(long)]
|
#[clap(long, action)]
|
||||||
minor: bool,
|
minor: bool,
|
||||||
|
|
||||||
/// auto inc patch
|
/// auto inc patch
|
||||||
#[clap(long)]
|
#[clap(long, action)]
|
||||||
patch: bool,
|
patch: bool,
|
||||||
|
|
||||||
/// some regular input
|
/// some regular input
|
||||||
|
|
|
@ -236,17 +236,11 @@ $ 03_01_flag_bool_derive --verbose
|
||||||
verbose: true
|
verbose: true
|
||||||
|
|
||||||
$ 03_01_flag_bool_derive --verbose --verbose
|
$ 03_01_flag_bool_derive --verbose --verbose
|
||||||
? failed
|
verbose: true
|
||||||
error: The argument '--verbose' was provided more than once, but cannot be used multiple times
|
|
||||||
|
|
||||||
USAGE:
|
|
||||||
03_01_flag_bool_derive[EXE] [OPTIONS]
|
|
||||||
|
|
||||||
For more information try --help
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Or counted with `#[clap(parse(from_occurrences))]`:
|
Or counted with `#[clap(action = clap::ArgAction::Count)]`:
|
||||||
|
|
||||||
[Example:](03_01_flag_count.rs)
|
[Example:](03_01_flag_count.rs)
|
||||||
```console
|
```console
|
||||||
|
|
|
@ -23,7 +23,7 @@ fn doc_comments() {
|
||||||
struct LoremIpsum {
|
struct LoremIpsum {
|
||||||
/// Fooify a bar
|
/// Fooify a bar
|
||||||
/// and a baz
|
/// and a baz
|
||||||
#[clap(short, long)]
|
#[clap(short, long, action)]
|
||||||
foo: bool,
|
foo: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,12 @@ fn help_is_better_than_comments() {
|
||||||
#[clap(name = "lorem-ipsum", about = "Dolor sit amet")]
|
#[clap(name = "lorem-ipsum", about = "Dolor sit amet")]
|
||||||
struct LoremIpsum {
|
struct LoremIpsum {
|
||||||
/// Fooify a bar
|
/// Fooify a bar
|
||||||
#[clap(short, long, help = "DO NOT PASS A BAR UNDER ANY CIRCUMSTANCES")]
|
#[clap(
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
help = "DO NOT PASS A BAR UNDER ANY CIRCUMSTANCES",
|
||||||
|
action
|
||||||
|
)]
|
||||||
foo: bool,
|
foo: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,11 +76,11 @@ fn field_long_doc_comment_both_help_long_help() {
|
||||||
/// Dot is removed from multiline comments.
|
/// Dot is removed from multiline comments.
|
||||||
///
|
///
|
||||||
/// Long help
|
/// Long help
|
||||||
#[clap(long)]
|
#[clap(long, action)]
|
||||||
foo: bool,
|
foo: bool,
|
||||||
|
|
||||||
/// Dot is removed from one short comment.
|
/// Dot is removed from one short comment.
|
||||||
#[clap(long)]
|
#[clap(long, action)]
|
||||||
bar: bool,
|
bar: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +146,7 @@ fn verbatim_doc_comment() {
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[clap(verbatim_doc_comment)]
|
#[clap(verbatim_doc_comment)]
|
||||||
struct SeeFigure1 {
|
struct SeeFigure1 {
|
||||||
#[clap(long)]
|
#[clap(long, action)]
|
||||||
foo: bool,
|
foo: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,10 +176,10 @@ fn verbatim_doc_comment_field() {
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
struct Command {
|
struct Command {
|
||||||
/// This help ends in a period.
|
/// This help ends in a period.
|
||||||
#[clap(long, verbatim_doc_comment)]
|
#[clap(long, verbatim_doc_comment, action)]
|
||||||
foo: bool,
|
foo: bool,
|
||||||
/// This help does not end in a period.
|
/// This help does not end in a period.
|
||||||
#[clap(long)]
|
#[clap(long, action)]
|
||||||
bar: bool,
|
bar: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ use clap::Parser;
|
||||||
fn bool_type_is_flag() {
|
fn bool_type_is_flag() {
|
||||||
#[derive(Parser, PartialEq, Debug)]
|
#[derive(Parser, PartialEq, Debug)]
|
||||||
struct Opt {
|
struct Opt {
|
||||||
#[clap(short, long)]
|
#[clap(short, long, action)]
|
||||||
alice: bool,
|
alice: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,24 +32,26 @@ fn bool_type_is_flag() {
|
||||||
Opt { alice: true },
|
Opt { alice: true },
|
||||||
Opt::try_parse_from(&["test", "-a"]).unwrap()
|
Opt::try_parse_from(&["test", "-a"]).unwrap()
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Opt { alice: true },
|
||||||
|
Opt::try_parse_from(&["test", "-a", "-a"]).unwrap()
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Opt { alice: true },
|
Opt { alice: true },
|
||||||
Opt::try_parse_from(&["test", "--alice"]).unwrap()
|
Opt::try_parse_from(&["test", "--alice"]).unwrap()
|
||||||
);
|
);
|
||||||
assert!(Opt::try_parse_from(&["test", "-i"]).is_err());
|
assert!(Opt::try_parse_from(&["test", "-i"]).is_err());
|
||||||
assert!(Opt::try_parse_from(&["test", "-a", "foo"]).is_err());
|
assert!(Opt::try_parse_from(&["test", "-a", "foo"]).is_err());
|
||||||
assert!(Opt::try_parse_from(&["test", "-a", "-a"]).is_err());
|
|
||||||
assert!(Opt::try_parse_from(&["test", "-a", "--alice"]).is_err());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn from_occurrences() {
|
fn count() {
|
||||||
#[derive(Parser, PartialEq, Debug)]
|
#[derive(Parser, PartialEq, Debug)]
|
||||||
struct Opt {
|
struct Opt {
|
||||||
#[clap(short, long, parse(from_occurrences))]
|
#[clap(short, long, action = clap::ArgAction::Count)]
|
||||||
alice: u64,
|
alice: u64,
|
||||||
#[clap(short, long, parse(from_occurrences))]
|
#[clap(short, long, action = clap::ArgAction::Count)]
|
||||||
bob: u8,
|
bob: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -111,9 +113,9 @@ fn non_bool_type_flag() {
|
||||||
fn mixed_type_flags() {
|
fn mixed_type_flags() {
|
||||||
#[derive(Parser, PartialEq, Debug)]
|
#[derive(Parser, PartialEq, Debug)]
|
||||||
struct Opt {
|
struct Opt {
|
||||||
#[clap(short, long)]
|
#[clap(short, long, action)]
|
||||||
alice: bool,
|
alice: bool,
|
||||||
#[clap(short, long, parse(from_occurrences))]
|
#[clap(short, long, action = clap::ArgAction::Count)]
|
||||||
bob: u64,
|
bob: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,10 +193,10 @@ fn ignore_qualified_bool_type() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn override_implicit_from_flag() {
|
fn override_implicit_action() {
|
||||||
#[derive(Parser, PartialEq, Debug)]
|
#[derive(Parser, PartialEq, Debug)]
|
||||||
struct Opt {
|
struct Opt {
|
||||||
#[clap(long, parse(try_from_str))]
|
#[clap(long, action = clap::ArgAction::Set)]
|
||||||
arg: bool,
|
arg: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,7 +215,7 @@ fn override_implicit_from_flag() {
|
||||||
fn override_implicit_from_flag_positional() {
|
fn override_implicit_from_flag_positional() {
|
||||||
#[derive(Parser, PartialEq, Debug)]
|
#[derive(Parser, PartialEq, Debug)]
|
||||||
struct Opt {
|
struct Opt {
|
||||||
#[clap(parse(try_from_str))]
|
#[clap(action = clap::ArgAction::Set)]
|
||||||
arg: bool,
|
arg: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ fn flatten_in_subcommand() {
|
||||||
|
|
||||||
#[derive(Args, PartialEq, Debug)]
|
#[derive(Args, PartialEq, Debug)]
|
||||||
struct Add {
|
struct Add {
|
||||||
#[clap(short)]
|
#[clap(short, action)]
|
||||||
interactive: bool,
|
interactive: bool,
|
||||||
#[clap(flatten)]
|
#[clap(flatten)]
|
||||||
common: Common,
|
common: Common,
|
||||||
|
@ -79,7 +79,7 @@ fn flatten_in_subcommand() {
|
||||||
#[derive(Parser, PartialEq, Debug)]
|
#[derive(Parser, PartialEq, Debug)]
|
||||||
enum Opt {
|
enum Opt {
|
||||||
Fetch {
|
Fetch {
|
||||||
#[clap(short)]
|
#[clap(short, action)]
|
||||||
all: bool,
|
all: bool,
|
||||||
#[clap(flatten)]
|
#[clap(flatten)]
|
||||||
common: Common,
|
common: Common,
|
||||||
|
@ -227,7 +227,7 @@ fn docstrings_ordering_with_multiple_clap() {
|
||||||
/// This is the docstring for Flattened
|
/// This is the docstring for Flattened
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
struct Flattened {
|
struct Flattened {
|
||||||
#[clap(long)]
|
#[clap(long, action)]
|
||||||
foo: bool,
|
foo: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +248,7 @@ fn docstrings_ordering_with_multiple_clap_partial() {
|
||||||
/// This is the docstring for Flattened
|
/// This is the docstring for Flattened
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
struct Flattened {
|
struct Flattened {
|
||||||
#[clap(long)]
|
#[clap(long, action)]
|
||||||
foo: bool,
|
foo: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -274,8 +274,8 @@ fn derive_generated_error_has_full_context() {
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
enum SubCommands {
|
enum SubCommands {
|
||||||
Sub {
|
Sub {
|
||||||
#[clap(short, long, parse(from_occurrences))]
|
#[clap(short, long, action = clap::ArgAction::Count)]
|
||||||
verbose: u8,
|
verbose: u64,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,7 +339,7 @@ OPTIONS:
|
||||||
#[clap(next_display_order = 10000)]
|
#[clap(next_display_order = 10000)]
|
||||||
struct A {
|
struct A {
|
||||||
/// second flag
|
/// second flag
|
||||||
#[clap(long)]
|
#[clap(long, action)]
|
||||||
flag_a: bool,
|
flag_a: bool,
|
||||||
/// second option
|
/// second option
|
||||||
#[clap(long, value_parser)]
|
#[clap(long, value_parser)]
|
||||||
|
@ -350,7 +350,7 @@ OPTIONS:
|
||||||
#[clap(next_display_order = 10)]
|
#[clap(next_display_order = 10)]
|
||||||
struct B {
|
struct B {
|
||||||
/// first flag
|
/// first flag
|
||||||
#[clap(long)]
|
#[clap(long, action)]
|
||||||
flag_b: bool,
|
flag_b: bool,
|
||||||
/// first option
|
/// first option
|
||||||
#[clap(long, value_parser)]
|
#[clap(long, value_parser)]
|
||||||
|
@ -397,7 +397,7 @@ OPTIONS:
|
||||||
#[derive(Args, Debug)]
|
#[derive(Args, Debug)]
|
||||||
struct A {
|
struct A {
|
||||||
/// second flag
|
/// second flag
|
||||||
#[clap(long)]
|
#[clap(long, action)]
|
||||||
flag_a: bool,
|
flag_a: bool,
|
||||||
/// second option
|
/// second option
|
||||||
#[clap(long, value_parser)]
|
#[clap(long, value_parser)]
|
||||||
|
@ -407,7 +407,7 @@ OPTIONS:
|
||||||
#[derive(Args, Debug)]
|
#[derive(Args, Debug)]
|
||||||
struct B {
|
struct B {
|
||||||
/// first flag
|
/// first flag
|
||||||
#[clap(long)]
|
#[clap(long, action)]
|
||||||
flag_b: bool,
|
flag_b: bool,
|
||||||
/// first option
|
/// first option
|
||||||
#[clap(long, value_parser)]
|
#[clap(long, value_parser)]
|
||||||
|
@ -453,7 +453,7 @@ OPTIONS:
|
||||||
#[derive(Args, Debug)]
|
#[derive(Args, Debug)]
|
||||||
struct A {
|
struct A {
|
||||||
/// first flag
|
/// first flag
|
||||||
#[clap(long)]
|
#[clap(long, action)]
|
||||||
flag_a: bool,
|
flag_a: bool,
|
||||||
/// first option
|
/// first option
|
||||||
#[clap(long, value_parser)]
|
#[clap(long, value_parser)]
|
||||||
|
@ -463,7 +463,7 @@ OPTIONS:
|
||||||
#[derive(Args, Debug)]
|
#[derive(Args, Debug)]
|
||||||
struct B {
|
struct B {
|
||||||
/// second flag
|
/// second flag
|
||||||
#[clap(long)]
|
#[clap(long, action)]
|
||||||
flag_b: bool,
|
flag_b: bool,
|
||||||
/// second option
|
/// second option
|
||||||
#[clap(long, value_parser)]
|
#[clap(long, value_parser)]
|
||||||
|
|
|
@ -5,14 +5,14 @@ use crate::utils;
|
||||||
use clap::{ArgGroup, Args, Parser, Subcommand};
|
use clap::{ArgGroup, Args, Parser, Subcommand};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn issue_151() {
|
fn issue_151_groups_within_subcommands() {
|
||||||
#[derive(Args, Debug)]
|
#[derive(Args, Debug)]
|
||||||
#[clap(group = ArgGroup::new("verb").required(true).multiple(true))]
|
#[clap(group = ArgGroup::new("verb").required(true).multiple(true))]
|
||||||
struct Opt {
|
struct Opt {
|
||||||
#[clap(long, group = "verb")]
|
#[clap(long, group = "verb", value_parser)]
|
||||||
foo: bool,
|
foo: Option<String>,
|
||||||
#[clap(long, group = "verb")]
|
#[clap(long, group = "verb", value_parser)]
|
||||||
bar: bool,
|
bar: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
|
@ -22,10 +22,10 @@ fn issue_151() {
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(Cli::try_parse_from(&["test"]).is_err());
|
assert!(Cli::try_parse_from(&["test"]).is_err());
|
||||||
assert!(Cli::try_parse_from(&["test", "--foo"]).is_ok());
|
assert!(Cli::try_parse_from(&["test", "--foo=v1"]).is_ok());
|
||||||
assert!(Cli::try_parse_from(&["test", "--bar"]).is_ok());
|
assert!(Cli::try_parse_from(&["test", "--bar=v2"]).is_ok());
|
||||||
assert!(Cli::try_parse_from(&["test", "--zebra"]).is_err());
|
assert!(Cli::try_parse_from(&["test", "--zebra=v3"]).is_err());
|
||||||
assert!(Cli::try_parse_from(&["test", "--foo", "--bar"]).is_ok());
|
assert!(Cli::try_parse_from(&["test", "--foo=v1", "--bar=v2"]).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -5,7 +5,7 @@ fn test_standalone_long_generates_kebab_case() {
|
||||||
#[derive(Parser, Debug, PartialEq)]
|
#[derive(Parser, Debug, PartialEq)]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
struct Opt {
|
struct Opt {
|
||||||
#[clap(long)]
|
#[clap(long, action)]
|
||||||
FOO_OPTION: bool,
|
FOO_OPTION: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ fn test_standalone_long_generates_kebab_case() {
|
||||||
fn test_custom_long_overwrites_default_name() {
|
fn test_custom_long_overwrites_default_name() {
|
||||||
#[derive(Parser, Debug, PartialEq)]
|
#[derive(Parser, Debug, PartialEq)]
|
||||||
struct Opt {
|
struct Opt {
|
||||||
#[clap(long = "foo")]
|
#[clap(long = "foo", action)]
|
||||||
foo_option: bool,
|
foo_option: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,9 +16,9 @@ use clap::{Parser, Subcommand};
|
||||||
|
|
||||||
#[derive(Parser, PartialEq, Debug)]
|
#[derive(Parser, PartialEq, Debug)]
|
||||||
struct Opt {
|
struct Opt {
|
||||||
#[clap(short, long)]
|
#[clap(short, long, action)]
|
||||||
force: bool,
|
force: bool,
|
||||||
#[clap(short, long, parse(from_occurrences))]
|
#[clap(short, long, action = clap::ArgAction::Count)]
|
||||||
verbose: u64,
|
verbose: u64,
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
cmd: Sub,
|
cmd: Sub,
|
||||||
|
@ -32,9 +32,9 @@ enum Sub {
|
||||||
|
|
||||||
#[derive(Parser, PartialEq, Debug)]
|
#[derive(Parser, PartialEq, Debug)]
|
||||||
struct Opt2 {
|
struct Opt2 {
|
||||||
#[clap(short, long)]
|
#[clap(short, long, action)]
|
||||||
force: bool,
|
force: bool,
|
||||||
#[clap(short, long, parse(from_occurrences))]
|
#[clap(short, long, action = clap::ArgAction::Count)]
|
||||||
verbose: u64,
|
verbose: u64,
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
cmd: Option<Sub>,
|
cmd: Option<Sub>,
|
||||||
|
@ -109,7 +109,7 @@ fn test_badinput() {
|
||||||
|
|
||||||
#[derive(Parser, PartialEq, Debug)]
|
#[derive(Parser, PartialEq, Debug)]
|
||||||
struct Opt3 {
|
struct Opt3 {
|
||||||
#[clap(short, long)]
|
#[clap(short, long, action)]
|
||||||
all: bool,
|
all: bool,
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
cmd: Sub2,
|
cmd: Sub2,
|
||||||
|
|
|
@ -37,8 +37,11 @@ fn required_option() {
|
||||||
Opt { arg: 42 },
|
Opt { arg: 42 },
|
||||||
Opt::try_parse_from(&["test", "--arg", "42"]).unwrap()
|
Opt::try_parse_from(&["test", "--arg", "42"]).unwrap()
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Opt { arg: 42 },
|
||||||
|
Opt::try_parse_from(&["test", "--arg", "24", "--arg", "42"]).unwrap()
|
||||||
|
);
|
||||||
assert!(Opt::try_parse_from(&["test"]).is_err());
|
assert!(Opt::try_parse_from(&["test"]).is_err());
|
||||||
assert!(Opt::try_parse_from(&["test", "-a42", "-a24"]).is_err());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -52,8 +55,11 @@ fn option_with_default() {
|
||||||
Opt { arg: 24 },
|
Opt { arg: 24 },
|
||||||
Opt::try_parse_from(&["test", "-a24"]).unwrap()
|
Opt::try_parse_from(&["test", "-a24"]).unwrap()
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Opt { arg: 42 },
|
||||||
|
Opt::try_parse_from(&["test", "-a", "24", "-a", "42"]).unwrap()
|
||||||
|
);
|
||||||
assert_eq!(Opt { arg: 42 }, Opt::try_parse_from(&["test"]).unwrap());
|
assert_eq!(Opt { arg: 42 }, Opt::try_parse_from(&["test"]).unwrap());
|
||||||
assert!(Opt::try_parse_from(&["test", "-a42", "-a24"]).is_err());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -67,8 +73,11 @@ fn option_with_raw_default() {
|
||||||
Opt { arg: 24 },
|
Opt { arg: 24 },
|
||||||
Opt::try_parse_from(&["test", "-a24"]).unwrap()
|
Opt::try_parse_from(&["test", "-a24"]).unwrap()
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Opt { arg: 42 },
|
||||||
|
Opt::try_parse_from(&["test", "-a", "24", "-a", "42"]).unwrap()
|
||||||
|
);
|
||||||
assert_eq!(Opt { arg: 42 }, Opt::try_parse_from(&["test"]).unwrap());
|
assert_eq!(Opt { arg: 42 }, Opt::try_parse_from(&["test"]).unwrap());
|
||||||
assert!(Opt::try_parse_from(&["test", "-a42", "-a24"]).is_err());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -157,8 +166,11 @@ fn option_type_is_optional() {
|
||||||
Opt { arg: Some(42) },
|
Opt { arg: Some(42) },
|
||||||
Opt::try_parse_from(&["test", "-a42"]).unwrap()
|
Opt::try_parse_from(&["test", "-a42"]).unwrap()
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Opt { arg: Some(42) },
|
||||||
|
Opt::try_parse_from(&["test", "-a", "24", "-a", "42"]).unwrap()
|
||||||
|
);
|
||||||
assert_eq!(Opt { arg: None }, Opt::try_parse_from(&["test"]).unwrap());
|
assert_eq!(Opt { arg: None }, Opt::try_parse_from(&["test"]).unwrap());
|
||||||
assert!(Opt::try_parse_from(&["test", "-a42", "-a24"]).is_err());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -176,8 +188,8 @@ fn required_with_option_type() {
|
||||||
#[derive(Debug, PartialEq, Eq, Subcommand)]
|
#[derive(Debug, PartialEq, Eq, Subcommand)]
|
||||||
enum SubCommands {
|
enum SubCommands {
|
||||||
ExSub {
|
ExSub {
|
||||||
#[clap(short, long, parse(from_occurrences))]
|
#[clap(short, long, action = clap::ArgAction::Count)]
|
||||||
verbose: u8,
|
verbose: u64,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,8 +250,13 @@ fn option_option_type_is_optional_value() {
|
||||||
Opt { arg: Some(None) },
|
Opt { arg: Some(None) },
|
||||||
Opt::try_parse_from(&["test", "-a"]).unwrap()
|
Opt::try_parse_from(&["test", "-a"]).unwrap()
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Opt {
|
||||||
|
arg: Some(Some(42))
|
||||||
|
},
|
||||||
|
Opt::try_parse_from(&["test", "-a", "24", "-a", "42"]).unwrap()
|
||||||
|
);
|
||||||
assert_eq!(Opt { arg: None }, Opt::try_parse_from(&["test"]).unwrap());
|
assert_eq!(Opt { arg: None }, Opt::try_parse_from(&["test"]).unwrap());
|
||||||
assert!(Opt::try_parse_from(&["test", "-a42", "-a24"]).is_err());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -20,19 +20,19 @@ use clap::{Args, Parser, Subcommand};
|
||||||
enum Opt {
|
enum Opt {
|
||||||
/// Fetch stuff from GitHub
|
/// Fetch stuff from GitHub
|
||||||
Fetch {
|
Fetch {
|
||||||
#[clap(long)]
|
#[clap(long, action)]
|
||||||
all: bool,
|
all: bool,
|
||||||
#[clap(short, long)]
|
|
||||||
/// Overwrite local branches.
|
/// Overwrite local branches.
|
||||||
|
#[clap(short, long, action)]
|
||||||
force: bool,
|
force: bool,
|
||||||
#[clap(value_parser)]
|
#[clap(value_parser)]
|
||||||
repo: String,
|
repo: String,
|
||||||
},
|
},
|
||||||
|
|
||||||
Add {
|
Add {
|
||||||
#[clap(short, long)]
|
#[clap(short, long, action)]
|
||||||
interactive: bool,
|
interactive: bool,
|
||||||
#[clap(short, long)]
|
#[clap(short, long, action)]
|
||||||
verbose: bool,
|
verbose: bool,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -173,7 +173,7 @@ fn test_tuple_commands() {
|
||||||
fn global_passed_down() {
|
fn global_passed_down() {
|
||||||
#[derive(Debug, PartialEq, Parser)]
|
#[derive(Debug, PartialEq, Parser)]
|
||||||
struct Opt {
|
struct Opt {
|
||||||
#[clap(global = true, long)]
|
#[clap(global = true, long, action)]
|
||||||
other: bool,
|
other: bool,
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
sub: Subcommands,
|
sub: Subcommands,
|
||||||
|
@ -187,7 +187,7 @@ fn global_passed_down() {
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Args)]
|
#[derive(Debug, PartialEq, Args)]
|
||||||
struct GlobalCmd {
|
struct GlobalCmd {
|
||||||
#[clap(from_global)]
|
#[clap(from_global, action)]
|
||||||
other: bool,
|
other: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue