Skip to content

Commit

Permalink
Merge pull request #5290 from epage/or
Browse files Browse the repository at this point in the history
fix: Allow position-sensitive flags
  • Loading branch information
epage committed Jan 8, 2024
2 parents c603f34 + 02f8214 commit d6479ff
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 23 deletions.
4 changes: 3 additions & 1 deletion clap_builder/src/builder/arg.rs
Expand Up @@ -4078,7 +4078,9 @@ impl Arg {
}

pub(crate) fn is_takes_value_set(&self) -> bool {
self.get_action().takes_values()
self.get_num_args()
.unwrap_or_else(|| 1.into())
.takes_values()
}

/// Report whether [`Arg::allow_hyphen_values`] is set
Expand Down
22 changes: 8 additions & 14 deletions clap_builder/src/builder/debug_asserts.rs
Expand Up @@ -704,13 +704,14 @@ fn assert_arg(arg: &Arg) {
arg.get_id(),
);

assert_eq!(
arg.get_action().takes_values(),
arg.is_takes_value_set(),
"Argument `{}`'s selected action {:?} contradicts `takes_value`",
arg.get_id(),
arg.get_action()
);
if arg.is_takes_value_set() {
assert!(
arg.get_action().takes_values(),
"Argument `{}`'s selected action {:?} contradicts `takes_value`",
arg.get_id(),
arg.get_action()
);
}
if let Some(action_type_id) = arg.get_action().value_type_id() {
assert_eq!(
action_type_id,
Expand Down Expand Up @@ -774,13 +775,6 @@ fn assert_arg(arg: &Arg) {
}
}

assert_eq!(
num_vals.takes_values(),
arg.is_takes_value_set(),
"Argument {}: mismatch between `num_args` ({}) and `takes_value`",
arg.get_id(),
num_vals,
);
assert_eq!(
num_vals.is_multiple(),
arg.is_multiple_values_set(),
Expand Down
4 changes: 2 additions & 2 deletions clap_mangen/src/render.rs
Expand Up @@ -99,7 +99,7 @@ pub(crate) fn options(roff: &mut Roff, cmd: &clap::Command) {
(None, None) => vec![],
};

if opt.get_action().takes_values() {
if opt.get_num_args().expect("built").takes_values() {
if let Some(value) = &opt.get_value_names() {
header.push(roman("="));
header.push(italic(value.join(" ")));
Expand Down Expand Up @@ -288,7 +288,7 @@ fn option_environment(opt: &clap::Arg) -> Option<Vec<Inline>> {
}

fn option_default_values(opt: &clap::Arg) -> Option<String> {
if opt.is_hide_default_value_set() || !opt.get_action().takes_values() {
if opt.is_hide_default_value_set() || !opt.get_num_args().expect("built").takes_values() {
return None;
} else if !opt.get_default_values().is_empty() {
let values = opt
Expand Down
36 changes: 35 additions & 1 deletion examples/find.md
Expand Up @@ -12,7 +12,7 @@ Options:

TESTS:
--empty File is empty and is either a regular file or a directory
--name <NAME> Base of file name (the path with the leading directories removed) matches shell
--name <name> Base of file name (the path with the leading directories removed) matches shell
pattern pattern

OPERATORS:
Expand Down Expand Up @@ -41,5 +41,39 @@ $ find --empty -o --name .keep
),
]

$ find --empty -o --name .keep -o --name foo
[
(
"empty",
Bool(
true,
),
),
(
"or",
Bool(
true,
),
),
(
"name",
String(
".keep",
),
),
(
"or",
Bool(
true,
),
),
(
"name",
String(
"foo",
),
),
]

```

37 changes: 32 additions & 5 deletions examples/find.rs
@@ -1,6 +1,6 @@
use std::collections::BTreeMap;

use clap::{arg, command, ArgGroup, ArgMatches, Command};
use clap::{command, value_parser, Arg, ArgAction, ArgGroup, ArgMatches, Command};

fn main() {
let matches = cli().get_matches();
Expand All @@ -13,17 +13,44 @@ fn cli() -> Command {
.group(ArgGroup::new("tests").multiple(true))
.next_help_heading("TESTS")
.args([
arg!(--empty "File is empty and is either a regular file or a directory").group("tests"),
arg!(--name <NAME> "Base of file name (the path with the leading directories removed) matches shell pattern pattern").group("tests"),
position_sensitive_flag(Arg::new("empty"))
.long("empty")
.action(ArgAction::Append)
.help("File is empty and is either a regular file or a directory")
.group("tests"),
Arg::new("name")
.long("name")
.action(ArgAction::Append)
.help("Base of file name (the path with the leading directories removed) matches shell pattern pattern")
.group("tests")
])
.group(ArgGroup::new("operators").multiple(true))
.next_help_heading("OPERATORS")
.args([
arg!(-o - -or "expr2 is not evaluate if exp1 is true").group("operators"),
arg!(-a - -and "Same as `expr1 expr1`").group("operators"),
position_sensitive_flag(Arg::new("or"))
.short('o')
.long("or")
.action(ArgAction::Append)
.help("expr2 is not evaluate if exp1 is true")
.group("operators"),
position_sensitive_flag(Arg::new("and"))
.short('a')
.long("and")
.action(ArgAction::Append)
.help("Same as `expr1 expr1`")
.group("operators"),
])
}

fn position_sensitive_flag(arg: Arg) -> Arg {
// Flags don't track the position of each occurrence, so we need to emulate flags with
// value-less options to get the same result
arg.num_args(0)
.value_parser(value_parser!(bool))
.default_missing_value("true")
.default_value("false")
}

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum Value {
Bool(bool),
Expand Down

0 comments on commit d6479ff

Please sign in to comment.