fix: Deprecate validator / validator_os

`validator_regex` is being ignored for now as I await on a comment
period for #3743
This commit is contained in:
Ed Page 2022-05-23 15:42:34 -05:00
parent f15a1aab1a
commit 177511dab1
36 changed files with 246 additions and 239 deletions

View file

@ -3,7 +3,7 @@
// //
// CLI used is adapted from ripgrep 48a8a3a691220f9e5b2b08f4051abe8655ea7e8a // CLI used is adapted from ripgrep 48a8a3a691220f9e5b2b08f4051abe8655ea7e8a
use clap::{Arg, Command}; use clap::{value_parser, Arg, Command};
use criterion::{criterion_group, criterion_main, Criterion}; use criterion::{criterion_group, criterion_main, Criterion};
use std::collections::HashMap; use std::collections::HashMap;
use std::io::Cursor; use std::io::Cursor;
@ -394,19 +394,19 @@ where
flag("after-context") flag("after-context")
.short('A') .short('A')
.value_name("NUM") .value_name("NUM")
.validator(validate_number), .value_parser(value_parser!(usize)),
) )
.arg( .arg(
flag("before-context") flag("before-context")
.short('B') .short('B')
.value_name("NUM") .value_name("NUM")
.validator(validate_number), .value_parser(value_parser!(usize)),
) )
.arg( .arg(
flag("context") flag("context")
.short('C') .short('C')
.value_name("NUM") .value_name("NUM")
.validator(validate_number), .value_parser(value_parser!(usize)),
) )
.arg(flag("column")) .arg(flag("column"))
.arg(flag("context-separator").value_name("SEPARATOR")) .arg(flag("context-separator").value_name("SEPARATOR"))
@ -434,12 +434,12 @@ where
flag("max-count") flag("max-count")
.short('m') .short('m')
.value_name("NUM") .value_name("NUM")
.validator(validate_number), .value_parser(value_parser!(usize)),
) )
.arg( .arg(
flag("maxdepth") flag("maxdepth")
.value_name("NUM") .value_name("NUM")
.validator(validate_number), .value_parser(value_parser!(usize)),
) )
.arg(flag("mmap")) .arg(flag("mmap"))
.arg(flag("no-messages")) .arg(flag("no-messages"))
@ -458,7 +458,7 @@ where
flag("threads") flag("threads")
.short('j') .short('j')
.value_name("ARG") .value_name("ARG")
.validator(validate_number), .value_parser(value_parser!(usize)),
) )
.arg(flag("vimgrep")) .arg(flag("vimgrep"))
.arg( .arg(
@ -933,12 +933,6 @@ lazy_static! {
}; };
} }
fn validate_number(s: &str) -> Result<(), String> {
s.parse::<usize>()
.map(|_| ())
.map_err(|err| err.to_string())
}
criterion_group!( criterion_group!(
benches, benches,
build_rg_with_short_help, build_rg_with_short_help,

View file

@ -26,34 +26,34 @@ use std::path::PathBuf;
)] )]
struct Opt { struct Opt {
/// If provided, outputs the completion file for given shell /// If provided, outputs the completion file for given shell
#[clap(long = "generate", arg_enum)] #[clap(long = "generate", arg_enum, value_parser)]
generator: Option<Shell>, generator: Option<Shell>,
// Showcasing all possible ValueHints: // Showcasing all possible ValueHints:
#[clap(long, value_hint = ValueHint::Unknown)] #[clap(long, value_hint = ValueHint::Unknown, value_parser)]
unknown: Option<String>, unknown: Option<String>,
#[clap(long, value_hint = ValueHint::Other)] #[clap(long, value_hint = ValueHint::Other, value_parser)]
other: Option<String>, other: Option<String>,
#[clap(short, long, value_hint = ValueHint::AnyPath)] #[clap(short, long, value_hint = ValueHint::AnyPath, value_parser)]
path: Option<PathBuf>, path: Option<PathBuf>,
#[clap(short, long, value_hint = ValueHint::FilePath)] #[clap(short, long, value_hint = ValueHint::FilePath, value_parser)]
file: Option<PathBuf>, file: Option<PathBuf>,
#[clap(short, long, value_hint = ValueHint::DirPath)] #[clap(short, long, value_hint = ValueHint::DirPath, value_parser)]
dir: Option<PathBuf>, dir: Option<PathBuf>,
#[clap(short, long, value_hint = ValueHint::ExecutablePath)] #[clap(short, long, value_hint = ValueHint::ExecutablePath, value_parser)]
exe: Option<PathBuf>, exe: Option<PathBuf>,
#[clap(long, parse(from_os_str), value_hint = ValueHint::CommandName)] #[clap(long, value_hint = ValueHint::CommandName, value_parser)]
cmd_name: Option<OsString>, cmd_name: Option<OsString>,
#[clap(short, long, value_hint = ValueHint::CommandString)] #[clap(short, long, value_hint = ValueHint::CommandString, value_parser)]
cmd: Option<String>, cmd: Option<String>,
#[clap(value_hint = ValueHint::CommandWithArguments)] #[clap(value_hint = ValueHint::CommandWithArguments, value_parser)]
command_with_args: Vec<String>, command_with_args: Vec<String>,
#[clap(short, long, value_hint = ValueHint::Username)] #[clap(short, long, value_hint = ValueHint::Username, value_parser)]
user: Option<String>, user: Option<String>,
#[clap(short, long, value_hint = ValueHint::Hostname)] #[clap(short, long, value_hint = ValueHint::Hostname, value_parser)]
host: Option<String>, host: Option<String>,
#[clap(long, value_hint = ValueHint::Url)] #[clap(long, value_hint = ValueHint::Url, value_parser)]
url: Option<String>, url: Option<String>,
#[clap(long, value_hint = ValueHint::EmailAddress)] #[clap(long, value_hint = ValueHint::EmailAddress, value_parser)]
email: Option<String>, email: Option<String>,
} }

View file

