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
use clap::{Arg, Command};
use clap::{value_parser, Arg, Command};
use criterion::{criterion_group, criterion_main, Criterion};
use std::collections::HashMap;
use std::io::Cursor;
@ -394,19 +394,19 @@ where
flag("after-context")
.short('A')
.value_name("NUM")
.validator(validate_number),
.value_parser(value_parser!(usize)),
)
.arg(
flag("before-context")
.short('B')
.value_name("NUM")
.validator(validate_number),
.value_parser(value_parser!(usize)),
)
.arg(
flag("context")
.short('C')
.value_name("NUM")
.validator(validate_number),
.value_parser(value_parser!(usize)),
)
.arg(flag("column"))
.arg(flag("context-separator").value_name("SEPARATOR"))
@ -434,12 +434,12 @@ where
flag("max-count")
.short('m')
.value_name("NUM")
.validator(validate_number),
.value_parser(value_parser!(usize)),
)
.arg(
flag("maxdepth")
.value_name("NUM")
.validator(validate_number),
.value_parser(value_parser!(usize)),
)
.arg(flag("mmap"))
.arg(flag("no-messages"))
@ -458,7 +458,7 @@ where
flag("threads")
.short('j')
.value_name("ARG")
.validator(validate_number),
.value_parser(value_parser!(usize)),
)
.arg(flag("vimgrep"))
.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!(
benches,
build_rg_with_short_help,

View file

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

View file

@ -31,14 +31,14 @@ USAGE:
For more information try --help
$ 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,
bar: false,
boom: 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,
bar: true,
boom: false,

View file

@ -1,3 +1,4 @@
#![allow(deprecated)] // Can't opt-out of implicit flags until #3405
use clap::Parser;
#[derive(Parser, Debug, PartialEq)]

View file

@ -1557,43 +1557,10 @@ impl<'help> Arg<'help> {
self.takes_value(true)
}
/// Perform a custom validation on the argument value.
///
/// 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
/// Deprecated, replaced with [`Arg::value_parser(...)`]
#[inline]
#[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
where
F: FnMut(&str) -> Result<O, E> + Send + 'help,
@ -1605,37 +1572,9 @@ impl<'help> Arg<'help> {
self
}
/// Perform a custom validation on the argument value.
///
/// 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
/// Deprecated, replaced with [`Arg::value_parser(...)`]
#[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
where
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)]
#[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() {
use clap::{Arg, Command};
let _ = Command::new("test")
.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"),
)
.try_get_matches();

View file

@ -652,14 +652,14 @@ fn default_values_are_possible_values() {
#[cfg(debug_assertions)]
#[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() {
use clap::{Arg, Command};
let _ = Command::new("test")
.arg(
Arg::new("arg")
.validator(|val| val.parse::<u32>().map_err(|e| e.to_string()))
.value_parser(clap::value_parser!(u32))
.default_value("one"),
)
.try_get_matches();
@ -672,7 +672,7 @@ fn valid_delimited_default_values() {
let _ = Command::new("test")
.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)
.require_value_delimiter(true)
.default_value("1,2,3"),
@ -682,14 +682,14 @@ fn valid_delimited_default_values() {
#[cfg(debug_assertions)]
#[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() {
use clap::{Arg, Command};
let _ = Command::new("test")
.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)
.require_value_delimiter(true)
.default_value("one,two"),

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -22,7 +22,7 @@ fn use_option() {
($name:ident: $ty:ty) => {
#[derive(Parser)]
struct Outer {
#[clap(short, long)]
#[clap(short, long, value_parser)]
#[allow(dead_code)]
$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() {
#[derive(Parser, Debug, PartialEq)]
enum Opt {
Command { foo: u32 },
Command {
#[clap(value_parser)]
foo: u32,
},
}
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() {
#[derive(Parser, Debug, PartialEq)]
enum Opt {
FirstCommand { foo: u32 },
FirstCommand {
#[clap(value_parser)]
foo: u32,
},
}
assert_eq!(
@ -295,7 +301,7 @@ fn test_rename_all_is_propagated_from_enum_to_variants() {
enum Opt {
FirstVariant,
SecondVariant {
#[clap(long)]
#[clap(long, value_parser)]
foo: String,
},
}
@ -313,7 +319,7 @@ fn test_rename_all_is_propagated_from_enum_to_variant_fields() {
enum Opt {
FirstVariant,
SecondVariant {
#[clap(long)]
#[clap(long, value_parser)]
foo: String,
},
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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