From b589a6ce062259e78ad7a74fc0e3bd1fb6f68542 Mon Sep 17 00:00:00 2001 From: ModProg Date: Thu, 9 Sep 2021 14:50:43 +0200 Subject: [PATCH 01/10] feat(derive:arg_enum): use ArgValue in ArgEnum trait --- clap_derive/src/derives/arg_enum.rs | 2 +- clap_derive/src/dummies.rs | 2 +- clap_derive/tests/arg_enum.rs | 7 +++++-- src/build/arg/arg_value.rs | 5 +++-- src/derive.rs | 4 ++-- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/clap_derive/src/derives/arg_enum.rs b/clap_derive/src/derives/arg_enum.rs index 9bae00725b2..0d3b182b1e0 100644 --- a/clap_derive/src/derives/arg_enum.rs +++ b/clap_derive/src/derives/arg_enum.rs @@ -107,7 +107,7 @@ fn gen_variants(lits: &[(TokenStream, Ident)]) -> TokenStream { let lit = lits.iter().map(|l| &l.0).collect::>(); quote! { - const VARIANTS: &'static [&'static str] = &[#(#lit),*]; + const VARIANTS: &'static [clap::ArgValue<'static>] = &[#(clap::ArgValue::new(#lit)),*]; } } diff --git a/clap_derive/src/dummies.rs b/clap_derive/src/dummies.rs index 433fff3f16e..7529758b4e1 100644 --- a/clap_derive/src/dummies.rs +++ b/clap_derive/src/dummies.rs @@ -76,7 +76,7 @@ pub fn args(name: &Ident) { pub fn arg_enum(name: &Ident) { append_dummy(quote! { impl clap::ArgEnum for #name { - const VARIANTS: &'static [&'static str] = &[]; + const VARIANTS: &'static [clap::ArgValue<'static>] = &[]; fn from_str(_input: &str, _case_insensitive: bool) -> Result { unimplemented!() } diff --git a/clap_derive/tests/arg_enum.rs b/clap_derive/tests/arg_enum.rs index cbffaa41684..26ecfb82330 100644 --- a/clap_derive/tests/arg_enum.rs +++ b/clap_derive/tests/arg_enum.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -use clap::{ArgEnum, Clap}; +use clap::{ArgEnum, ArgValue, Clap}; #[test] fn basic() { @@ -367,7 +367,10 @@ fn skip_variant() { Baz, } - assert_eq!(ArgChoice::VARIANTS, ["foo", "bar"]); + assert_eq!( + ArgChoice::VARIANTS, + [ArgValue::new("foo"), ArgValue::new("bar")] + ); assert!(ArgChoice::from_str("foo", true).is_ok()); assert!(ArgChoice::from_str("bar", true).is_ok()); assert!(ArgChoice::from_str("baz", true).is_err()); diff --git a/src/build/arg/arg_value.rs b/src/build/arg/arg_value.rs index 83de81b35d1..2ecfd4e406b 100644 --- a/src/build/arg/arg_value.rs +++ b/src/build/arg/arg_value.rs @@ -20,7 +20,7 @@ /// [possible values]: crate::Arg::possible_value() /// [hide]: ArgValue::hidden() /// [about]: ArgValue::about() -#[derive(Debug, Default, Clone)] +#[derive(Debug, Default, Clone, Copy, PartialEq)] pub struct ArgValue<'help> { pub(crate) name: &'help str, pub(crate) about: Option<&'help str>, @@ -83,7 +83,8 @@ impl<'help> ArgValue<'help> { pub fn new(name: &'help str) -> Self { ArgValue { name, - ..Default::default() + about: None, + hidden: false, } } diff --git a/src/derive.rs b/src/derive.rs index 918f8f06831..03ea5660e8e 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -1,7 +1,7 @@ //! This module contains traits that are usable with the `#[derive(...)].` //! macros in [`clap_derive`]. -use crate::{App, ArgMatches, Error}; +use crate::{App, ArgMatches, ArgValue, Error}; use std::ffi::OsString; @@ -283,7 +283,7 @@ pub trait Subcommand: FromArgMatches + Sized { /// ``` pub trait ArgEnum: Sized { /// All possible argument choices, in display order. - const VARIANTS: &'static [&'static str]; + const VARIANTS: &'static [ArgValue<'static>]; /// Parse an argument into `Self`. fn from_str(input: &str, case_insensitive: bool) -> Result; From 88d7d025554b7b38b676cb40243e17acd0c92c94 Mon Sep 17 00:00:00 2001 From: Roland Fredenhagen Date: Sat, 18 Sep 2021 14:13:44 +0200 Subject: [PATCH 02/10] Working Implementation --- clap_derive/examples/arg_enum.rs | 6 ++++++ clap_derive/src/attrs.rs | 14 ++++++++++++++ clap_derive/src/derives/arg_enum.rs | 26 ++++++++++++++++++-------- clap_derive/src/parse.rs | 2 ++ src/build/arg/arg_value.rs | 6 +++--- 5 files changed, 43 insertions(+), 11 deletions(-) diff --git a/clap_derive/examples/arg_enum.rs b/clap_derive/examples/arg_enum.rs index e233b053b4a..3f13658ee7f 100644 --- a/clap_derive/examples/arg_enum.rs +++ b/clap_derive/examples/arg_enum.rs @@ -6,11 +6,17 @@ use clap::{ArgEnum, Clap}; #[derive(ArgEnum, Debug, PartialEq)] enum ArgChoice { + /// Descriptions are supported as doc-comment Foo, + // Renames are supported + #[clap(name = "b-a-r")] Bar, // Aliases are supported #[clap(alias = "b", alias = "z")] Baz, + // Hiding variants from help and completion is supported + #[clap(hidden)] + Hidden, } #[derive(Clap, PartialEq, Debug)] diff --git a/clap_derive/src/attrs.rs b/clap_derive/src/attrs.rs index 0d465f817ca..2fd7feba383 100644 --- a/clap_derive/src/attrs.rs +++ b/clap_derive/src/attrs.rs @@ -308,6 +308,8 @@ impl Attrs { self.push_method(ident, self.name.clone().translate(*self.env_casing)); } + Hidden(ident) => self.push_method(ident, true), + ArgEnum(_) => self.is_enum = true, FromGlobal(ident) => { @@ -782,6 +784,18 @@ impl Attrs { quote!( #(#doc_comment)* #(#methods)* ) } + /// generate methods on top of a field + /// filter out any passed method names + pub fn field_methods_filtered(&self, filter: &[&str]) -> proc_macro2::TokenStream { + let methods: Vec<_> = self + .methods + .iter() + .filter(|m| !filter.contains(&m.name.to_string().as_str())) + .collect(); + let doc_comment = &self.doc_comment; + quote!( #(#doc_comment)* #(#methods)* ) + } + pub fn version(&self) -> TokenStream { self.version .clone() diff --git a/clap_derive/src/derives/arg_enum.rs b/clap_derive/src/derives/arg_enum.rs index 0d3b182b1e0..766edf0b1e6 100644 --- a/clap_derive/src/derives/arg_enum.rs +++ b/clap_derive/src/derives/arg_enum.rs @@ -47,9 +47,10 @@ pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStr ); let lits = lits(&e.variants, &attrs); + let lits_wo_attrs: Vec<_> = lits.iter().cloned().map(|(ts, i, _)| (ts, i)).collect(); let variants = gen_variants(&lits); - let from_str = gen_from_str(&lits); - let as_arg = gen_as_arg(&lits); + let from_str = gen_from_str(&lits_wo_attrs); + let as_arg = gen_as_arg(&lits_wo_attrs); quote! { #[allow(dead_code, unreachable_code, unused_variables)] @@ -75,7 +76,7 @@ pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStr fn lits( variants: &Punctuated, parent_attribute: &Attrs, -) -> Vec<(TokenStream, Ident)> { +) -> Vec<(TokenStream, Ident, Attrs)> { variants .iter() .filter_map(|variant| { @@ -91,23 +92,32 @@ fn lits( } }) .flat_map(|(variant, attrs)| { - let mut ret = vec![(attrs.cased_name(), variant.ident.clone())]; + let mut ret = vec![(attrs.cased_name(), variant.ident.clone(), attrs.clone())]; attrs .enum_aliases() .into_iter() - .for_each(|x| ret.push((x, variant.ident.clone()))); + .for_each(|x| ret.push((x, variant.ident.clone(), attrs.clone()))); ret }) .collect::>() } -fn gen_variants(lits: &[(TokenStream, Ident)]) -> TokenStream { - let lit = lits.iter().map(|l| &l.0).collect::>(); +fn gen_variants(lits: &[(TokenStream, Ident, Attrs)]) -> TokenStream { + let lit = lits + .iter() + .map(|(name, _, attrs)| { + let fields = attrs.field_methods_filtered(&["alias"]); + quote! { + clap::ArgValue::new(#name) + #fields + } + }) + .collect::>(); quote! { - const VARIANTS: &'static [clap::ArgValue<'static>] = &[#(clap::ArgValue::new(#lit)),*]; + const VARIANTS: &'static [clap::ArgValue<'static>] = &[#(#lit),*]; } } diff --git a/clap_derive/src/parse.rs b/clap_derive/src/parse.rs index e563bc72cdd..eb487a3ba2b 100644 --- a/clap_derive/src/parse.rs +++ b/clap_derive/src/parse.rs @@ -21,6 +21,7 @@ pub enum ClapAttr { Subcommand(Ident), VerbatimDocComment(Ident), ExternalSubcommand(Ident), + Hidden(Ident), // ident [= "string literal"] About(Ident, Option), @@ -172,6 +173,7 @@ impl Parse for ClapAttr { "subcommand" => Ok(Subcommand(name)), "external_subcommand" => Ok(ExternalSubcommand(name)), "verbatim_doc_comment" => Ok(VerbatimDocComment(name)), + "hidden" => Ok(Hidden(name)), "default_value" => { abort!(name, diff --git a/src/build/arg/arg_value.rs b/src/build/arg/arg_value.rs index 2ecfd4e406b..7ceb1bafea4 100644 --- a/src/build/arg/arg_value.rs +++ b/src/build/arg/arg_value.rs @@ -80,7 +80,7 @@ impl<'help> ArgValue<'help> { /// [hidden]: ArgValue::hidden /// [possible value]: crate::Arg::possible_values /// [`Arg::hide_possible_values(true)`]: crate::Arg::hide_possible_values() - pub fn new(name: &'help str) -> Self { + pub const fn new(name: &'help str) -> Self { ArgValue { name, about: None, @@ -100,7 +100,7 @@ impl<'help> ArgValue<'help> { /// # ; /// ``` #[inline] - pub fn about(mut self, about: &'help str) -> Self { + pub const fn about(mut self, about: &'help str) -> Self { self.about = Some(about); self } @@ -120,7 +120,7 @@ impl<'help> ArgValue<'help> { /// ``` /// [`Arg::hide_possible_values(true)`]: crate::Arg::hide_possible_values() #[inline] - pub fn hidden(mut self, yes: bool) -> Self { + pub const fn hidden(mut self, yes: bool) -> Self { self.hidden = yes; self } From d3f0534939b4f2498d04d622181fe3a1bc54fbee Mon Sep 17 00:00:00 2001 From: ModProg Date: Sun, 26 Sep 2021 22:46:23 +0200 Subject: [PATCH 03/10] add hidden aliases to ArgValue --- src/build/arg/arg_value.rs | 24 ++++++++++++++++- src/parse/validator.rs | 8 ++++-- tests/possible_values.rs | 54 +++++++++++++++++++++++++++++++++++++- 3 files changed, 82 insertions(+), 4 deletions(-) diff --git a/src/build/arg/arg_value.rs b/src/build/arg/arg_value.rs index 7ceb1bafea4..c6a081e9968 100644 --- a/src/build/arg/arg_value.rs +++ b/src/build/arg/arg_value.rs @@ -20,10 +20,11 @@ /// [possible values]: crate::Arg::possible_value() /// [hide]: ArgValue::hidden() /// [about]: ArgValue::about() -#[derive(Debug, Default, Clone, Copy, PartialEq)] +#[derive(Debug, Default, Clone, PartialEq)] pub struct ArgValue<'help> { pub(crate) name: &'help str, pub(crate) about: Option<&'help str>, + pub(crate) aliases: Vec<&'help str>, // (name, visible) pub(crate) hidden: bool, } @@ -61,6 +62,11 @@ impl<'help> ArgValue<'help> { Some(self.name) } } + + /// TODO + pub fn get_name_and_aliases(&self) -> Vec<&str> { + [self.name].iter().chain(&self.aliases).copied().collect() + } } impl<'help> ArgValue<'help> { @@ -85,6 +91,7 @@ impl<'help> ArgValue<'help> { name, about: None, hidden: false, + aliases: Vec::new(), } } @@ -124,4 +131,19 @@ impl<'help> ArgValue<'help> { self.hidden = yes; self } + + /// TODO + pub fn alias(mut self, name: &'help str) -> Self { + self.aliases.push(name); + self + } + + /// TODO + pub fn aliases(mut self, names: I) -> Self + where + I: IntoIterator, + { + self.aliases.extend(names.into_iter()); + self + } } diff --git a/src/parse/validator.rs b/src/parse/validator.rs index 45463a3ecd1..2e1af4e9a10 100644 --- a/src/parse/validator.rs +++ b/src/parse/validator.rs @@ -107,9 +107,13 @@ impl<'help, 'app, 'parser> Validator<'help, 'app, 'parser> { let ok = if arg.is_set(ArgSettings::IgnoreCase) { arg.possible_vals .iter() - .any(|pv| pv.name.eq_ignore_ascii_case(&val_str)) + .flat_map(ArgValue::get_name_and_aliases) + .any(|pv| pv.eq_ignore_ascii_case(&val_str)) } else { - arg.possible_vals.iter().any(|pv| pv.name == &*val_str) + arg.possible_vals + .iter() + .flat_map(ArgValue::get_name_and_aliases) + .any(|pv| pv == &*val_str) }; if !ok { let used: Vec = matcher diff --git a/tests/possible_values.rs b/tests/possible_values.rs index 932982eb583..5f8638af454 100644 --- a/tests/possible_values.rs +++ b/tests/possible_values.rs @@ -219,6 +219,22 @@ fn possible_values_output() { )); } +#[test] +fn possible_values_alias_output() { + assert!(utils::compare_output( + App::new("test").arg( + Arg::new("option") + .short('O') + .possible_value("slow") + .possible_value(ArgValue::new("fast").alias("fost")) + .possible_value(ArgValue::new("ludicrous speed").aliases(["ls", "lcs"])) + ), + "clap-test -O slo", + PV_ERROR, + true + )); +} + #[test] fn possible_values_hidden_output() { assert!(utils::compare_output( @@ -249,6 +265,42 @@ fn escaped_possible_values_output() { )); } +#[test] +fn alias() { + let m = App::new("pv") + .arg( + Arg::new("option") + .short('o') + .long("--option") + .takes_value(true) + .possible_value(ArgValue::new("test123").alias("123")) + .possible_value("test321") + .case_insensitive(true), + ) + .try_get_matches_from(vec!["pv", "--option", "123"]); + + assert!(m.is_ok()); + assert!(m.unwrap().value_of("option").unwrap().eq("123")); +} + +#[test] +fn aliases() { + let m = App::new("pv") + .arg( + Arg::new("option") + .short('o') + .long("--option") + .takes_value(true) + .possible_value(ArgValue::new("test123").aliases(["1", "2", "3"])) + .possible_value("test321") + .case_insensitive(true), + ) + .try_get_matches_from(vec!["pv", "--option", "2"]); + + assert!(m.is_ok()); + assert!(m.unwrap().value_of("option").unwrap().eq("2")); +} + #[test] fn case_insensitive() { let m = App::new("pv") @@ -272,7 +324,7 @@ fn case_insensitive() { } #[test] -fn case_insensitive_faili() { +fn case_insensitive_fail() { let m = App::new("pv") .arg( Arg::new("option") From f002cdcc9966eb331625af1b282183b27c3aed25 Mon Sep 17 00:00:00 2001 From: ModProg Date: Mon, 27 Sep 2021 01:18:47 +0200 Subject: [PATCH 04/10] move alias implementation to ArgValue for derive --- clap_derive/src/attrs.rs | 20 ----------- clap_derive/src/derives/arg_enum.rs | 51 +++++++++++------------------ clap_derive/src/derives/args.rs | 2 +- clap_derive/tests/arg_enum.rs | 6 ++-- src/build/arg/arg_value.rs | 13 ++++++++ src/derive.rs | 4 +-- src/parse/validator.rs | 15 +++------ 7 files changed, 42 insertions(+), 69 deletions(-) diff --git a/clap_derive/src/attrs.rs b/clap_derive/src/attrs.rs index 2fd7feba383..7f258692337 100644 --- a/clap_derive/src/attrs.rs +++ b/clap_derive/src/attrs.rs @@ -784,18 +784,6 @@ impl Attrs { quote!( #(#doc_comment)* #(#methods)* ) } - /// generate methods on top of a field - /// filter out any passed method names - pub fn field_methods_filtered(&self, filter: &[&str]) -> proc_macro2::TokenStream { - let methods: Vec<_> = self - .methods - .iter() - .filter(|m| !filter.contains(&m.name.to_string().as_str())) - .collect(); - let doc_comment = &self.doc_comment; - quote!( #(#doc_comment)* #(#methods)* ) - } - pub fn version(&self) -> TokenStream { self.version .clone() @@ -833,14 +821,6 @@ impl Attrs { } } - pub fn enum_aliases(&self) -> Vec { - self.methods - .iter() - .filter(|m| m.name == "alias") - .map(|m| m.args.clone()) - .collect() - } - pub fn casing(&self) -> Sp { self.casing.clone() } diff --git a/clap_derive/src/derives/arg_enum.rs b/clap_derive/src/derives/arg_enum.rs index 766edf0b1e6..06fd46d827d 100644 --- a/clap_derive/src/derives/arg_enum.rs +++ b/clap_derive/src/derives/arg_enum.rs @@ -47,10 +47,9 @@ pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStr ); let lits = lits(&e.variants, &attrs); - let lits_wo_attrs: Vec<_> = lits.iter().cloned().map(|(ts, i, _)| (ts, i)).collect(); let variants = gen_variants(&lits); - let from_str = gen_from_str(&lits_wo_attrs); - let as_arg = gen_as_arg(&lits_wo_attrs); + let from_str = gen_from_str(&lits); + let as_arg = gen_as_arg(&lits); quote! { #[allow(dead_code, unreachable_code, unused_variables)] @@ -76,7 +75,7 @@ pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStr fn lits( variants: &Punctuated, parent_attribute: &Attrs, -) -> Vec<(TokenStream, Ident, Attrs)> { +) -> Vec<(TokenStream, Ident)> { variants .iter() .filter_map(|variant| { @@ -88,36 +87,30 @@ fn lits( if let Kind::Skip(_) = &*attrs.kind() { None } else { - Some((variant, attrs)) + let fields = attrs.field_methods(); + let name = attrs.cased_name(); + Some(( + quote! { + clap::ArgValue::new(#name) + #fields + }, + variant.ident.clone(), + )) } }) - .flat_map(|(variant, attrs)| { - let mut ret = vec![(attrs.cased_name(), variant.ident.clone(), attrs.clone())]; - - attrs - .enum_aliases() - .into_iter() - .for_each(|x| ret.push((x, variant.ident.clone(), attrs.clone()))); - - ret - }) .collect::>() } -fn gen_variants(lits: &[(TokenStream, Ident, Attrs)]) -> TokenStream { +fn gen_variants(lits: &[(TokenStream, Ident)]) -> TokenStream { let lit = lits .iter() - .map(|(name, _, attrs)| { - let fields = attrs.field_methods_filtered(&["alias"]); - quote! { - clap::ArgValue::new(#name) - #fields - } - }) + .map(|(arg_value, ..)| arg_value) .collect::>(); quote! { - const VARIANTS: &'static [clap::ArgValue<'static>] = &[#(#lit),*]; + fn variants() -> Vec> { + vec![#(#lit),*] + } } } @@ -126,14 +119,8 @@ fn gen_from_str(lits: &[(TokenStream, Ident)]) -> TokenStream { quote! { fn from_str(input: &str, case_insensitive: bool) -> ::std::result::Result { - let func = if case_insensitive { - ::std::ascii::AsciiExt::eq_ignore_ascii_case - } else { - str::eq - }; - match input { - #(val if func(val, #lit) => Ok(Self::#variant),)* + #(val if #lit.matches(val, case_insensitive) => Ok(Self::#variant),)* e => Err(format!("Invalid variant: {}", e)), } } @@ -144,7 +131,7 @@ fn gen_as_arg(lits: &[(TokenStream, Ident)]) -> TokenStream { let (lit, variant): (Vec, Vec) = lits.iter().cloned().unzip(); quote! { - fn as_arg(&self) -> Option<&'static str> { + fn as_arg(&self) -> Option> { match self { #(Self::#variant => Some(#lit),)* _ => None diff --git a/clap_derive/src/derives/args.rs b/clap_derive/src/derives/args.rs index 398489def06..3b987cffc01 100644 --- a/clap_derive/src/derives/args.rs +++ b/clap_derive/src/derives/args.rs @@ -361,7 +361,7 @@ pub fn gen_augment( fn gen_arg_enum_possible_values(ty: &Type) -> TokenStream { quote_spanned! { ty.span()=> - .possible_values(<#ty as clap::ArgEnum>::VARIANTS.into_iter().copied()) + .possible_values(<#ty as clap::ArgEnum>::variants()) } } diff --git a/clap_derive/tests/arg_enum.rs b/clap_derive/tests/arg_enum.rs index 26ecfb82330..8642b545d7a 100644 --- a/clap_derive/tests/arg_enum.rs +++ b/clap_derive/tests/arg_enum.rs @@ -54,7 +54,7 @@ fn default_value() { impl std::fmt::Display for ArgChoice { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - std::fmt::Display::fmt(self.as_arg().unwrap(), f) + std::fmt::Display::fmt(self.as_arg().unwrap().get_name(), f) } } @@ -368,8 +368,8 @@ fn skip_variant() { } assert_eq!( - ArgChoice::VARIANTS, - [ArgValue::new("foo"), ArgValue::new("bar")] + ArgChoice::variants(), + vec![ArgValue::new("foo"), ArgValue::new("bar")] ); assert!(ArgChoice::from_str("foo", true).is_ok()); assert!(ArgChoice::from_str("bar", true).is_ok()); diff --git a/src/build/arg/arg_value.rs b/src/build/arg/arg_value.rs index c6a081e9968..bc184294407 100644 --- a/src/build/arg/arg_value.rs +++ b/src/build/arg/arg_value.rs @@ -67,6 +67,19 @@ impl<'help> ArgValue<'help> { pub fn get_name_and_aliases(&self) -> Vec<&str> { [self.name].iter().chain(&self.aliases).copied().collect() } + + /// TODO + pub fn matches(&self, value: &str, ignore_case: bool) -> bool { + if ignore_case { + self.get_name_and_aliases() + .iter() + .any(|name| name.eq_ignore_ascii_case(value)) + } else { + self.get_name_and_aliases() + .iter() + .any(|name| name == &value) + } + } } impl<'help> ArgValue<'help> { diff --git a/src/derive.rs b/src/derive.rs index 03ea5660e8e..e1f3e3dcf79 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -283,7 +283,7 @@ pub trait Subcommand: FromArgMatches + Sized { /// ``` pub trait ArgEnum: Sized { /// All possible argument choices, in display order. - const VARIANTS: &'static [ArgValue<'static>]; + fn variants() -> Vec>; /// Parse an argument into `Self`. fn from_str(input: &str, case_insensitive: bool) -> Result; @@ -291,7 +291,7 @@ pub trait ArgEnum: Sized { /// The canonical argument value. /// /// The value is `None` for skipped variants. - fn as_arg(&self) -> Option<&'static str>; + fn as_arg(&self) -> Option>; } impl Clap for Box { diff --git a/src/parse/validator.rs b/src/parse/validator.rs index 2e1af4e9a10..15835ac704c 100644 --- a/src/parse/validator.rs +++ b/src/parse/validator.rs @@ -104,17 +104,10 @@ impl<'help, 'app, 'parser> Validator<'help, 'app, 'parser> { arg.possible_vals ); let val_str = val.to_string_lossy(); - let ok = if arg.is_set(ArgSettings::IgnoreCase) { - arg.possible_vals - .iter() - .flat_map(ArgValue::get_name_and_aliases) - .any(|pv| pv.eq_ignore_ascii_case(&val_str)) - } else { - arg.possible_vals - .iter() - .flat_map(ArgValue::get_name_and_aliases) - .any(|pv| pv == &*val_str) - }; + let ok = arg + .possible_vals + .iter() + .any(|pv| pv.matches(&val_str, arg.is_set(ArgSettings::IgnoreCase))); if !ok { let used: Vec = matcher .arg_names() From 76f7211d8b28d0e4b4e24c8dd67058f687882183 Mon Sep 17 00:00:00 2001 From: ModProg Date: Mon, 27 Sep 2021 01:29:10 +0200 Subject: [PATCH 05/10] small changes --- clap_derive/examples/arg_enum.rs | 2 +- clap_derive/src/attrs.rs | 2 -- clap_derive/src/derives/arg_enum.rs | 5 +---- clap_derive/src/dummies.rs | 6 ++++-- clap_derive/src/parse.rs | 2 -- src/build/arg/arg_value.rs | 10 ++++------ 6 files changed, 10 insertions(+), 17 deletions(-) diff --git a/clap_derive/examples/arg_enum.rs b/clap_derive/examples/arg_enum.rs index 3f13658ee7f..b2bd93c24e8 100644 --- a/clap_derive/examples/arg_enum.rs +++ b/clap_derive/examples/arg_enum.rs @@ -15,7 +15,7 @@ enum ArgChoice { #[clap(alias = "b", alias = "z")] Baz, // Hiding variants from help and completion is supported - #[clap(hidden)] + #[clap(hidden = true)] Hidden, } diff --git a/clap_derive/src/attrs.rs b/clap_derive/src/attrs.rs index 7f258692337..85b86154e06 100644 --- a/clap_derive/src/attrs.rs +++ b/clap_derive/src/attrs.rs @@ -308,8 +308,6 @@ impl Attrs { self.push_method(ident, self.name.clone().translate(*self.env_casing)); } - Hidden(ident) => self.push_method(ident, true), - ArgEnum(_) => self.is_enum = true, FromGlobal(ident) => { diff --git a/clap_derive/src/derives/arg_enum.rs b/clap_derive/src/derives/arg_enum.rs index 06fd46d827d..373b432e996 100644 --- a/clap_derive/src/derives/arg_enum.rs +++ b/clap_derive/src/derives/arg_enum.rs @@ -102,10 +102,7 @@ fn lits( } fn gen_variants(lits: &[(TokenStream, Ident)]) -> TokenStream { - let lit = lits - .iter() - .map(|(arg_value, ..)| arg_value) - .collect::>(); + let lit = lits.iter().map(|l| &l.0).collect::>(); quote! { fn variants() -> Vec> { diff --git a/clap_derive/src/dummies.rs b/clap_derive/src/dummies.rs index 7529758b4e1..3d5905cd84d 100644 --- a/clap_derive/src/dummies.rs +++ b/clap_derive/src/dummies.rs @@ -76,11 +76,13 @@ pub fn args(name: &Ident) { pub fn arg_enum(name: &Ident) { append_dummy(quote! { impl clap::ArgEnum for #name { - const VARIANTS: &'static [clap::ArgValue<'static>] = &[]; + fn variants() -> Vec> { + unimplemented!() + } fn from_str(_input: &str, _case_insensitive: bool) -> Result { unimplemented!() } - fn as_arg(&self) -> Option<&'static str> { + fn as_arg(&self) -> Option> { unimplemented!() } } diff --git a/clap_derive/src/parse.rs b/clap_derive/src/parse.rs index eb487a3ba2b..e563bc72cdd 100644 --- a/clap_derive/src/parse.rs +++ b/clap_derive/src/parse.rs @@ -21,7 +21,6 @@ pub enum ClapAttr { Subcommand(Ident), VerbatimDocComment(Ident), ExternalSubcommand(Ident), - Hidden(Ident), // ident [= "string literal"] About(Ident, Option), @@ -173,7 +172,6 @@ impl Parse for ClapAttr { "subcommand" => Ok(Subcommand(name)), "external_subcommand" => Ok(ExternalSubcommand(name)), "verbatim_doc_comment" => Ok(VerbatimDocComment(name)), - "hidden" => Ok(Hidden(name)), "default_value" => { abort!(name, diff --git a/src/build/arg/arg_value.rs b/src/build/arg/arg_value.rs index bc184294407..3557921366b 100644 --- a/src/build/arg/arg_value.rs +++ b/src/build/arg/arg_value.rs @@ -99,12 +99,10 @@ impl<'help> ArgValue<'help> { /// [hidden]: ArgValue::hidden /// [possible value]: crate::Arg::possible_values /// [`Arg::hide_possible_values(true)`]: crate::Arg::hide_possible_values() - pub const fn new(name: &'help str) -> Self { + pub fn new(name: &'help str) -> Self { ArgValue { name, - about: None, - hidden: false, - aliases: Vec::new(), + ..Default::default() } } @@ -120,7 +118,7 @@ impl<'help> ArgValue<'help> { /// # ; /// ``` #[inline] - pub const fn about(mut self, about: &'help str) -> Self { + pub fn about(mut self, about: &'help str) -> Self { self.about = Some(about); self } @@ -140,7 +138,7 @@ impl<'help> ArgValue<'help> { /// ``` /// [`Arg::hide_possible_values(true)`]: crate::Arg::hide_possible_values() #[inline] - pub const fn hidden(mut self, yes: bool) -> Self { + pub fn hidden(mut self, yes: bool) -> Self { self.hidden = yes; self } From ac1a9d6d1333ab06ce19da0aa1680d768ad8c214 Mon Sep 17 00:00:00 2001 From: ModProg Date: Mon, 27 Sep 2021 22:06:17 +0200 Subject: [PATCH 06/10] address epage's remarks --- clap_derive/src/derives/arg_enum.rs | 16 ++++++++-------- clap_derive/src/derives/args.rs | 2 +- clap_derive/src/dummies.rs | 4 ++-- clap_derive/tests/arg_enum.rs | 4 ++-- clap_derive/tests/ui/arg_enum_on_struct.rs | 2 +- src/build/arg/arg_value.rs | 13 ++++++------- src/derive.rs | 6 +++--- 7 files changed, 23 insertions(+), 24 deletions(-) diff --git a/clap_derive/src/derives/arg_enum.rs b/clap_derive/src/derives/arg_enum.rs index 373b432e996..1211e829049 100644 --- a/clap_derive/src/derives/arg_enum.rs +++ b/clap_derive/src/derives/arg_enum.rs @@ -47,9 +47,9 @@ pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStr ); let lits = lits(&e.variants, &attrs); - let variants = gen_variants(&lits); + let arg_values = gen_arg_values(&lits); let from_str = gen_from_str(&lits); - let as_arg = gen_as_arg(&lits); + let arg_value = gen_arg_value(&lits); quote! { #[allow(dead_code, unreachable_code, unused_variables)] @@ -65,9 +65,9 @@ pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStr )] #[deny(clippy::correctness)] impl clap::ArgEnum for #name { - #variants + #arg_values #from_str - #as_arg + #arg_value } } } @@ -101,11 +101,11 @@ fn lits( .collect::>() } -fn gen_variants(lits: &[(TokenStream, Ident)]) -> TokenStream { +fn gen_arg_values(lits: &[(TokenStream, Ident)]) -> TokenStream { let lit = lits.iter().map(|l| &l.0).collect::>(); quote! { - fn variants() -> Vec> { + fn arg_values() -> Vec> { vec![#(#lit),*] } } @@ -124,11 +124,11 @@ fn gen_from_str(lits: &[(TokenStream, Ident)]) -> TokenStream { } } -fn gen_as_arg(lits: &[(TokenStream, Ident)]) -> TokenStream { +fn gen_arg_value(lits: &[(TokenStream, Ident)]) -> TokenStream { let (lit, variant): (Vec, Vec) = lits.iter().cloned().unzip(); quote! { - fn as_arg(&self) -> Option> { + fn arg_value(&self) -> Option> { match self { #(Self::#variant => Some(#lit),)* _ => None diff --git a/clap_derive/src/derives/args.rs b/clap_derive/src/derives/args.rs index 3b987cffc01..0cceb291db9 100644 --- a/clap_derive/src/derives/args.rs +++ b/clap_derive/src/derives/args.rs @@ -361,7 +361,7 @@ pub fn gen_augment( fn gen_arg_enum_possible_values(ty: &Type) -> TokenStream { quote_spanned! { ty.span()=> - .possible_values(<#ty as clap::ArgEnum>::variants()) + .possible_values(<#ty as clap::ArgEnum>::arg_values()) } } diff --git a/clap_derive/src/dummies.rs b/clap_derive/src/dummies.rs index 3d5905cd84d..ecc63277887 100644 --- a/clap_derive/src/dummies.rs +++ b/clap_derive/src/dummies.rs @@ -76,13 +76,13 @@ pub fn args(name: &Ident) { pub fn arg_enum(name: &Ident) { append_dummy(quote! { impl clap::ArgEnum for #name { - fn variants() -> Vec> { + fn arg_values() -> Vec> { unimplemented!() } fn from_str(_input: &str, _case_insensitive: bool) -> Result { unimplemented!() } - fn as_arg(&self) -> Option> { + fn arg_value(&self) -> Option> { unimplemented!() } } diff --git a/clap_derive/tests/arg_enum.rs b/clap_derive/tests/arg_enum.rs index 8642b545d7a..84c816cd8f8 100644 --- a/clap_derive/tests/arg_enum.rs +++ b/clap_derive/tests/arg_enum.rs @@ -54,7 +54,7 @@ fn default_value() { impl std::fmt::Display for ArgChoice { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - std::fmt::Display::fmt(self.as_arg().unwrap().get_name(), f) + std::fmt::Display::fmt(self.arg_value().unwrap().get_name(), f) } } @@ -368,7 +368,7 @@ fn skip_variant() { } assert_eq!( - ArgChoice::variants(), + ArgChoice::arg_values(), vec![ArgValue::new("foo"), ArgValue::new("bar")] ); assert!(ArgChoice::from_str("foo", true).is_ok()); diff --git a/clap_derive/tests/ui/arg_enum_on_struct.rs b/clap_derive/tests/ui/arg_enum_on_struct.rs index cb41f72b2f7..27f9a9502c8 100644 --- a/clap_derive/tests/ui/arg_enum_on_struct.rs +++ b/clap_derive/tests/ui/arg_enum_on_struct.rs @@ -4,5 +4,5 @@ use clap::ArgEnum; struct Opt {} fn main() { - println!("{:?}", Opt::VARIANTS); + println!("{:?}", Opt::arg_values()); } diff --git a/src/build/arg/arg_value.rs b/src/build/arg/arg_value.rs index 3557921366b..6b7d45e3769 100644 --- a/src/build/arg/arg_value.rs +++ b/src/build/arg/arg_value.rs @@ -1,3 +1,5 @@ +use std::iter; + /// The representation of a possible value of an argument. /// /// This is used for specifying [possible values] of [Args]. @@ -20,7 +22,7 @@ /// [possible values]: crate::Arg::possible_value() /// [hide]: ArgValue::hidden() /// [about]: ArgValue::about() -#[derive(Debug, Default, Clone, PartialEq)] +#[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct ArgValue<'help> { pub(crate) name: &'help str, pub(crate) about: Option<&'help str>, @@ -64,20 +66,17 @@ impl<'help> ArgValue<'help> { } /// TODO - pub fn get_name_and_aliases(&self) -> Vec<&str> { - [self.name].iter().chain(&self.aliases).copied().collect() + pub fn get_name_and_aliases(&self) -> impl Iterator { + iter::once(&self.name).chain(&self.aliases).copied() } /// TODO pub fn matches(&self, value: &str, ignore_case: bool) -> bool { if ignore_case { self.get_name_and_aliases() - .iter() .any(|name| name.eq_ignore_ascii_case(value)) } else { - self.get_name_and_aliases() - .iter() - .any(|name| name == &value) + self.get_name_and_aliases().any(|name| name == value) } } } diff --git a/src/derive.rs b/src/derive.rs index e1f3e3dcf79..3edb39c3e50 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -282,8 +282,8 @@ pub trait Subcommand: FromArgMatches + Sized { /// } /// ``` pub trait ArgEnum: Sized { - /// All possible argument choices, in display order. - fn variants() -> Vec>; + /// All possible argument values, in display order. + fn arg_values() -> Vec>; /// Parse an argument into `Self`. fn from_str(input: &str, case_insensitive: bool) -> Result; @@ -291,7 +291,7 @@ pub trait ArgEnum: Sized { /// The canonical argument value. /// /// The value is `None` for skipped variants. - fn as_arg(&self) -> Option>; + fn arg_value(&self) -> Option>; } impl Clap for Box { From 480035ac9c36490c4cccbf09e71b0ae84a6d527b Mon Sep 17 00:00:00 2001 From: ModProg Date: Wed, 29 Sep 2021 18:05:19 +0200 Subject: [PATCH 07/10] ArgEnum: Slice instead of array, from_str in ArgEnum implemented --- clap_derive/examples/arg_enum.rs | 2 +- clap_derive/examples/value_hints_derive.rs | 2 +- clap_derive/src/derives/arg_enum.rs | 23 +++------------ clap_derive/src/derives/args.rs | 2 +- clap_derive/tests/arg_enum.rs | 34 ++++++++++++---------- src/derive.rs | 16 ++++++---- 6 files changed, 37 insertions(+), 42 deletions(-) diff --git a/clap_derive/examples/arg_enum.rs b/clap_derive/examples/arg_enum.rs index b2bd93c24e8..e5ca96230d3 100644 --- a/clap_derive/examples/arg_enum.rs +++ b/clap_derive/examples/arg_enum.rs @@ -4,7 +4,7 @@ use clap::{ArgEnum, Clap}; -#[derive(ArgEnum, Debug, PartialEq)] +#[derive(ArgEnum, Debug, PartialEq, Clone)] enum ArgChoice { /// Descriptions are supported as doc-comment Foo, diff --git a/clap_derive/examples/value_hints_derive.rs b/clap_derive/examples/value_hints_derive.rs index 0ecca5fb325..d0be2c00e82 100644 --- a/clap_derive/examples/value_hints_derive.rs +++ b/clap_derive/examples/value_hints_derive.rs @@ -19,7 +19,7 @@ use std::ffi::OsString; use std::io; use std::path::PathBuf; -#[derive(ArgEnum, Debug, PartialEq)] +#[derive(ArgEnum, Debug, PartialEq, Clone)] enum GeneratorChoice { Bash, Elvish, diff --git a/clap_derive/src/derives/arg_enum.rs b/clap_derive/src/derives/arg_enum.rs index 1211e829049..8d6a878f095 100644 --- a/clap_derive/src/derives/arg_enum.rs +++ b/clap_derive/src/derives/arg_enum.rs @@ -48,7 +48,6 @@ pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStr let lits = lits(&e.variants, &attrs); let arg_values = gen_arg_values(&lits); - let from_str = gen_from_str(&lits); let arg_value = gen_arg_value(&lits); quote! { @@ -66,7 +65,6 @@ pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStr #[deny(clippy::correctness)] impl clap::ArgEnum for #name { #arg_values - #from_str #arg_value } } @@ -102,24 +100,11 @@ fn lits( } fn gen_arg_values(lits: &[(TokenStream, Ident)]) -> TokenStream { - let lit = lits.iter().map(|l| &l.0).collect::>(); + let lit = lits.iter().map(|l| &l.1).collect::>(); quote! { - fn arg_values() -> Vec> { - vec![#(#lit),*] - } - } -} - -fn gen_from_str(lits: &[(TokenStream, Ident)]) -> TokenStream { - let (lit, variant): (Vec, Vec) = lits.iter().cloned().unzip(); - - quote! { - fn from_str(input: &str, case_insensitive: bool) -> ::std::result::Result { - match input { - #(val if #lit.matches(val, case_insensitive) => Ok(Self::#variant),)* - e => Err(format!("Invalid variant: {}", e)), - } + fn value_variants<'a>() -> &'a [Self]{ + &[#(Self::#lit),*] } } } @@ -128,7 +113,7 @@ fn gen_arg_value(lits: &[(TokenStream, Ident)]) -> TokenStream { let (lit, variant): (Vec, Vec) = lits.iter().cloned().unzip(); quote! { - fn arg_value(&self) -> Option> { + fn arg_value<'a>(&self) -> Option> { match self { #(Self::#variant => Some(#lit),)* _ => None diff --git a/clap_derive/src/derives/args.rs b/clap_derive/src/derives/args.rs index 0cceb291db9..ec7b6fdbb2b 100644 --- a/clap_derive/src/derives/args.rs +++ b/clap_derive/src/derives/args.rs @@ -361,7 +361,7 @@ pub fn gen_augment( fn gen_arg_enum_possible_values(ty: &Type) -> TokenStream { quote_spanned! { ty.span()=> - .possible_values(<#ty as clap::ArgEnum>::arg_values()) + .possible_values(<#ty as clap::ArgEnum>::value_variants().iter().filter_map(clap::ArgEnum::arg_value)) } } diff --git a/clap_derive/tests/arg_enum.rs b/clap_derive/tests/arg_enum.rs index 84c816cd8f8..f68cc70ce5d 100644 --- a/clap_derive/tests/arg_enum.rs +++ b/clap_derive/tests/arg_enum.rs @@ -11,7 +11,7 @@ use clap::{ArgEnum, ArgValue, Clap}; #[test] fn basic() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { Foo, Bar, @@ -40,7 +40,7 @@ fn basic() { #[test] fn default_value() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { Foo, Bar, @@ -86,7 +86,7 @@ fn default_value() { #[test] fn multi_word_is_renamed_kebab() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] #[allow(non_camel_case_types)] enum ArgChoice { FooBar, @@ -116,7 +116,7 @@ fn multi_word_is_renamed_kebab() { #[test] fn variant_with_defined_casing() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { #[clap(rename_all = "screaming_snake")] FooBar, @@ -139,7 +139,7 @@ fn variant_with_defined_casing() { #[test] fn casing_is_propogated_from_parent() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] #[clap(rename_all = "screaming_snake")] enum ArgChoice { FooBar, @@ -162,7 +162,7 @@ fn casing_is_propogated_from_parent() { #[test] fn casing_propogation_is_overridden() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] #[clap(rename_all = "screaming_snake")] enum ArgChoice { #[clap(rename_all = "camel")] @@ -187,7 +187,7 @@ fn casing_propogation_is_overridden() { #[test] fn case_insensitive() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { Foo, } @@ -214,7 +214,7 @@ fn case_insensitive() { #[test] fn case_insensitive_set_to_false() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { Foo, } @@ -236,7 +236,7 @@ fn case_insensitive_set_to_false() { #[test] fn alias() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { #[clap(alias = "TOTP")] TOTP, @@ -264,7 +264,7 @@ fn alias() { #[test] fn multiple_alias() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { #[clap(alias = "TOTP", alias = "t")] TOTP, @@ -298,7 +298,7 @@ fn multiple_alias() { #[test] fn option() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { Foo, Bar, @@ -328,7 +328,7 @@ fn option() { #[test] fn vector() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { Foo, Bar, @@ -358,7 +358,7 @@ fn vector() { #[test] fn skip_variant() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] #[allow(dead_code)] // silence warning about `Baz` being unused enum ArgChoice { Foo, @@ -368,7 +368,11 @@ fn skip_variant() { } assert_eq!( - ArgChoice::arg_values(), + ArgChoice::value_variants() + .iter() + .map(ArgEnum::arg_value) + .map(Option::unwrap) + .collect::>(), vec![ArgValue::new("foo"), ArgValue::new("bar")] ); assert!(ArgChoice::from_str("foo", true).is_ok()); @@ -378,7 +382,7 @@ fn skip_variant() { #[test] fn from_str_invalid() { - #[derive(ArgEnum, PartialEq, Debug)] + #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { Foo, } diff --git a/src/derive.rs b/src/derive.rs index 3edb39c3e50..133ffbc308e 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -273,7 +273,7 @@ pub trait Subcommand: FromArgMatches + Sized { /// level: Level, /// } /// -/// #[derive(clap::ArgEnum)] +/// #[derive(clap::ArgEnum, Clone)] /// enum Level { /// Debug, /// Info, @@ -281,17 +281,23 @@ pub trait Subcommand: FromArgMatches + Sized { /// Error, /// } /// ``` -pub trait ArgEnum: Sized { +pub trait ArgEnum: Sized + Clone { /// All possible argument values, in display order. - fn arg_values() -> Vec>; + fn value_variants<'a>() -> &'a [Self]; /// Parse an argument into `Self`. - fn from_str(input: &str, case_insensitive: bool) -> Result; + fn from_str(input: &str, case_insensitive: bool) -> Result { + Self::value_variants() + .iter() + .find(|v| v.arg_value().unwrap().matches(input, case_insensitive)) + .cloned() + .ok_or_else(|| format!("Invalid variant: {}", input)) + } /// The canonical argument value. /// /// The value is `None` for skipped variants. - fn arg_value(&self) -> Option>; + fn arg_value<'a>(&self) -> Option>; } impl Clap for Box { From 15fcf814c2250318f22b9ea4f12a84c445260c88 Mon Sep 17 00:00:00 2001 From: ModProg Date: Wed, 29 Sep 2021 18:46:08 +0200 Subject: [PATCH 08/10] fix dummies --- clap_derive/src/dummies.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clap_derive/src/dummies.rs b/clap_derive/src/dummies.rs index ecc63277887..0f04567e770 100644 --- a/clap_derive/src/dummies.rs +++ b/clap_derive/src/dummies.rs @@ -76,13 +76,13 @@ pub fn args(name: &Ident) { pub fn arg_enum(name: &Ident) { append_dummy(quote! { impl clap::ArgEnum for #name { - fn arg_values() -> Vec> { + fn value_variants<'a>() -> &'a [Self]{ unimplemented!() } fn from_str(_input: &str, _case_insensitive: bool) -> Result { unimplemented!() } - fn arg_value(&self) -> Option> { + fn arg_value<'a>(&self) -> Option>{ unimplemented!() } } From d53778ed5db0cb79400d4229010b2963c3e5e5a2 Mon Sep 17 00:00:00 2001 From: ModProg Date: Wed, 29 Sep 2021 19:31:05 +0200 Subject: [PATCH 09/10] fix ui --- clap_derive/tests/ui/arg_enum_on_struct.rs | 4 ++-- clap_derive/tests/ui/arg_enum_on_struct.stderr | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clap_derive/tests/ui/arg_enum_on_struct.rs b/clap_derive/tests/ui/arg_enum_on_struct.rs index 27f9a9502c8..a26c9658aac 100644 --- a/clap_derive/tests/ui/arg_enum_on_struct.rs +++ b/clap_derive/tests/ui/arg_enum_on_struct.rs @@ -1,8 +1,8 @@ use clap::ArgEnum; -#[derive(ArgEnum, Debug)] +#[derive(ArgEnum, Clone, Debug)] struct Opt {} fn main() { - println!("{:?}", Opt::arg_values()); + println!("{:?}", Opt::value_variants()); } diff --git a/clap_derive/tests/ui/arg_enum_on_struct.stderr b/clap_derive/tests/ui/arg_enum_on_struct.stderr index d83386a4118..3b7175d7c93 100644 --- a/clap_derive/tests/ui/arg_enum_on_struct.stderr +++ b/clap_derive/tests/ui/arg_enum_on_struct.stderr @@ -1,7 +1,7 @@ error: `#[derive(ArgEnum)]` only supports enums --> $DIR/arg_enum_on_struct.rs:3:10 | -3 | #[derive(ArgEnum, Debug)] +3 | #[derive(ArgEnum, Clone, Debug)] | ^^^^^^^ | = note: this error originates in the derive macro `ArgEnum` (in Nightly builds, run with -Z macro-backtrace for more info) From 47ff3ed94578f2a9963dd56bca4d6f193f85fcf6 Mon Sep 17 00:00:00 2001 From: ModProg Date: Wed, 29 Sep 2021 20:55:47 +0200 Subject: [PATCH 10/10] documentation for ArgValue --- src/build/arg/arg_value.rs | 46 ++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/src/build/arg/arg_value.rs b/src/build/arg/arg_value.rs index 6b7d45e3769..af655579fda 100644 --- a/src/build/arg/arg_value.rs +++ b/src/build/arg/arg_value.rs @@ -65,12 +65,28 @@ impl<'help> ArgValue<'help> { } } - /// TODO + /// Returns all valid values of the argument value. + /// Namely the name and all aliases. pub fn get_name_and_aliases(&self) -> impl Iterator { iter::once(&self.name).chain(&self.aliases).copied() } - /// TODO + /// Tests if the value is valid for this argument value + /// + /// The value is valid if it is either the name or one of the aliases. + /// + /// # Examples + /// + /// ```rust + /// # use clap::ArgValue; + /// let arg_value = ArgValue::new("fast").alias("not-slow"); + /// + /// assert!(arg_value.matches("fast", false)); + /// assert!(arg_value.matches("not-slow", false)); + /// + /// assert!(arg_value.matches("FAST", true)); + /// assert!(!arg_value.matches("FAST", false)); + /// ``` pub fn matches(&self, value: &str, ignore_case: bool) -> bool { if ignore_case { self.get_name_and_aliases() @@ -142,13 +158,35 @@ impl<'help> ArgValue<'help> { self } - /// TODO + /// Sets an alias for this argument value. + /// + /// The alias will be hidden from completion and help texts. + /// + /// # Examples + /// + /// ```rust + /// # use clap::ArgValue; + /// ArgValue::new("slow") + /// .alias("not-fast") + /// # ; + /// ``` pub fn alias(mut self, name: &'help str) -> Self { self.aliases.push(name); self } - /// TODO + /// Sets multiple aliases for this argument value. + /// + /// The aliases will be hidden from completion and help texts. + /// + /// # Examples + /// + /// ```rust + /// # use clap::ArgValue; + /// ArgValue::new("slow") + /// .aliases(["not-fast", "snake-like"]) + /// # ; + /// ``` pub fn aliases(mut self, names: I) -> Self where I: IntoIterator,