fix!: Change default actions to Set/SetTrue

This is in prep for removing StoreValue/IncOccurrences
This commit is contained in:
Ed Page 2022-07-22 13:37:18 -05:00
parent 4b499ac024
commit 122b562e6b
23 changed files with 107 additions and 92 deletions

View file

@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- `ErrorKind::EmptyValue` replaced with `ErrorKind::InvalidValue`
- `ErrorKind::UnrecognizedSubcommand` replaced with `ErrorKind::InvalidSubcommand` (#3676)
- `arg!` now sets `ArgAction::SetTrue`, `ArgAction::Count`, `ArgAction::Set`, or `ArgAction::Append` as appropriate (#3795)
- Default actions are now `Set` and `SetTrue`
- *(help)* Make `DeriveDisplayOrder` the default and removed the setting. To sort help, set `next_display_order(None)` (#2808)
- *(help)* Subcommand display order respects `Command::next_display_order` instead of `DeriveDisplayOrder` and using its own initial display order value (#2808)
- *(env)* Parse `--help` and `--version` like any `ArgAction::SetTrue` flag (#3776)

View file

@ -15,18 +15,18 @@ _my-app() {
local context curcontext="$curcontext" state line
_arguments "${_arguments_options[@]}" /
'-o+[cmd option]: : ' /
'-O+[cmd option]: : ' /
'--option=[cmd option]: : ' /
'--opt=[cmd option]: : ' /
'*-o+[cmd option]: : ' /
'*-O+[cmd option]: : ' /
'*--option=[cmd option]: : ' /
'*--opt=[cmd option]: : ' /
'-h[Print help information]' /
'--help[Print help information]' /
'-V[Print version information]' /
'--version[Print version information]' /
'-f[cmd flag]' /
'-F[cmd flag]' /
'--flag[cmd flag]' /
'--flg[cmd flag]' /
'*-f[cmd flag]' /
'*-F[cmd flag]' /
'*--flag[cmd flag]' /
'*--flg[cmd flag]' /
'::positional:' /
&& ret=0
}

View file

@ -17,8 +17,8 @@ _my-app() {
_arguments "${_arguments_options[@]}" /
'-h[Print help information]' /
'--help[Print help information]' /
'-c[]' /
'(-c)-v[]' /
'*-c[]' /
'(-c)*-v[]' /
":: :_my-app_commands" /
"*::: :->my-app" /
&& ret=0
@ -33,12 +33,12 @@ _arguments "${_arguments_options[@]}" /
'*-d[]' /
'-h[Print help information]' /
'--help[Print help information]' /
'-c[]' /
'*-c[]' /
&& ret=0
;;
(help)
_arguments "${_arguments_options[@]}" /
'-c[]' /
'*-c[]' /
'*::subcommand -- The subcommand whose help message to display:' /
&& ret=0
;;

View file

@ -36,7 +36,7 @@ _my-app() {
case $line[3] in
(test)
_arguments "${_arguments_options[@]}" /
'--case=[the case to test]: : ' /
'*--case=[the case to test]: : ' /
'-h[Print help information]' /
'--help[Print help information]' /
'-V[Print version information]' /

View file

@ -19,12 +19,12 @@ _my-app() {
'--help[Print help information]' /
'-V[Print version information]' /
'--version[Print version information]' /
'--single-quotes[Can be '/''always'/'', '/''auto'/'', or '/''never'/'']' /
'--double-quotes[Can be "always", "auto", or "never"]' /
'--backticks[For more information see `echo test`]' /
'--backslash[Avoid '/''//n'/'']' /
'--brackets[List packages /[filter/]]' /
'--expansions[Execute the shell command with $SHELL]' /
'*--single-quotes[Can be '/''always'/'', '/''auto'/'', or '/''never'/'']' /
'*--double-quotes[Can be "always", "auto", or "never"]' /
'*--backticks[For more information see `echo test`]' /
'*--backslash[Avoid '/''//n'/'']' /
'*--brackets[List packages /[filter/]]' /
'*--expansions[Execute the shell command with $SHELL]' /
":: :_my-app_commands" /
"*::: :->my-app" /
&& ret=0

View file

@ -36,7 +36,7 @@ _my-app() {
case $line[3] in
(test)
_arguments "${_arguments_options[@]}" /
'--case=[the case to test]: : ' /
'*--case=[the case to test]: : ' /
'-h[Print help information]' /
'--help[Print help information]' /
'-V[Print version information]' /
@ -45,7 +45,7 @@ _arguments "${_arguments_options[@]}" /
;;
(some_cmd)
_arguments "${_arguments_options[@]}" /
'--config=[the other case to test]: : ' /
'*--config=[the other case to test]: : ' /
'-h[Print help information]' /
'--help[Print help information]' /
'-V[Print version information]' /

View file

@ -36,7 +36,7 @@ _my-app() {
case $line[3] in
(test)
_arguments "${_arguments_options[@]}" /
'--case=[the case to test]: : ' /
'*--case=[the case to test]: : ' /
'-h[Print help information]' /
'--help[Print help information]' /
'-V[Print version information]' /
@ -61,7 +61,7 @@ _arguments "${_arguments_options[@]}" /
case $line[1] in
(sub_cmd)
_arguments "${_arguments_options[@]}" /
'--config=[the other case to test]: :(Lest quotes aren't escaped.)' /
'*--config=[the other case to test]: :(Lest quotes aren't escaped.)' /
'-h[Print help information]' /
'--help[Print help information]' /
'-V[Print version information]' /

View file

@ -15,26 +15,26 @@ _my-app() {
local context curcontext="$curcontext" state line
_arguments "${_arguments_options[@]}" /
'--choice=[]: :(bash fish zsh)' /
'--unknown=[]: : ' /
'--other=[]: :( )' /
'-p+[]: :_files' /
'--path=[]: :_files' /
'-f+[]: :_files' /
'--file=[]: :_files' /
'-d+[]: :_files -/' /
'--dir=[]: :_files -/' /
'-e+[]: :_absolute_command_paths' /
'--exe=[]: :_absolute_command_paths' /
'--cmd-name=[]: :_command_names -e' /
'-c+[]: :_cmdstring' /
'--cmd=[]: :_cmdstring' /
'-u+[]: :_users' /
'--user=[]: :_users' /
'-h+[]: :_hosts' /
'--host=[]: :_hosts' /
'--url=[]: :_urls' /
'--email=[]: :_email_addresses' /
'*--choice=[]: :(bash fish zsh)' /
'*--unknown=[]: : ' /
'*--other=[]: :( )' /
'*-p+[]: :_files' /
'*--path=[]: :_files' /
'*-f+[]: :_files' /
'*--file=[]: :_files' /
'*-d+[]: :_files -/' /
'*--dir=[]: :_files -/' /
'*-e+[]: :_absolute_command_paths' /
'*--exe=[]: :_absolute_command_paths' /
'*--cmd-name=[]: :_command_names -e' /
'*-c+[]: :_cmdstring' /
'*--cmd=[]: :_cmdstring' /
'*-u+[]: :_users' /
'*--user=[]: :_users' /
'*-h+[]: :_hosts' /
'*--host=[]: :_hosts' /
'*--url=[]: :_urls' /
'*--email=[]: :_email_addresses' /
'--help[Print help information]' /
'*::command_with_args:_cmdambivalent' /
&& ret=0

View file

@ -5,6 +5,7 @@ const completion: Fig.Spec = {
{
name: ["-o", "-O", "--option", "--opt"],
description: "cmd option",
isRepeatable: true,
args: {
name: "option",
isOptional: true,

View file

@ -9,6 +9,7 @@ const completion: Fig.Spec = {
{
name: "--case",
description: "the case to test",
isRepeatable: true,
args: {
name: "case",
isOptional: true,

View file

@ -9,6 +9,7 @@ const completion: Fig.Spec = {
{
name: "--case",
description: "the case to test",
isRepeatable: true,
args: {
name: "case",
isOptional: true,
@ -32,6 +33,7 @@ const completion: Fig.Spec = {
name: "--config",
description: "the other case to test",
hidden: true,
isRepeatable: true,
requiresEquals: true,
args: {
name: "config",

View file

@ -9,6 +9,7 @@ const completion: Fig.Spec = {
{
name: "--case",
description: "the case to test",
isRepeatable: true,
args: {
name: "case",
isOptional: true,
@ -35,6 +36,7 @@ const completion: Fig.Spec = {
{
name: "--config",
description: "the other case to test",
isRepeatable: true,
args: {
name: "config",
isOptional: true,

View file

@ -4,6 +4,7 @@ const completion: Fig.Spec = {
options: [
{
name: "--choice",
isRepeatable: true,
args: {
name: "choice",
isOptional: true,
@ -16,6 +17,7 @@ const completion: Fig.Spec = {
},
{
name: "--unknown",
isRepeatable: true,
args: {
name: "unknown",
isOptional: true,
@ -23,6 +25,7 @@ const completion: Fig.Spec = {
},
{
name: "--other",
isRepeatable: true,
args: {
name: "other",
isOptional: true,
@ -30,6 +33,7 @@ const completion: Fig.Spec = {
},
{
name: ["-p", "--path"],
isRepeatable: true,
args: {
name: "path",
isOptional: true,
@ -38,6 +42,7 @@ const completion: Fig.Spec = {
},
{
name: ["-f", "--file"],
isRepeatable: true,
args: {
name: "file",
isOptional: true,
@ -46,6 +51,7 @@ const completion: Fig.Spec = {
},
{
name: ["-d", "--dir"],
isRepeatable: true,
args: {
name: "dir",
isOptional: true,
@ -54,6 +60,7 @@ const completion: Fig.Spec = {
},
{
name: ["-e", "--exe"],
isRepeatable: true,
args: {
name: "exe",
isOptional: true,
@ -62,6 +69,7 @@ const completion: Fig.Spec = {
},
{
name: "--cmd-name",
isRepeatable: true,
args: {
name: "cmd_name",
isOptional: true,
@ -70,6 +78,7 @@ const completion: Fig.Spec = {
},
{
name: ["-c", "--cmd"],
isRepeatable: true,
args: {
name: "cmd",
isOptional: true,
@ -78,6 +87,7 @@ const completion: Fig.Spec = {
},
{
name: ["-u", "--user"],
isRepeatable: true,
args: {
name: "user",
isOptional: true,
@ -85,6 +95,7 @@ const completion: Fig.Spec = {
},
{
name: ["-h", "--host"],
isRepeatable: true,
args: {
name: "host",
isOptional: true,
@ -92,6 +103,7 @@ const completion: Fig.Spec = {
},
{
name: "--url",
isRepeatable: true,
args: {
name: "url",
isOptional: true,
@ -99,6 +111,7 @@ const completion: Fig.Spec = {
},
{
name: "--email",
isRepeatable: true,
args: {
name: "email",
isOptional: true,

View file

@ -15,7 +15,7 @@ Print help information
/fB/-V/fR, /fB/-/-version/fR
Print version information
.TP
/fB/-f/fR, /fB/-/-flag/fR
/fB/-f/fR, /fB/-/-flag/fR [default: false]
cmd flag
.TP
/fB/-o/fR, /fB/-/-option/fR

View file

@ -11,10 +11,10 @@ my/-app
/fB/-h/fR, /fB/-/-help/fR
Print help information
.TP
/fB/-c/fR
/fB/-c/fR [default: false]
.TP
/fB/-v/fR
/fB/-v/fR [default: false]
.SH SUBCOMMANDS
.TP

View file

@ -15,7 +15,7 @@ Print help information
/fB/-V/fR, /fB/-/-version/fR
Print version information
.TP
/fB/-c/fR, /fB/-/-config/fR
/fB/-c/fR, /fB/-/-config/fR [default: false]
some config file
.TP
[/fIfile/fR]

View file

@ -14,22 +14,22 @@ Print help information
/fB/-V/fR, /fB/-/-version/fR
Print version information
.TP
/fB/-/-single/-quotes/fR
/fB/-/-single/-quotes/fR [default: false]
Can be /*(Aqalways/*(Aq, /*(Aqauto/*(Aq, or /*(Aqnever/*(Aq
.TP
/fB/-/-double/-quotes/fR
/fB/-/-double/-quotes/fR [default: false]
Can be "always", "auto", or "never"
.TP
/fB/-/-backticks/fR
/fB/-/-backticks/fR [default: false]
For more information see `echo test`
.TP
/fB/-/-backslash/fR
/fB/-/-backslash/fR [default: false]
Avoid /*(Aq//n/*(Aq
.TP
/fB/-/-brackets/fR
/fB/-/-brackets/fR [default: false]
List packages [filter]
.TP
/fB/-/-expansions/fR
/fB/-/-expansions/fR [default: false]
Execute the shell command with $SHELL
.SH SUBCOMMANDS
.TP

View file

@ -15,7 +15,7 @@ Print help information
/fB/-V/fR, /fB/-/-version/fR
Print version information
.TP
/fB/-c/fR, /fB/-/-config/fR
/fB/-c/fR, /fB/-/-config/fR [default: false]
some config file
.TP
[/fIfile/fR]

View file

@ -15,7 +15,7 @@ Print help information
/fB/-V/fR, /fB/-/-version/fR
Print version information
.TP
/fB/-c/fR, /fB/-/-config/fR
/fB/-c/fR, /fB/-/-config/fR [default: false]
some config file
.TP
[/fIfile/fR]

View file

@ -995,21 +995,22 @@ impl<'help> Arg<'help> {
/// assert_eq!(files, ["file1", "file2", "file3"]);
/// ```
///
/// Although `multiple_values` has been specified, we cannot use the argument more than once.
/// Although `multiple_values` has been specified, the last argument still wins
///
/// ```rust
/// # use clap::{Command, Arg, ErrorKind};
/// let res = Command::new("prog")
/// let m = Command::new("prog")
/// .arg(Arg::new("file")
/// .takes_value(true)
/// .multiple_values(true)
/// .short('F'))
/// .try_get_matches_from(vec![
/// .get_matches_from(vec![
/// "prog", "-F", "file1", "-F", "file2", "-F", "file3"
/// ]);
///
/// assert!(res.is_err());
/// assert_eq!(res.unwrap_err().kind(), ErrorKind::UnexpectedMultipleUsage)
/// assert!(m.contains_id("file"));
/// let files: Vec<_> = m.get_many::<String>("file").unwrap().collect();
/// assert_eq!(files, ["file3"]);
/// ```
///
/// A common mistake is to define an option which allows multiple values, and a positional
@ -2128,13 +2129,16 @@ impl<'help> Arg<'help> {
///
/// In this example, because [`Arg::takes_value(false)`] (by default),
/// `prog` is a flag that accepts an optional, case-insensitive boolean literal.
/// A `false` literal is `n`, `no`, `f`, `false`, `off` or `0`.
/// An absent environment variable will also be considered as `false`.
/// Anything else will considered as `true`.
///
/// Note that the value parser controls how flags are parsed. In this case we've selected
/// [`FalseyValueParser`][crate::builder::FalseyValueParser]. A `false` literal is `n`, `no`,
/// `f`, `false`, `off` or `0`. An absent environment variable will also be considered as
/// `false`. Anything else will considered as `true`.
///
/// ```rust
/// # use std::env;
/// # use clap::{Command, Arg};
/// # use clap::builder::FalseyValueParser;
///
/// env::set_var("TRUE_FLAG", "true");
/// env::set_var("FALSE_FLAG", "0");
@ -2142,20 +2146,23 @@ impl<'help> Arg<'help> {
/// let m = Command::new("prog")
/// .arg(Arg::new("true_flag")
/// .long("true_flag")
/// .value_parser(FalseyValueParser::new())
/// .env("TRUE_FLAG"))
/// .arg(Arg::new("false_flag")
/// .long("false_flag")
/// .value_parser(FalseyValueParser::new())
/// .env("FALSE_FLAG"))
/// .arg(Arg::new("absent_flag")
/// .long("absent_flag")
/// .value_parser(FalseyValueParser::new())
/// .env("ABSENT_FLAG"))
/// .get_matches_from(vec![
/// "prog"
/// ]);
///
/// assert!(m.is_present("true_flag"));
/// assert!(!m.is_present("false_flag"));
/// assert!(!m.is_present("absent_flag"));
/// assert!(*m.get_one::<bool>("true_flag").unwrap());
/// assert!(!*m.get_one::<bool>("false_flag").unwrap());
/// assert!(!*m.get_one::<bool>("absent_flag").unwrap());
/// ```
///
/// In this example, we show the variable coming from an option on the CLI:
@ -2920,7 +2927,7 @@ impl<'help> Arg<'help> {
/// .long("flag"))
/// .arg(Arg::new("other")
/// .long("other")
/// .default_value_if("flag", None, Some("default")))
/// .default_value_if("flag", Some("true"), Some("default")))
/// .get_matches_from(vec![
/// "prog"
/// ]);
@ -2976,7 +2983,7 @@ impl<'help> Arg<'help> {
/// .arg(Arg::new("other")
/// .long("other")
/// .default_value("default")
/// .default_value_if("flag", None, None))
/// .default_value_if("flag", Some("true"), None))
/// .get_matches_from(vec![
/// "prog", "--flag"
/// ]);
@ -3034,7 +3041,7 @@ impl<'help> Arg<'help> {
/// .arg(Arg::new("other")
/// .long("other")
/// .default_value_ifs(&[
/// ("flag", None, Some("default")),
/// ("flag", Some("true"), Some("default")),
/// ("opt", Some("channal"), Some("chan")),
/// ]))
/// .get_matches_from(vec![
@ -3054,7 +3061,7 @@ impl<'help> Arg<'help> {
/// .arg(Arg::new("other")
/// .long("other")
/// .default_value_ifs(&[
/// ("flag", None, Some("default")),
/// ("flag", Some("true"), Some("default")),
/// ("opt", Some("channal"), Some("chan")),
/// ]))
/// .get_matches_from(vec![
@ -4249,7 +4256,7 @@ impl<'help> Arg<'help> {
/// Behavior when parsing the argument
pub fn get_action(&self) -> &super::ArgAction {
const DEFAULT: super::ArgAction = super::ArgAction::StoreValue;
const DEFAULT: super::ArgAction = super::ArgAction::Set;
self.action.as_ref().unwrap_or(&DEFAULT)
}
@ -4369,10 +4376,15 @@ impl<'help> Arg<'help> {
let action = super::ArgAction::Version;
self.action = Some(action);
} else if self.is_takes_value_set() {
let action = super::ArgAction::StoreValue;
let action = if self.is_positional() && self.is_multiple_values_set() {
// Allow collecting arguments interleaved with flags
super::ArgAction::Append
} else {
super::ArgAction::Set
};
self.action = Some(action);
} else {
let action = super::ArgAction::IncOccurrence;
let action = super::ArgAction::SetTrue;
self.action = Some(action);
}
}

View file

@ -208,19 +208,6 @@ pub enum ErrorKind {
MissingSubcommand,
/// Occurs when the user provides multiple values to an argument which doesn't allow that.
///
/// # Examples
///
/// ```rust
/// # use clap::{Command, Arg, ErrorKind};
/// let result = Command::new("prog")
/// .arg(Arg::new("debug")
/// .long("debug")
/// .multiple_occurrences(false))
/// .try_get_matches_from(vec!["prog", "--debug", "--debug"]);
/// assert!(result.is_err());
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::UnexpectedMultipleUsage);
/// ```
UnexpectedMultipleUsage,
/// Occurs when the user provides a value containing invalid UTF-8.

View file

@ -191,7 +191,7 @@ fn grouped_interleaved_positional_values() {
.unwrap();
let pos: Vec<_> = m.grouped_values_of("pos").unwrap().collect();
assert_eq!(pos, vec![vec!["1", "2", "3", "4"]]);
assert_eq!(pos, vec![vec!["1", "2"], vec!["3"], vec!["4"]]);
let flag: Vec<_> = m.grouped_values_of("flag").unwrap().collect();
assert_eq!(flag, vec![vec!["a"], vec!["b"]]);
@ -214,7 +214,7 @@ fn grouped_interleaved_positional_occurrences() {
.unwrap();
let pos: Vec<_> = m.grouped_values_of("pos").unwrap().collect();
assert_eq!(pos, vec![vec!["1", "2", "3", "4"]]);
assert_eq!(pos, vec![vec!["1", "2"], vec!["3"], vec!["4"]]);
let flag: Vec<_> = m.grouped_values_of("flag").unwrap().collect();
assert_eq!(flag, vec![vec!["a"], vec!["b"]]);

View file

@ -520,10 +520,6 @@ fn issue_1047_min_zero_vals_default_val() {
)
.try_get_matches_from(vec!["foo", "-d"])
.unwrap();
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("del"), 1);
}
assert_eq!(
m.get_one::<String>("del").map(|v| v.as_str()),
Some("default")