@ -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:31] opt = Opt { [examples/derive_ref/custom-bool.rs:32] 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:31] opt = Opt { [examples/derive_ref/custom-bool.rs:32] opt = Opt {
foo: true, foo: true,
bar: true, bar: true,
boom: false, boom: false,

View file

@ -1,3 +1,4 @@
#![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)]

View file

@ -1557,43 +1557,10 @@ impl<'help> Arg<'help> {
self.takes_value(true) self.takes_value(true)
} }
/// Perform a custom validation on the argument value. /// Deprecated, replaced with [`Arg::value_parser(...)`]
/// #[inline]
/// You provide a closure
/// which accepts a [`&str`] value, and return a [`Result`] where the [`Err(String)`] is a
/// message displayed to the user.
///
/// **NOTE:** The error message does *not* need to contain the `error:` portion, only the
/// message as all errors will appear as
/// `error: Invalid value for '<arg>': <YOUR MESSAGE>` where `<arg>` is replaced by the actual
/// arg, and `<YOUR MESSAGE>` is the `String` you return as the error.
///
/// **NOTE:** There is a small performance hit for using validators, as they are implemented
/// with [`Arc`] pointers. And the value to be checked will be allocated an extra time in order
/// to be passed to the closure. This performance hit is extremely minimal in the grand
/// scheme of things.
///
/// # Examples
///
/// ```rust
/// # use clap::{Command, Arg};
/// fn has_at(v: &str) -> Result<(), String> {
/// if v.contains("@") { return Ok(()); }
/// Err(String::from("The value did not contain the required @ sigil"))
/// }
/// let res = Command::new("prog")
/// .arg(Arg::new("file")
/// .validator(has_at))
/// .try_get_matches_from(vec![
/// "prog", "some@file"
/// ]);
/// assert!(res.is_ok());
/// assert_eq!(res.unwrap().value_of("file"), Some("some@file"));
/// ```
/// [`Result`]: std::result::Result
/// [`Err(String)`]: std::result::Result::Err
/// [`Arc`]: std::sync::Arc
#[must_use] #[must_use]
#[deprecated(since = "3.2.0", note = "Replaced with `Arg::value_parser(...)`")]
pub fn validator<F, O, E>(mut self, mut f: F) -> Self pub fn validator<F, O, E>(mut self, mut f: F) -> Self
where where
F: FnMut(&str) -> Result<O, E> + Send + 'help, F: FnMut(&str) -> Result<O, E> + Send + 'help,
@ -1605,37 +1572,9 @@ impl<'help> Arg<'help> {
self self
} }
/// Perform a custom validation on the argument value. /// Deprecated, replaced with [`Arg::value_parser(...)`]
///
/// See [validator][Arg::validator].
///
/// # Examples
///
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```rust")]
/// # use clap::{Command, Arg};
/// # use std::ffi::{OsStr, OsString};
/// # use std::os::unix::ffi::OsStrExt;
/// fn has_ampersand(v: &OsStr) -> Result<(), String> {
/// if v.as_bytes().iter().any(|b| *b == b'&') { return Ok(()); }
/// Err(String::from("The value did not contain the required & sigil"))
/// }
/// let res = Command::new("prog")
/// .arg(Arg::new("file")
/// .validator_os(has_ampersand))
/// .try_get_matches_from(vec![
/// "prog", "Fish & chips"
/// ]);
/// assert!(res.is_ok());
/// assert_eq!(res.unwrap().value_of("file"), Some("Fish & chips"));
/// ```
/// [`String`]: std::string::String
/// [`OsStr`]: std::ffi::OsStr
/// [`OsString`]: std::ffi::OsString
/// [`Result`]: std::result::Result
/// [`Err(String)`]: std::result::Result::Err
/// [`Rc`]: std::rc::Rc
#[must_use] #[must_use]
#[deprecated(since = "3.2.0", note = "Replaced with `Arg::value_parser(...)`")]
pub fn validator_os<F, O, E>(mut self, mut f: F) -> Self pub fn validator_os<F, O, E>(mut self, mut f: F) -> Self
where where
F: FnMut(&OsStr) -> Result<O, E> + Send + 'help, F: FnMut(&OsStr) -> Result<O, E> + Send + 'help,

View file

@ -810,5 +810,28 @@ fn assert_defaults<'d>(
); );
} }
} }
let value_parser = arg.get_value_parser();
let assert_cmd = Command::new("assert");
if let Some(delim) = arg.get_value_delimiter() {
let default_os = RawOsStr::new(default_os);
for part in default_os.split(delim) {
if let Err(err) = value_parser.parse_ref(&assert_cmd, Some(arg), &part.to_os_str())
{
panic!(
"Argument `{}`'s {}={:?} failed validation: {}",
arg.name,
field,
part.to_str_lossy(),
err
);
}
}
} else if let Err(err) = value_parser.parse_ref(&assert_cmd, Some(arg), default_os) {
panic!(
"Argument `{}`'s {}={:?} failed validation: {}",
arg.name, field, default_os, err
);
}
} }
} }

View file

