Open lukehsiao opened 1 year ago
I've reduced the reproduction case down to:
#!/usr/bin/env -S rust-script
//! ```cargo
//! [dependencies]
//! clap = { version = "4", features = ["derive"] }
//! ```
use std::path::PathBuf;
use clap::Parser;
#[derive(Debug, clap::Parser)]
#[clap(version, about)]
pub struct Opt {
/// Input file
#[clap(short, long)]
pub input: Option<PathBuf>,
/// Allow a series of potentially hyphenated values
#[clap(required = true, allow_hyphen_values = true)]
pub choices: Vec<String>,
}
fn main() {
let opt = Opt::parse();
dbg!(opt);
}
Switching to clap 3 produces the same result
#!/usr/bin/env -S rust-script
//! ```cargo
//! [dependencies]
//! clap = { version = "3", features = ["derive"] }
//! ```
use std::path::PathBuf;
use clap::Parser;
#[derive(Debug, clap::Parser)]
#[clap(version, about)]
pub struct Opt {
/// Input file
#[clap(short, long)]
pub input: Option<PathBuf>,
/// Allow a series of potentially hyphenated values
#[clap(required = true, allow_hyphen_values = true)]
pub choices: Vec<String>,
}
fn main() {
let opt = Opt::parse();
dbg!(opt);
}
[clap-4283.rs:26] opt = Opt {
input: None,
choices: [
"-3",
"-i",
"panic.rs",
],
}
However, if I switch to Command::allow_hyphen_values
, it works as reported
#!/usr/bin/env -S rust-script
//! ```cargo
//! [dependencies]
//! clap = { version = "3", features = ["derive"] }
//! ```
use std::path::PathBuf;
use clap::Parser;
#[derive(Debug, clap::Parser)]
#[clap(version, about)]
#[clap(allow_hyphen_values = true)]
pub struct Opt {
/// Input file
#[clap(short, long)]
pub input: Option<PathBuf>,
/// Allow a series of potentially hyphenated values
#[clap(required = true)]
pub choices: Vec<String>,
}
fn main() {
let opt = Opt::parse();
dbg!(opt);
}
[clap-4283.rs:27] opt = Opt {
input: Some(
"panic.rs",
),
choices: [
"-3",
],
}
However, if I switch to Command::allow_hyphen_values, it works as reported
My apologies on the incomplete report. We were actually using #[clap(setting = clap::AppSettings::AllowLeadingHyphen)]
with clap v3, which was working. I believe this is similar to Command::allow_hyphen_values
. Either way, your minimum reproduction case is much more minimal and shows the issue :).
(Plus, I learned about #!/usr/bin/env -S rust-script
, so thanks!)
My apologies on the incomplete report. We were actually using #[clap(setting = clap::AppSettings::AllowLeadingHyphen)] with clap v3, which was working. I believe this is similar to Command::allow_hyphen_values. Either way, your minimum reproduction case is much more minimal and shows the issue :).
Yes, they are the same thing.
(Plus, I learned about #!/usr/bin/env -S rust-script, so thanks!)
I'm actually using a fork that exists for the purpose of creating an RFC
Hmm, looks like we had a test specifically for the "broken" behavior in clap 3. This is going to take some digging to unwind all of this
#[test]
fn leading_hyphen_with_flag_after() {
let r = Command::new("mvae")
.arg(
arg!(o: -o <opt> "some opt")
.multiple_values(true)
.allow_hyphen_values(true),
)
.arg(arg!(f: -f "some flag").action(ArgAction::SetTrue))
.try_get_matches_from(vec!["", "-o", "-2", "-f"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.contains_id("o"));
assert_eq!(
m.get_many::<String>("o")
.unwrap()
.map(|v| v.as_str())
.collect::<Vec<_>>(),
&["-2", "-f"]
);
assert!(!*m.get_one::<bool>("f").expect("defaulted by clap"));
}
So consuming the flag after has been the behavior since the arg-specific setting was introduced in #755
https://github.com/BurntSushi/ripgrep/pull/233#issuecomment-261838065 discusses the motivation for the design in #755
In #4187, what I fixed was when you have the flag before the positional (-i test/file.png -3
), it still left -3 -i test/file.png
as-is.
In 7a2bbca62bf245970866d3de76293de435dc8dbe, we had a check for self.cmd.is_allow_hyphen_values_set()
and if the short was known. I think this was the logic that wasn't mirrored over into the arg-specific version, replacing the logic for checking if the last seen arg supported hyphen values.
So the rules as of today
num_args(1)
(we generally try to discourage unbounded num_args
). The workaround otherwise is to use an attached value, like -fvalue
or --flag=value
.--
can always be used.At the moment, I'm leaning towards this being a documentation bug rather than a behavior bug or feature request.
At the moment, I'm leaning towards this being a documentation bug rather than a behavior bug or feature request.
This is reasonable.
It would "break" the cli of choose
if they adopt clap v4, so, selfishly, I'd vote that this become a supported feature as it was possible with structopt and clap v3, but also understand not wanting to.
That said, if a documentation change turns out to be the plan, I'd suggest changing both the docs linked above on allow_hyphen_values
and other references like https://github.com/clap-rs/clap/pull/4187/files#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4edR47 which suggest a known short flag would be treated differently then a hyphen-value.
If I'm understanding choice
s situation, you are using negative numbers but there is additional syntax so the "allow negative numbers" feature doesn't work for it?
If I'm understanding choices situation, you are using negative numbers but there is additional syntax so the "allow negative numbers" feature doesn't work for it?
Correct, they can also be things like -3:-2
, where the colon messes things up.
Something I've been considering is generalizing allow_negative_numbers
to asking the ValueParser
whether the value "looks correct".
The issues to work out
TypedValueParser
implementation0isize
isn't too greedy but a String
would be)ValueParser
without any other opt-in)That does sound interesting!
I'm no clap
expert, so to double check, it is not possible to get the behavior I want in clap v4 by implementing a TypedValueParser
, right?
At the moment, it is not. I have re-worked the issue for being focused on restoring your use case, somehow, including possibly the TypedValueParser
route.
Another interesting angle to include in this is that when we are parsing, we try to capture up to the max for num_args
. If we instead capture up to the min for num_args
and then check the TypedValueParser
for anything else, this will
TypedValueParser
in most casesGot it. Thank you for the triaging and explanations :)
Please complete the following tasks
Rust Version
rustc 1.64.0 (a55dd71d5 2022-09-19)
Clap Version
4.0.2
Minimal reproducible code
Steps to reproduce the bug with the above code
Actual Behaviour
This is both in v3 and v4 with
Arg::allow_hyphen_values
Expected Behaviour
With clap v3 and
Command::allow_hyphen_values
, this parsed correctly as-3
as a positional value, and-i test/file.png
as an option.Also note that using
allow_negative_numbers
is not a solution here, as sometimes the values may be things like-3:-4
.Additional Context
https://docs.rs/clap/latest/clap/builder/struct.Arg.html#method.allow_hyphen_values
This issue seems to go against the documentation. Here, we have a positional argument followed by a known flag, but, the flag is NOT treated as a flag, and instead causes an unexpected parsing error.
This behavior is the same whether or not I add
trailing_var_arg = false
to the positional arg.Debug Output