@ -173,14 +173,14 @@ fn default_missing_values_are_possible_values() {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
#[test] #[test]
#[should_panic = "Argument `arg`'s default_missing_value=value failed validation: invalid digit found in string"] #[should_panic = "Argument `arg`'s default_missing_value=\"value\" failed validation: error: Invalid value \"value\" for '<arg>"]
fn default_missing_values_are_valid() { fn default_missing_values_are_valid() {
use clap::{Arg, Command}; use clap::{Arg, Command};
let _ = Command::new("test") let _ = Command::new("test")
.arg( .arg(
Arg::new("arg") Arg::new("arg")
.validator(|val| val.parse::<u32>().map_err(|e| e.to_string())) .value_parser(clap::value_parser!(u32))
.default_missing_value("value"), .default_missing_value("value"),
) )
.try_get_matches(); .try_get_matches();

View file

@ -652,14 +652,14 @@ fn default_values_are_possible_values() {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
#[test] #[test]
#[should_panic = "Argument `arg`'s default_value=one failed validation: invalid digit found in string"] #[should_panic = "Argument `arg`'s default_value=\"one\" failed validation: error: Invalid value \"one\" for '<arg>"]
fn invalid_default_values() { fn invalid_default_values() {
use clap::{Arg, Command}; use clap::{Arg, Command};
let _ = Command::new("test") let _ = Command::new("test")
.arg( .arg(
Arg::new("arg") Arg::new("arg")
.validator(|val| val.parse::<u32>().map_err(|e| e.to_string())) .value_parser(clap::value_parser!(u32))
.default_value("one"), .default_value("one"),
) )
.try_get_matches(); .try_get_matches();
@ -672,7 +672,7 @@ fn valid_delimited_default_values() {
let _ = Command::new("test") let _ = Command::new("test")
.arg( .arg(
Arg::new("arg") Arg::new("arg")
.validator(|val| val.parse::<u32>().map_err(|e| e.to_string())) .value_parser(clap::value_parser!(u32))
.use_value_delimiter(true) .use_value_delimiter(true)
.require_value_delimiter(true) .require_value_delimiter(true)
.default_value("1,2,3"), .default_value("1,2,3"),
@ -682,14 +682,14 @@ fn valid_delimited_default_values() {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
#[test] #[test]
#[should_panic = "Argument `arg`'s default_value=one failed validation: invalid digit found in string"] #[should_panic = "Argument `arg`'s default_value=\"one\" failed validation: error: Invalid value \"one\" for '<arg>"]
fn invalid_delimited_default_values() { fn invalid_delimited_default_values() {
use clap::{Arg, Command}; use clap::{Arg, Command};
let _ = Command::new("test") let _ = Command::new("test")
.arg( .arg(
Arg::new("arg") Arg::new("arg")
.validator(|val| val.parse::<u32>().map_err(|e| e.to_string())) .value_parser(clap::value_parser!(u32))
.use_value_delimiter(true) .use_value_delimiter(true)
.require_value_delimiter(true) .require_value_delimiter(true)
.default_value("one,two"), .default_value("one,two"),

View file

@ -287,7 +287,7 @@ fn not_possible_value() {
} }
#[test] #[test]
fn validator() { fn value_parser() {
env::set_var("CLP_TEST_ENV_VDOR", "env"); env::set_var("CLP_TEST_ENV_VDOR", "env");
let r = Command::new("df") let r = Command::new("df")
@ -295,11 +295,11 @@ fn validator() {
arg!([arg] "some opt") arg!([arg] "some opt")
.env("CLP_TEST_ENV_VDOR") .env("CLP_TEST_ENV_VDOR")
.takes_value(true) .takes_value(true)
.validator(|s| { .value_parser(|s: &str| -> Result<String, String> {
if s == "env" { if s == "env" {
Ok(()) Ok(s.to_owned())
} else { } else {
Err("not equal".to_string()) Err("not equal".to_owned())
} }
}), }),
) )
@ -313,7 +313,7 @@ fn validator() {
} }
#[test] #[test]
fn validator_output() { fn value_parser_output() {
env::set_var("CLP_TEST_ENV_VO", "42"); env::set_var("CLP_TEST_ENV_VO", "42");
let m = Command::new("df") let m = Command::new("df")
@ -321,16 +321,16 @@ fn validator_output() {
arg!([arg] "some opt") arg!([arg] "some opt")
.env("CLP_TEST_ENV_VO") .env("CLP_TEST_ENV_VO")
.takes_value(true) .takes_value(true)
.validator(|s| s.parse::<i32>()), .value_parser(clap::value_parser!(i32)),
) )
.try_get_matches_from(vec![""]) .try_get_matches_from(vec![""])
.unwrap(); .unwrap();
assert_eq!(m.value_of("arg").unwrap().parse(), Ok(42)); assert_eq!(*m.get_one::<i32>("arg").unwrap(), 42);
} }
#[test] #[test]
fn validator_invalid() { fn value_parser_invalid() {
env::set_var("CLP_TEST_ENV_IV", "env"); env::set_var("CLP_TEST_ENV_IV", "env");
let r = Command::new("df") let r = Command::new("df")
@ -338,9 +338,9 @@ fn validator_invalid() {
arg!([arg] "some opt") arg!([arg] "some opt")
.env("CLP_TEST_ENV_IV") .env("CLP_TEST_ENV_IV")
.takes_value(true) .takes_value(true)
.validator(|s| { .value_parser(|s: &str| -> Result<String, String> {
if s != "env" { if s != "env" {
Ok(()) Ok(s.to_owned())
} else { } else {
Err("is equal".to_string()) Err("is equal".to_string())
} }

View file

@ -1,3 +1,5 @@
#![allow(deprecated)]
use clap::{Arg, Command}; use clap::{Arg, Command};
#[cfg(debug_assertions)] #[cfg(debug_assertions)]

View file

@ -19,6 +19,7 @@ use clap::Parser;
fn required_argument() { fn required_argument() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(value_parser)]
arg: i32, arg: i32,
} }
assert_eq!( assert_eq!(
@ -33,7 +34,7 @@ fn required_argument() {
fn argument_with_default() { fn argument_with_default() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(default_value = "42")] #[clap(value_parser, default_value = "42")]
arg: i32, arg: i32,
} }
assert_eq!( assert_eq!(
@ -48,6 +49,7 @@ fn argument_with_default() {
fn auto_value_name() { fn auto_value_name() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(value_parser)]
my_special_arg: i32, my_special_arg: i32,
} }
@ -67,7 +69,7 @@ fn auto_value_name() {
fn explicit_value_name() { fn explicit_value_name() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(value_name = "BROWNIE_POINTS")] #[clap(value_parser, value_name = "BROWNIE_POINTS")]
my_special_arg: i32, my_special_arg: i32,
} }
@ -88,6 +90,7 @@ fn explicit_value_name() {
fn option_type_is_optional() { fn option_type_is_optional() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(value_parser)]
arg: Option<i32>, arg: Option<i32>,
} }
assert_eq!( assert_eq!(
@ -102,6 +105,7 @@ fn option_type_is_optional() {
fn vec_type_is_multiple_values() { fn vec_type_is_multiple_values() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(value_parser)]
arg: Vec<i32>, arg: Vec<i32>,
} }
assert_eq!( assert_eq!(

View file

@ -18,7 +18,7 @@ use clap::Parser;
fn basic() { fn basic() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short = 'a', long = "arg")] #[clap(short = 'a', long = "arg", value_parser)]
arg: i32, arg: i32,
} }
assert_eq!( assert_eq!(
@ -31,7 +31,7 @@ fn basic() {
fn update_basic() { fn update_basic() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short = 'a', long = "arg")] #[clap(short = 'a', long = "arg", value_parser)]
single_value: i32, single_value: i32,
} }

View file

@ -16,6 +16,7 @@ enum Sub {
#[derive(Args, PartialEq, Debug)] #[derive(Args, PartialEq, Debug)]
struct Ext { struct Ext {
#[clap(value_parser)]
arg: u32, arg: u32,
} }

View file

@ -12,27 +12,29 @@
// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the // commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
// MIT/Apache 2.0 license. // MIT/Apache 2.0 license.
#![allow(deprecated)]
use clap::Parser; use clap::Parser;
use std::ffi::{CString, OsStr}; use std::ffi::CString;
use std::num::ParseIntError; use std::num::ParseIntError;
use std::path::PathBuf; use std::path::PathBuf;
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct PathOpt { struct PathOpt {
#[clap(short, long, parse(from_os_str))] #[clap(short, long, value_parser)]
path: PathBuf, path: PathBuf,
#[clap(short, default_value = "../", parse(from_os_str))] #[clap(short, default_value = "../", value_parser)]
default_path: PathBuf, default_path: PathBuf,
#[clap(short, parse(from_os_str), multiple_occurrences(true))] #[clap(short, value_parser, multiple_occurrences(true))]
vector_path: Vec<PathBuf>, vector_path: Vec<PathBuf>,
#[clap(short, parse(from_os_str))] #[clap(short, value_parser)]
option_path_1: Option<PathBuf>, option_path_1: Option<PathBuf>,
#[clap(short = 'q', parse(from_os_str))] #[clap(short = 'q', value_parser)]
option_path_2: Option<PathBuf>, option_path_2: Option<PathBuf>,
} }
@ -64,7 +66,7 @@ fn parse_hex(input: &str) -> Result<u64, ParseIntError> {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct HexOpt { struct HexOpt {
#[clap(short, parse(try_from_str = parse_hex))] #[clap(short, value_parser = parse_hex)]
number: u64, number: u64,
} }
@ -89,9 +91,6 @@ fn test_parse_hex() {
); );
} }
fn custom_parser_1(_: &str) -> &'static str {
"A"
}
#[derive(Debug)] #[derive(Debug)]
struct ErrCode(u32); struct ErrCode(u32);
impl std::error::Error for ErrCode {} impl std::error::Error for ErrCode {}
@ -103,59 +102,28 @@ impl std::fmt::Display for ErrCode {
fn custom_parser_2(_: &str) -> Result<&'static str, ErrCode> { fn custom_parser_2(_: &str) -> Result<&'static str, ErrCode> {
Ok("B") Ok("B")
} }
fn custom_parser_3(_: &OsStr) -> &'static str {
"C"
}
fn custom_parser_4(_: &OsStr) -> Result<&'static str, String> {
Ok("D")
}
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct NoOpOpt { struct NoOpOpt {
#[clap(short, parse(from_str = custom_parser_1))] #[clap(short, value_parser = custom_parser_2)]
a: &'static str,
#[clap(short, parse(try_from_str = custom_parser_2))]
b: &'static str, b: &'static str,
#[clap(short, parse(from_os_str = custom_parser_3))]
c: &'static str,
#[clap(short, parse(try_from_os_str = custom_parser_4))]
d: &'static str,
} }
#[test] #[test]
fn test_every_custom_parser() { fn test_every_custom_parser() {
assert_eq!( assert_eq!(
NoOpOpt { NoOpOpt { b: "B" },
a: "A", NoOpOpt::try_parse_from(&["test", "-b=?"]).unwrap()
b: "B",
c: "C",
d: "D"
},
NoOpOpt::try_parse_from(&["test", "-a=?", "-b=?", "-c=?", "-d=?"]).unwrap()
); );
} }
#[test] #[test]
fn update_every_custom_parser() { fn update_every_custom_parser() {
let mut opt = NoOpOpt { let mut opt = NoOpOpt { b: "0" };
a: "0",
b: "0",
c: "0",
d: "D",
};
opt.try_update_from(&["test", "-a=?", "-b=?", "-d=?"]) opt.try_update_from(&["test", "-b=?"]).unwrap();
.unwrap();
assert_eq!( assert_eq!(NoOpOpt { b: "B" }, opt);
NoOpOpt {
a: "A",
b: "B",
c: "0",
d: "D"
},
opt
);
} }
// Note: can't use `Vec<u8>` directly, as clap would instead look for // Note: can't use `Vec<u8>` directly, as clap would instead look for
@ -167,10 +135,10 @@ struct DefaultedOpt {
#[clap(short, parse(from_str))] #[clap(short, parse(from_str))]
bytes: Bytes, bytes: Bytes,
#[clap(short, parse(try_from_str))] #[clap(short, value_parser)]
integer: u64, integer: u64,
#[clap(short, parse(from_os_str))] #[clap(short, value_parser)]
path: PathBuf, path: PathBuf,
} }

View file

@ -6,7 +6,7 @@ use crate::utils;
fn default_value() { fn default_value() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(default_value = "3")] #[clap(value_parser, default_value = "3")]
arg: i32, arg: i32,
} }
assert_eq!(Opt { arg: 3 }, Opt::try_parse_from(&["test"]).unwrap()); assert_eq!(Opt { arg: 3 }, Opt::try_parse_from(&["test"]).unwrap());
@ -20,7 +20,7 @@ fn default_value() {
fn default_value_t() { fn default_value_t() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(default_value_t = 3)] #[clap(value_parser, default_value_t = 3)]
arg: i32, arg: i32,
} }
assert_eq!(Opt { arg: 3 }, Opt::try_parse_from(&["test"]).unwrap()); assert_eq!(Opt { arg: 3 }, Opt::try_parse_from(&["test"]).unwrap());
@ -34,7 +34,7 @@ fn default_value_t() {
fn auto_default_value_t() { fn auto_default_value_t() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(default_value_t)] #[clap(value_parser, default_value_t)]
arg: i32, arg: i32,
} }
assert_eq!(Opt { arg: 0 }, Opt::try_parse_from(&["test"]).unwrap()); assert_eq!(Opt { arg: 0 }, Opt::try_parse_from(&["test"]).unwrap());
@ -50,7 +50,7 @@ fn detect_os_variant() {
#[derive(clap::Parser)] #[derive(clap::Parser)]
pub struct Options { pub struct Options {
#[clap(default_value_os = ("123".as_ref()))] #[clap(value_parser, default_value_os = ("123".as_ref()))]
x: String, x: String,
} }
Options::command().debug_assert(); Options::command().debug_assert();

View file

@ -24,7 +24,7 @@ fn try_str(s: &str) -> Result<String, std::convert::Infallible> {
fn warning_never_struct() { fn warning_never_struct() {
#[derive(Parser, Debug, PartialEq)] #[derive(Parser, Debug, PartialEq)]
struct Opt { struct Opt {
#[clap(parse(try_from_str = try_str), default_value_t)] #[clap(value_parser = try_str, default_value_t)]
s: String, s: String,
} }
assert_eq!( assert_eq!(
@ -40,7 +40,7 @@ fn warning_never_enum() {
#[derive(Parser, Debug, PartialEq)] #[derive(Parser, Debug, PartialEq)]
enum Opt { enum Opt {
Foo { Foo {
#[clap(parse(try_from_str = try_str), default_value_t)] #[clap(value_parser = try_str, default_value_t)]
s: String, s: String,
}, },
} }

View file

@ -106,7 +106,7 @@ fn top_long_doc_comment_both_help_long_help() {
/// ///
/// Or something else /// Or something else
Foo { Foo {
#[clap(help = "foo")] #[clap(value_parser, help = "foo")]
bars: String, bars: String,
}, },
} }
@ -191,7 +191,7 @@ fn multiline_separates_default() {
/// Multiline /// Multiline
/// ///
/// Doc comment /// Doc comment
#[clap(long, default_value = "x")] #[clap(long, default_value = "x", value_parser)]
x: String, x: String,
} }
@ -229,7 +229,10 @@ fn doc_comment_about_handles_both_abouts() {
/// Sub doc comment body /// Sub doc comment body
#[derive(Parser, PartialEq, Eq, Debug)] #[derive(Parser, PartialEq, Eq, Debug)]
pub enum Sub { pub enum Sub {
Compress { output: String }, Compress {
#[clap(value_parser)]
output: String,
},
} }
let cmd = Opts::command(); let cmd = Opts::command();

View file

@ -6,7 +6,7 @@ use clap::Parser;
fn explicit_short_long_no_rename() { fn explicit_short_long_no_rename() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short = '.', long = ".foo")] #[clap(short = '.', long = ".foo", value_parser)]
foo: String, foo: String,
} }
@ -27,7 +27,7 @@ fn explicit_short_long_no_rename() {
fn explicit_name_no_rename() { fn explicit_name_no_rename() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(name = ".options")] #[clap(name = ".options", value_parser)]
foo: String, foo: String,
} }

View file

@ -12,6 +12,8 @@
// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the // commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
// MIT/Apache 2.0 license. // MIT/Apache 2.0 license.
#![allow(deprecated)]
use clap::Parser; use clap::Parser;
#[test] #[test]

View file

@ -20,6 +20,7 @@ use clap::{Args, Parser, Subcommand};
fn flatten() { fn flatten() {
#[derive(Args, PartialEq, Debug)] #[derive(Args, PartialEq, Debug)]
struct Common { struct Common {
#[clap(value_parser)]
arg: i32, arg: i32,
} }
@ -44,6 +45,7 @@ fn flatten() {
fn flatten_twice() { fn flatten_twice() {
#[derive(Args, PartialEq, Debug)] #[derive(Args, PartialEq, Debug)]
struct Common { struct Common {
#[clap(value_parser)]
arg: i32, arg: i32,
} }
@ -62,6 +64,7 @@ fn flatten_twice() {
fn flatten_in_subcommand() { fn flatten_in_subcommand() {
#[derive(Args, PartialEq, Debug)] #[derive(Args, PartialEq, Debug)]
struct Common { struct Common {
#[clap(value_parser)]
arg: i32, arg: i32,
} }
@ -105,6 +108,7 @@ fn flatten_in_subcommand() {
fn update_args_with_flatten() { fn update_args_with_flatten() {
#[derive(Args, PartialEq, Debug)] #[derive(Args, PartialEq, Debug)]
struct Common { struct Common {
#[clap(value_parser)]
arg: i32, arg: i32,
} }
@ -134,12 +138,15 @@ enum BaseCli {
#[derive(Args, PartialEq, Debug)] #[derive(Args, PartialEq, Debug)]
struct Command1 { struct Command1 {
#[clap(value_parser)]
arg1: i32, arg1: i32,
#[clap(value_parser)]
arg2: i32, arg2: i32,
} }
#[derive(Args, PartialEq, Debug)] #[derive(Args, PartialEq, Debug)]
struct Command2 { struct Command2 {
#[clap(value_parser)]
arg2: i32, arg2: i32,
} }
@ -192,6 +199,7 @@ fn flatten_with_doc_comment() {
#[derive(Args, PartialEq, Debug)] #[derive(Args, PartialEq, Debug)]
struct Common { struct Common {
/// This is an arg. Arg means "argument". Command line argument. /// This is an arg. Arg means "argument". Command line argument.
#[clap(value_parser)]
arg: i32, arg: i32,
} }

View file

@ -4,6 +4,7 @@ use clap::{Args, Parser};
fn generic_struct_flatten() { fn generic_struct_flatten() {
#[derive(Args, PartialEq, Debug)] #[derive(Args, PartialEq, Debug)]
struct Inner { struct Inner {
#[clap(value_parser)]
pub answer: isize, pub answer: isize,
} }
@ -25,6 +26,7 @@ fn generic_struct_flatten() {
fn generic_struct_flatten_w_where_clause() { fn generic_struct_flatten_w_where_clause() {
#[derive(Args, PartialEq, Debug)] #[derive(Args, PartialEq, Debug)]
struct Inner { struct Inner {
#[clap(value_parser)]
pub answer: isize, pub answer: isize,
} }
@ -49,6 +51,7 @@ fn generic_struct_flatten_w_where_clause() {
fn generic_enum() { fn generic_enum() {
#[derive(Args, PartialEq, Debug)] #[derive(Args, PartialEq, Debug)]
struct Inner { struct Inner {
#[clap(value_parser)]
pub answer: isize, pub answer: isize,
} }
@ -68,6 +71,7 @@ fn generic_enum() {
fn generic_enum_w_where_clause() { fn generic_enum_w_where_clause() {
#[derive(Args, PartialEq, Debug)] #[derive(Args, PartialEq, Debug)]
struct Inner { struct Inner {
#[clap(value_parser)]
pub answer: isize, pub answer: isize,
} }
@ -93,9 +97,10 @@ fn generic_w_fromstr_trait_bound() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt<T> struct Opt<T>
where where
T: FromStr, T: FromStr + Send + Sync + Clone + 'static,
<T as FromStr>::Err: std::error::Error + Sync + Send + 'static, <T as FromStr>::Err: std::error::Error + Sync + Send + 'static,
{ {
#[clap(value_parser)]
answer: T, answer: T,
} }
@ -111,6 +116,7 @@ fn generic_wo_trait_bound() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt<T> { struct Opt<T> {
#[clap(value_parser)]
answer: isize, answer: isize,
#[clap(skip)] #[clap(skip)]
took: Option<T>, took: Option<T>,
@ -132,9 +138,10 @@ fn generic_where_clause_w_trailing_comma() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt<T> struct Opt<T>
where where
T: FromStr, T: FromStr + Send + Sync + Clone + 'static,
<T as FromStr>::Err: std::error::Error + Sync + Send + 'static, <T as FromStr>::Err: std::error::Error + Sync + Send + 'static,
{ {
#[clap(value_parser)]
pub answer: T, pub answer: T,
} }

View file

@ -4,11 +4,11 @@ use clap::{AppSettings, Args, CommandFactory, Parser, Subcommand};
fn arg_help_heading_applied() { fn arg_help_heading_applied() {
#[derive(Debug, Clone, Parser)] #[derive(Debug, Clone, Parser)]
struct CliOptions { struct CliOptions {
#[clap(long)] #[clap(long, value_parser)]
#[clap(help_heading = Some("HEADING A"))] #[clap(help_heading = Some("HEADING A"))]
should_be_in_section_a: u32, should_be_in_section_a: u32,
#[clap(long)] #[clap(long, value_parser)]
no_section: u32, no_section: u32,
} }
@ -42,11 +42,11 @@ fn app_help_heading_applied() {
#[derive(Debug, Clone, Parser)] #[derive(Debug, Clone, Parser)]
#[clap(next_help_heading = "DEFAULT")] #[clap(next_help_heading = "DEFAULT")]
struct CliOptions { struct CliOptions {
#[clap(long)] #[clap(long, value_parser)]
#[clap(help_heading = Some("HEADING A"))] #[clap(help_heading = Some("HEADING A"))]
should_be_in_section_a: u32, should_be_in_section_a: u32,
#[clap(long)] #[clap(long, value_parser)]
should_be_in_default_section: u32, should_be_in_default_section: u32,
} }
@ -94,21 +94,21 @@ fn app_help_heading_flattened() {
#[clap(subcommand)] #[clap(subcommand)]
sub_a: SubA, sub_a: SubA,
#[clap(long)] #[clap(long, value_parser)]
should_be_in_default_section: u32, should_be_in_default_section: u32,
} }
#[derive(Debug, Clone, Args)] #[derive(Debug, Clone, Args)]
#[clap(next_help_heading = "HEADING A")] #[clap(next_help_heading = "HEADING A")]
struct OptionsA { struct OptionsA {
#[clap(long)] #[clap(long, value_parser)]
should_be_in_section_a: u32, should_be_in_section_a: u32,
} }
#[derive(Debug, Clone, Args)] #[derive(Debug, Clone, Args)]
#[clap(next_help_heading = "HEADING B")] #[clap(next_help_heading = "HEADING B")]
struct OptionsB { struct OptionsB {
#[clap(long)] #[clap(long, value_parser)]
should_be_in_section_b: u32, should_be_in_section_b: u32,
} }
@ -121,6 +121,7 @@ fn app_help_heading_flattened() {
SubAOne, SubAOne,
#[clap(next_help_heading = "SUB A")] #[clap(next_help_heading = "SUB A")]
SubATwo { SubATwo {
#[clap(value_parser)]
should_be_in_sub_a: u32, should_be_in_sub_a: u32,
}, },
} }
@ -128,13 +129,19 @@ fn app_help_heading_flattened() {
#[derive(Debug, Clone, Subcommand)] #[derive(Debug, Clone, Subcommand)]
enum SubB { enum SubB {
#[clap(next_help_heading = "SUB B")] #[clap(next_help_heading = "SUB B")]
SubBOne { should_be_in_sub_b: u32 }, SubBOne {
#[clap(value_parser)]
should_be_in_sub_b: u32,
},
} }
#[derive(Debug, Clone, Subcommand)] #[derive(Debug, Clone, Subcommand)]
enum SubC { enum SubC {
#[clap(next_help_heading = "SUB C")] #[clap(next_help_heading = "SUB C")]
SubCOne { should_be_in_sub_c: u32 }, SubCOne {
#[clap(value_parser)]
should_be_in_sub_c: u32,
},
} }
let cmd = CliOptions::command(); let cmd = CliOptions::command();
@ -230,7 +237,7 @@ fn flatten_field_with_help_heading() {
#[derive(Debug, Clone, Args)] #[derive(Debug, Clone, Args)]
struct OptionsA { struct OptionsA {
#[clap(long)] #[clap(long, value_parser)]
should_be_in_section_a: u32, should_be_in_section_a: u32,
} }
@ -257,7 +264,7 @@ fn derive_generated_error_has_full_context() {
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
#[clap(subcommand_negates_reqs = true)] #[clap(subcommand_negates_reqs = true)]
struct Opts { struct Opts {
#[clap(long)] #[clap(long, value_parser)]
req_str: String, req_str: String,
#[clap(subcommand)] #[clap(subcommand)]
@ -335,7 +342,7 @@ OPTIONS:
#[clap(long)] #[clap(long)]
flag_a: bool, flag_a: bool,
/// second option /// second option
#[clap(long)] #[clap(long, value_parser)]
option_a: Option<String>, option_a: Option<String>,
} }
@ -346,7 +353,7 @@ OPTIONS:
#[clap(long)] #[clap(long)]
flag_b: bool, flag_b: bool,
/// first option /// first option
#[clap(long)] #[clap(long, value_parser)]
option_b: Option<String>, option_b: Option<String>,
} }
@ -393,7 +400,7 @@ OPTIONS:
#[clap(long)] #[clap(long)]
flag_a: bool, flag_a: bool,
/// second option /// second option
#[clap(long)] #[clap(long, value_parser)]
option_a: Option<String>, option_a: Option<String>,
} }
@ -403,7 +410,7 @@ OPTIONS:
#[clap(long)] #[clap(long)]
flag_b: bool, flag_b: bool,
/// first option /// first option
#[clap(long)] #[clap(long, value_parser)]
option_b: Option<String>, option_b: Option<String>,
} }
@ -449,7 +456,7 @@ OPTIONS:
#[clap(long)] #[clap(long)]
flag_a: bool, flag_a: bool,
/// first option /// first option
#[clap(long)] #[clap(long, value_parser)]
option_a: Option<String>, option_a: Option<String>,
} }
@ -459,7 +466,7 @@ OPTIONS:
#[clap(long)] #[clap(long)]
flag_b: bool, flag_b: bool,
/// second option /// second option
#[clap(long)] #[clap(long, value_parser)]
option_b: Option<String>, option_b: Option<String>,
} }

View file

@ -89,6 +89,7 @@ fn issue_418() {
#[clap(visible_alias = "ret")] #[clap(visible_alias = "ret")]
Reticulate { Reticulate {
/// How many splines /// How many splines
#[clap(value_parser)]
num_splines: u8, num_splines: u8,
}, },
/// Frobnicate the rest /// Frobnicate the rest
@ -121,8 +122,9 @@ fn issue_490() {
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
struct Opt { struct Opt {
#[clap(value_parser)]
opt_vec: Vec<u16>, opt_vec: Vec<u16>,
#[clap(long)] #[clap(long, value_parser)]
opt_opt_vec: Option<Vec<u16>>, opt_opt_vec: Option<Vec<u16>>,
} }

View file

@ -22,7 +22,7 @@ fn use_option() {
($name:ident: $ty:ty) => { ($name:ident: $ty:ty) => {
#[derive(Parser)] #[derive(Parser)]
struct Outer { struct Outer {
#[clap(short, long)] #[clap(short, long, value_parser)]
#[allow(dead_code)] #[allow(dead_code)]
$name: $ty, $name: $ty,
} }

View file

@ -241,7 +241,10 @@ fn test_upper_is_renamed() {
fn test_single_word_enum_variant_is_default_renamed_into_kebab_case() { fn test_single_word_enum_variant_is_default_renamed_into_kebab_case() {
#[derive(Parser, Debug, PartialEq)] #[derive(Parser, Debug, PartialEq)]
enum Opt { enum Opt {
Command { foo: u32 }, Command {
#[clap(value_parser)]
foo: u32,
},
} }
assert_eq!( assert_eq!(
@ -254,7 +257,10 @@ fn test_single_word_enum_variant_is_default_renamed_into_kebab_case() {
fn test_multi_word_enum_variant_is_renamed() { fn test_multi_word_enum_variant_is_renamed() {
#[derive(Parser, Debug, PartialEq)] #[derive(Parser, Debug, PartialEq)]
enum Opt { enum Opt {
FirstCommand { foo: u32 }, FirstCommand {
#[clap(value_parser)]
foo: u32,
},
} }
assert_eq!( assert_eq!(
@ -295,7 +301,7 @@ fn test_rename_all_is_propagated_from_enum_to_variants() {
enum Opt { enum Opt {
FirstVariant, FirstVariant,
SecondVariant { SecondVariant {
#[clap(long)] #[clap(long, value_parser)]
foo: String, foo: String,
}, },
} }
@ -313,7 +319,7 @@ fn test_rename_all_is_propagated_from_enum_to_variant_fields() {
enum Opt { enum Opt {
FirstVariant, FirstVariant,
SecondVariant { SecondVariant {
#[clap(long)] #[clap(long, value_parser)]
foo: String, foo: String,
}, },
} }

View file

@ -118,6 +118,7 @@ struct Opt3 {
#[derive(Subcommand, PartialEq, Debug)] #[derive(Subcommand, PartialEq, Debug)]
enum Sub2 { enum Sub2 {
Foo { Foo {
#[clap(value_parser)]
file: String, file: String,
#[clap(subcommand)] #[clap(subcommand)]
cmd: Sub3, cmd: Sub3,
@ -158,8 +159,16 @@ enum SubSubCmdWithOption {
} }
#[derive(Subcommand, PartialEq, Debug)] #[derive(Subcommand, PartialEq, Debug)]
enum Remote { enum Remote {
Add { name: String, url: String }, Add {
Remove { name: String }, #[clap(value_parser)]
name: String,
#[clap(value_parser)]
url: String,
},
Remove {
#[clap(value_parser)]
name: String,
},
} }
#[derive(Subcommand, PartialEq, Debug)] #[derive(Subcommand, PartialEq, Debug)]

View file

@ -26,17 +26,18 @@ struct Opt {
display_order = DISPLAY_ORDER, display_order = DISPLAY_ORDER,
next_line_help = true, next_line_help = true,
default_value = "0", default_value = "0",
require_equals = true require_equals = true,
value_parser
)] )]
x: i32, x: i32,
#[clap(short = 'l', long = "level", aliases = &["set-level", "lvl"])] #[clap(short = 'l', long = "level", value_parser, aliases = &["set-level", "lvl"])]
level: String, level: String,
#[clap(long("values"))] #[clap(long("values"), value_parser)]
values: Vec<i32>, values: Vec<i32>,
#[clap(name = "FILE", requires_if("FILE", "values"))] #[clap(name = "FILE", value_parser, requires_if("FILE", "values"))]
files: Vec<String>, files: Vec<String>,
} }
@ -130,7 +131,7 @@ fn parse_hex(input: &str) -> Result<u64, ParseIntError> {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct HexOpt { struct HexOpt {
#[clap(short, parse(try_from_str = parse_hex))] #[clap(short, value_parser = parse_hex)]
number: u64, number: u64,
} }

View file

@ -22,7 +22,7 @@ use clap::{Parser, Subcommand};
fn required_option() { fn required_option() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short, long)] #[clap(short, long, value_parser)]
arg: i32, arg: i32,
} }
assert_eq!( assert_eq!(
@ -45,7 +45,7 @@ fn required_option() {
fn option_with_default() { fn option_with_default() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short, default_value = "42")] #[clap(short, value_parser, default_value = "42")]
arg: i32, arg: i32,
} }
assert_eq!( assert_eq!(
@ -60,7 +60,7 @@ fn option_with_default() {
fn option_with_raw_default() { fn option_with_raw_default() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short, default_value = "42")] #[clap(short, value_parser, default_value = "42")]
arg: i32, arg: i32,
} }
assert_eq!( assert_eq!(
@ -150,7 +150,7 @@ fn option_vec_from_str() {
fn option_type_is_optional() { fn option_type_is_optional() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short)] #[clap(short, value_parser)]
arg: Option<i32>, arg: Option<i32>,
} }
assert_eq!( assert_eq!(
@ -166,7 +166,7 @@ fn required_with_option_type() {
#[derive(Debug, PartialEq, Eq, Parser)] #[derive(Debug, PartialEq, Eq, Parser)]
#[clap(subcommand_negates_reqs = true)] #[clap(subcommand_negates_reqs = true)]
struct Opt { struct Opt {
#[clap(required = true)] #[clap(value_parser, required = true)]
req_str: Option<String>, req_str: Option<String>,
#[clap(subcommand)] #[clap(subcommand)]
@ -224,7 +224,7 @@ fn ignore_qualified_option_type() {
fn option_option_type_is_optional_value() { fn option_option_type_is_optional_value() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short, multiple_occurrences(true))] #[clap(short, value_parser, multiple_occurrences(true))]
#[allow(clippy::option_option)] #[allow(clippy::option_option)]
arg: Option<Option<i32>>, arg: Option<Option<i32>>,
} }
@ -246,7 +246,7 @@ fn option_option_type_is_optional_value() {
fn option_option_type_help() { fn option_option_type_help() {
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
struct Opt { struct Opt {
#[clap(long, value_name = "val")] #[clap(long, value_name = "val", value_parser)]
arg: Option<Option<i32>>, arg: Option<Option<i32>>,
} }
let help = utils::get_help::<Opt>(); let help = utils::get_help::<Opt>();
@ -258,10 +258,10 @@ fn option_option_type_help() {
fn two_option_option_types() { fn two_option_option_types() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short)] #[clap(short, value_parser)]
arg: Option<Option<i32>>, arg: Option<Option<i32>>,
#[clap(long)] #[clap(long, value_parser)]
field: Option<Option<String>>, field: Option<Option<String>>,
} }
assert_eq!( assert_eq!(
@ -312,7 +312,7 @@ fn two_option_option_types() {
fn vec_type_is_multiple_occurrences() { fn vec_type_is_multiple_occurrences() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short, long)] #[clap(short, long, value_parser)]
arg: Vec<i32>, arg: Vec<i32>,
} }
assert_eq!( assert_eq!(
@ -330,7 +330,7 @@ fn vec_type_is_multiple_occurrences() {
fn vec_type_with_required() { fn vec_type_with_required() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short, long, required = true)] #[clap(short, long, required = true, value_parser)]
arg: Vec<i32>, arg: Vec<i32>,
} }
assert_eq!( assert_eq!(
@ -348,7 +348,13 @@ fn vec_type_with_required() {
fn vec_type_with_multiple_values_only() { fn vec_type_with_multiple_values_only() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short, long, multiple_values(true), multiple_occurrences(false))] #[clap(
short,
long,
multiple_values(true),
multiple_occurrences(false),
value_parser
)]
arg: Vec<i32>, arg: Vec<i32>,
} }
assert_eq!( assert_eq!(
@ -386,7 +392,7 @@ fn ignore_qualified_vec_type() {
fn option_vec_type() { fn option_vec_type() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short)] #[clap(short, value_parser)]
arg: Option<Vec<i32>>, arg: Option<Vec<i32>>,
} }
assert_eq!( assert_eq!(
@ -408,7 +414,7 @@ fn option_vec_type() {
fn option_vec_type_structopt_behavior() { fn option_vec_type_structopt_behavior() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short, long, multiple_values(true), min_values(0))] #[clap(short, long, multiple_values(true), min_values(0), value_parser)]
arg: Option<Vec<i32>>, arg: Option<Vec<i32>>,
} }
assert_eq!( assert_eq!(
@ -435,10 +441,10 @@ fn option_vec_type_structopt_behavior() {
fn two_option_vec_types() { fn two_option_vec_types() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short)] #[clap(short, value_parser)]
arg: Option<Vec<i32>>, arg: Option<Vec<i32>>,
#[clap(short)] #[clap(short, value_parser)]
b: Option<Vec<i32>>, b: Option<Vec<i32>>,
} }

View file

@ -30,6 +30,7 @@ mod subcommands {
/// foo /// foo
Foo { Foo {
/// foo /// foo
#[clap(value_parser)]
bars: String, bars: String,
}, },
} }

View file

@ -13,9 +13,9 @@ fn raw_bool_literal() {
#[derive(Parser, Debug, PartialEq)] #[derive(Parser, Debug, PartialEq)]
#[clap(name = "raw_bool")] #[clap(name = "raw_bool")]
struct Opt { struct Opt {
#[clap(raw(false))] #[clap(raw(false), value_parser)]
a: String, a: String,
#[clap(raw(true))] #[clap(raw(true), value_parser)]
b: String, b: String,
} }

View file

@ -4,7 +4,7 @@ use clap::Parser;
fn raw_idents() { fn raw_idents() {
#[derive(Parser, Debug, PartialEq)] #[derive(Parser, Debug, PartialEq)]
struct Opt { struct Opt {
#[clap(short, long)] #[clap(short, long, value_parser)]
r#type: String, r#type: String,
} }

View file

@ -9,7 +9,7 @@ fn it_works() {
#[derive(Debug, PartialEq, Parser)] #[derive(Debug, PartialEq, Parser)]
#[clap(rename_all_env = "kebab")] #[clap(rename_all_env = "kebab")]
struct BehaviorModel { struct BehaviorModel {
#[clap(env)] #[clap(env, value_parser)]
be_nice: String, be_nice: String,
} }
@ -21,7 +21,7 @@ fn it_works() {
fn default_is_screaming() { fn default_is_screaming() {
#[derive(Debug, PartialEq, Parser)] #[derive(Debug, PartialEq, Parser)]
struct BehaviorModel { struct BehaviorModel {
#[clap(env)] #[clap(env, value_parser)]
be_nice: String, be_nice: String,
} }
@ -34,10 +34,10 @@ fn overridable() {
#[derive(Debug, PartialEq, Parser)] #[derive(Debug, PartialEq, Parser)]
#[clap(rename_all_env = "kebab")] #[clap(rename_all_env = "kebab")]
struct BehaviorModel { struct BehaviorModel {
#[clap(env)] #[clap(env, value_parser)]
be_nice: String, be_nice: String,
#[clap(rename_all_env = "pascal", env)] #[clap(rename_all_env = "pascal", env, value_parser)]
be_aggressive: String, be_aggressive: String,
} }

View file

@ -12,7 +12,7 @@ use clap::Parser;
fn skip_1() { fn skip_1() {
#[derive(Parser, Debug, PartialEq)] #[derive(Parser, Debug, PartialEq)]
struct Opt { struct Opt {
#[clap(short)] #[clap(short, value_parser)]
x: u32, x: u32,
#[clap(skip)] #[clap(skip)]
s: u32, s: u32,
@ -39,15 +39,17 @@ fn skip_1() {
fn skip_2() { fn skip_2() {
#[derive(Parser, Debug, PartialEq)] #[derive(Parser, Debug, PartialEq)]
struct Opt { struct Opt {
#[clap(short)] #[clap(short, value_parser)]
x: u32, x: u32,
#[clap(skip)] #[clap(skip)]
ss: String, ss: String,
#[clap(skip)] #[clap(skip)]
sn: u8, sn: u8,
#[clap(value_parser)]
y: u32, y: u32,
#[clap(skip)] #[clap(skip)]
sz: u16, sz: u16,
#[clap(value_parser)]
t: u32, t: u32,
} }
@ -81,7 +83,7 @@ fn skip_enum() {
#[derive(Parser, Debug, PartialEq)] #[derive(Parser, Debug, PartialEq)]
pub struct Opt { pub struct Opt {
#[clap(long, short)] #[clap(long, short, value_parser)]
number: u32, number: u32,
#[clap(skip)] #[clap(skip)]
k: Kind, k: Kind,
@ -115,7 +117,7 @@ fn skip_help_doc_comments() {
#[clap(skip)] #[clap(skip)]
c: u32, c: u32,
#[clap(short, parse(try_from_str))] #[clap(short, value_parser)]
n: u32, n: u32,
} }
@ -134,7 +136,7 @@ fn skip_help_doc_comments() {
fn skip_val() { fn skip_val() {
#[derive(Parser, Debug, PartialEq)] #[derive(Parser, Debug, PartialEq)]
pub struct Opt { pub struct Opt {
#[clap(long, short)] #[clap(long, short, value_parser)]
number: u32, number: u32,
#[clap(skip = "key")] #[clap(skip = "key")]

View file

@ -25,6 +25,7 @@ enum Opt {
#[clap(short, long)] #[clap(short, long)]
/// Overwrite local branches. /// Overwrite local branches.
force: bool, force: bool,
#[clap(value_parser)]
repo: String, repo: String,
}, },
@ -88,7 +89,10 @@ fn test_no_parse() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
enum Opt2 { enum Opt2 {
DoSomething { arg: String }, DoSomething {
#[clap(value_parser)]
arg: String,
},
} }
#[test] #[test]
@ -123,11 +127,13 @@ fn test_null_commands() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
#[clap(about = "Not shown")] #[clap(about = "Not shown")]
struct Add { struct Add {
#[clap(value_parser)]
file: String, file: String,
} }
/// Not shown /// Not shown
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Fetch { struct Fetch {
#[clap(value_parser)]
remote: String, remote: String,
} }
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
@ -337,12 +343,15 @@ fn update_subcommands() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Command1 { struct Command1 {
#[clap(value_parser)]
arg1: i32, arg1: i32,
#[clap(value_parser)]
arg2: i32, arg2: i32,
} }
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Command2 { struct Command2 {
#[clap(value_parser)]
arg2: i32, arg2: i32,
} }
@ -396,12 +405,15 @@ fn update_sub_subcommands() {
#[derive(Args, PartialEq, Debug)] #[derive(Args, PartialEq, Debug)]
struct Command1 { struct Command1 {
#[clap(value_parser)]
arg1: i32, arg1: i32,
#[clap(value_parser)]
arg2: i32, arg2: i32,
} }
#[derive(Args, PartialEq, Debug)] #[derive(Args, PartialEq, Debug)]
struct Command2 { struct Command2 {
#[clap(value_parser)]
arg2: i32, arg2: i32,
} }
@ -454,12 +466,15 @@ fn update_ext_subcommand() {
#[derive(Args, PartialEq, Debug)] #[derive(Args, PartialEq, Debug)]
struct Command1 { struct Command1 {
#[clap(value_parser)]
arg1: i32, arg1: i32,
#[clap(value_parser)]
arg2: i32, arg2: i32,
} }
#[derive(Args, PartialEq, Debug)] #[derive(Args, PartialEq, Debug)]
struct Command2 { struct Command2 {
#[clap(value_parser)]
arg2: i32, arg2: i32,
} }
@ -554,6 +569,7 @@ fn built_in_subcommand_escaped() {
#[derive(Debug, PartialEq, Parser)] #[derive(Debug, PartialEq, Parser)]
enum Command { enum Command {
Install { Install {
#[clap(value_parser)]
arg: Option<String>, arg: Option<String>,
}, },
#[clap(external_subcommand)] #[clap(external_subcommand)]
@ -582,6 +598,7 @@ fn built_in_subcommand_escaped() {
#[derive(Debug, PartialEq, Parser)] #[derive(Debug, PartialEq, Parser)]
enum Command { enum Command {
Install { Install {
#[clap(value_parser)]
arg: Option<String>, arg: Option<String>,
}, },
#[clap(external_subcommand)] #[clap(external_subcommand)]

View file

@ -1,3 +1,5 @@
#![allow(deprecated)]
/// Regression test to ensure that type aliases do not cause compilation failures. /// Regression test to ensure that type aliases do not cause compilation failures.
use std::str::FromStr; use std::str::FromStr;
@ -23,10 +25,11 @@ type Option<T> = std::option::Option<Wrapper<T>>;
#[derive(Parser)] #[derive(Parser)]
pub struct Opts { pub struct Opts {
#[clap(value_parser)]
another_string: String, another_string: String,
#[clap(subcommand)] #[clap(subcommand)]
command: Command, command: Command,
#[clap(short, long, arg_enum)] #[clap(short, long, arg_enum, value_parser)]
choice: ArgChoice, choice: ArgChoice,
} }

View file

@ -6,12 +6,13 @@ use std::os::unix::ffi::OsStringExt;
#[derive(Parser, Debug, PartialEq, Eq)] #[derive(Parser, Debug, PartialEq, Eq)]
struct Positional { struct Positional {
#[clap(value_parser)]
arg: String, arg: String,
} }
#[derive(Parser, Debug, PartialEq, Eq)] #[derive(Parser, Debug, PartialEq, Eq)]
struct Named { struct Named {
#[clap(short, long)] #[clap(short, long, value_parser)]
arg: String, arg: String,
} }