Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"allow_hyphen_values" absorbs short options (-f), but not long options (--flag) #3880

Closed
2 tasks done
david0u0 opened this issue Jun 28, 2022 · 2 comments · Fixed by #4187
Closed
2 tasks done

"allow_hyphen_values" absorbs short options (-f), but not long options (--flag) #3880

david0u0 opened this issue Jun 28, 2022 · 2 comments · Fixed by #4187
Labels
A-parsing Area: Parser's logic and needs it changed somehow. C-bug Category: Updating dependencies M-breaking-change Meta: Implementing or merging this will introduce a breaking change.
Milestone

Comments

@david0u0
Copy link

david0u0 commented Jun 28, 2022

Please complete the following tasks

Rust Version

rustc 1.60.0-nightly (88fb06a1f 2022-02-05)

Clap Version

3.1.8

Minimal reproducible code

use clap::Parser;

#[derive(Parser, Debug)]
#[clap(disable_help_subcommand = true, args_override_self = true)]
pub enum Root {
    #[clap(allow_hyphen_values = true)]
    Run {
        #[clap(long, short)]
        flag: bool,
        #[clap(default_value = "-")]
        query: String,
        #[clap(allow_hyphen_values = true)]
        args: Vec<String>,
    },
}

fn handle_args(s: &str) -> Root {
    Root::from_iter(s.split(' '))
}

fn extract(r: Root) -> Vec<String> {
    match r {
        Root::Run {args, ..} => args
    }
}

fn main() {
    let root = handle_args("test run query -f");
    println!("{:?}", root);
    assert_eq!(extract(root), vec!["-f"]);

    let root = handle_args("test run query --flag");
    println!("{:?}", root);
    assert_eq!(extract(root), vec!["--flag"]); // <- fail!!
}

Steps to reproduce the bug with the above code

cargo run

The second assert will fail

Actual Behaviour

With argument "test run query --flag", the "--flag" will be treated as the option, instead of the positional argument

This seems be not consistent, because the short option "-f" will be treated as the positional argument

Expected Behaviour

Treat the long option as positional argument

Or treat the short option as option?

Additional Context

No response

Debug Output

first

[ clap::builder::command] Command::_do_parse
[ clap::builder::command] Command::_build: name="clap-hyphen"
[ clap::builder::command] Command::_propagate:clap-hyphen
[ clap::builder::command] Command::_check_help_and_version: clap-hyphen
[ clap::builder::command] Command::_check_help_and_version: Removing generated version
[ clap::builder::command] Command::_propagate_global_args:clap-hyphen
[ clap::builder::command] Command::_propagate removing run's help
[ clap::builder::command] Command::_propagate pushing help to run
[ clap::builder::command] Command::_derive_display_order:clap-hyphen
[ clap::builder::command] Command::_derive_display_order:run
[clap::builder::debug_asserts] Command::_debug_asserts
[clap::builder::debug_asserts] Arg::_debug_asserts:help
[clap::builder::debug_asserts] Command::_verify_positionals
[ clap::parser::parser] Parser::get_matches_with
[ clap::parser::parser] Parser::get_matches_with: Begin parsing 'RawOsStr("run")' ([114, 117, 110])
[ clap::parser::parser] Parser::get_matches_with: Positional counter...1
[ clap::parser::parser] Parser::get_matches_with: Low index multiples...false
[ clap::parser::parser] Parser::possible_subcommand: arg=Ok("run")
[ clap::parser::parser] Parser::get_matches_with: sc=Some("run")
[ clap::parser::parser] Parser::parse_subcommand
[ clap::output::usage] Usage::get_required_usage_from: incls=[], matcher=false, incl_last=true
[ clap::output::usage] Usage::get_required_usage_from: unrolled_reqs={}
[ clap::output::usage] Usage::get_required_usage_from: ret_val={}
[ clap::builder::command] Command::_build_subcommand Setting bin_name of run to "test run"
[ clap::builder::command] Command::_build_subcommand Setting display_name of run to "clap-hyphen-run"
[ clap::builder::command] Command::_build: name="run"
[ clap::builder::command] Command::_propagate:run
[ clap::builder::command] Command::_check_help_and_version: run
[ clap::builder::command] Command::_check_help_and_version: Removing generated version
[ clap::builder::command] Command::_propagate_global_args:run
[ clap::builder::command] Command::_derive_display_order:run
[clap::builder::debug_asserts] Command::_debug_asserts
[clap::builder::debug_asserts] Arg::_debug_asserts:flag
[clap::builder::debug_asserts] Arg::_debug_asserts:query
[clap::builder::debug_asserts] Arg::_debug_asserts:args
[clap::builder::debug_asserts] Arg::_debug_asserts:help
[clap::builder::debug_asserts] Command::_verify_positionals
[ clap::parser::parser] Parser::parse_subcommand: About to parse sc=run
[ clap::parser::parser] Parser::get_matches_with
[ clap::parser::parser] Parser::get_matches_with: Begin parsing 'RawOsStr("query")' ([113, 117, 101, 114, 121])
[ clap::parser::parser] Parser::get_matches_with: Positional counter...1
[ clap::parser::parser] Parser::get_matches_with: Low index multiples...false
[ clap::parser::parser] Parser::possible_subcommand: arg=Ok("query")
[ clap::parser::parser] Parser::get_matches_with: sc=None
[ clap::parser::parser] Parser::split_arg_values; arg=query, val=RawOsStr("query")
[ clap::parser::parser] Parser::split_arg_values; trailing_values=false, DontDelimTrailingVals=false
[ clap::parser::parser] Parser::get_matches_with: Begin parsing 'RawOsStr("-f")' ([45, 102])
[ clap::parser::parser] Parser::get_matches_with: Positional counter...2
[ clap::parser::parser] Parser::get_matches_with: Low index multiples...false
[ clap::parser::parser] Parser::possible_subcommand: arg=Ok("-f")
[ clap::parser::parser] Parser::get_matches_with: sc=None
[ clap::parser::parser] Parser::parse_short_arg: short_arg=ShortFlags { inner: RawOsStr("f"), utf8_prefix: CharIndices { front_offset: 0, iter: Chars(['f']) }, invalid_suffix: None }
[ clap::parser::parser] Parser::parse_short_args: positional at 2 allows hyphens
[ clap::parser::parser] Parser::get_matches_with: After parse_short_arg MaybeHyphenValue
[ clap::parser::parser] Parser::resolve_pending: id=query
[ clap::parser::parser] Parser::react action=StoreValue, identifier=Some(Index), source=CommandLine
[ clap::parser::parser] Parser::remove_overrides: id=query
[ clap::parser::arg_matcher] ArgMatcher::start_occurrence_of_arg: id=query
[ clap::builder::command] Command::groups_for_arg: id=query
[ clap::parser::parser] Parser::push_arg_values: ["query"]
[ clap::parser::parser] Parser::add_single_val_to_arg: cur_idx:=1
[ clap::builder::command] Command::groups_for_arg: id=query
[ clap::parser::arg_matcher] ArgMatcher::needs_more_vals: o=query, resolved=1, pending=0
[ clap::parser::parser] Parser::split_arg_values; arg=args, val=RawOsStr("-f")
[ clap::parser::parser] Parser::split_arg_values; trailing_values=true, DontDelimTrailingVals=false
[ clap::parser::parser] Parser::resolve_pending: id=args
[ clap::parser::parser] Parser::react action=StoreValue, identifier=Some(Index), source=CommandLine
[ clap::parser::parser] Parser::remove_overrides: id=args
[ clap::parser::arg_matcher] ArgMatcher::start_occurrence_of_arg: id=args
[ clap::builder::command] Command::groups_for_arg: id=args
[ clap::parser::parser] Parser::push_arg_values: ["-f"]
[ clap::parser::parser] Parser::add_single_val_to_arg: cur_idx:=2
[ clap::builder::command] Command::groups_for_arg: id=args
[ clap::parser::arg_matcher] ArgMatcher::needs_more_vals: o=args, resolved=1, pending=0
[ clap::parser::parser] Parser::add_defaults
[ clap::parser::parser] Parser::add_defaults:iter:flag:
[ clap::parser::parser] Parser::add_default_value:iter:flag: doesn't have default missing vals
[ clap::parser::parser] Parser::add_default_value: doesn't have conditional defaults
[ clap::parser::parser] Parser::add_default_value:iter:flag: doesn't have default vals
[ clap::parser::parser] Parser::add_defaults:iter:query:
[ clap::parser::parser] Parser::add_default_value:iter:query: doesn't have default missing vals
[ clap::parser::parser] Parser::add_default_value: doesn't have conditional defaults
[ clap::parser::parser] Parser::add_default_value:iter:query: has default vals
[ clap::parser::parser] Parser::add_default_value:iter:query: was used
[ clap::parser::parser] Parser::add_defaults:iter:args:
[ clap::parser::parser] Parser::add_default_value:iter:args: doesn't have default missing vals
[ clap::parser::parser] Parser::add_default_value: doesn't have conditional defaults
[ clap::parser::parser] Parser::add_default_value:iter:args: doesn't have default vals
[ clap::parser::parser] Parser::add_defaults:iter:help:
[ clap::parser::parser] Parser::add_default_value:iter:help: doesn't have default missing vals
[ clap::parser::parser] Parser::add_default_value: doesn't have conditional defaults
[ clap::parser::parser] Parser::add_default_value:iter:help: doesn't have default vals
[ clap::parser::validator] Validator::validate
[ clap::parser::validator] Validator::validate_conflicts
[ clap::parser::validator] Validator::validate_exclusive
[ clap::parser::validator] Validator::validate_exclusive:iter:query
[ clap::parser::validator] Validator::validate_exclusive:iter:args
[ clap::parser::validator] Validator::validate_conflicts::iter: id=query
[ clap::parser::validator] Conflicts::gather_conflicts: arg=query
[ clap::builder::command] Command::groups_for_arg: id=query
[ clap::parser::validator] Conflicts::gather_direct_conflicts id=query, conflicts=[]
[ clap::builder::command] Command::groups_for_arg: id=args
[ clap::parser::validator] Conflicts::gather_direct_conflicts id=args, conflicts=[]
[ clap::parser::validator] Conflicts::gather_conflicts: conflicts=[]
[ clap::parser::validator] Validator::validate_conflicts::iter: id=args
[ clap::parser::validator] Conflicts::gather_conflicts: arg=args
[ clap::parser::validator] Conflicts::gather_conflicts: conflicts=[]
[ clap::parser::validator] Validator::validate_required: required=ChildGraph([])
[ clap::parser::validator] Validator::gather_requires
[ clap::parser::validator] Validator::gather_requires:iter:query
[ clap::parser::validator] Validator::gather_requires:iter:args
[ clap::parser::validator] Validator::validate_required: is_exclusive_present=false
[ clap::parser::validator] Validator::validate_required_unless
[ clap::parser::validator] Validator::validate_matched_args
[ clap::parser::validator] Validator::validate_matched_args:iter:query: vals=Flatten {
inner: FlattenCompat {
iter: Fuse {
iter: Some(
Iter(
[
[
AnyValue {
inner: alloc::string::String,
},
],
],
),
),
},
frontiter: None,
backiter: None,
},
}
[ clap::parser::validator] Validator::validate_arg_num_vals
[ clap::parser::validator] Validator::validate_arg_values: arg="query"
[ clap::parser::validator] Validator::validate_arg_values: checking validator...
[ clap::parser::validator] good
[ clap::parser::validator] Validator::validate_arg_num_occurs: "query"=1
[ clap::parser::validator] Validator::validate_matched_args:iter:args: vals=Flatten {
inner: FlattenCompat {
iter: Fuse {
iter: Some(
Iter(
[
[
AnyValue {
inner: alloc::string::String,
},
],
],
),
),
},
frontiter: None,
backiter: None,
},
}
[ clap::parser::validator] Validator::validate_arg_num_vals
[ clap::parser::validator] Validator::validate_arg_values: arg="args"
[ clap::parser::validator] Validator::validate_arg_values: checking validator...
[ clap::parser::validator] good
[ clap::parser::validator] Validator::validate_arg_num_occurs: "args"=1
[ clap::parser::parser] Parser::add_defaults
[ clap::parser::parser] Parser::add_defaults:iter:help:
[ clap::parser::parser] Parser::add_default_value:iter:help: doesn't have default missing vals
[ clap::parser::parser] Parser::add_default_value: doesn't have conditional defaults
[ clap::parser::parser] Parser::add_default_value:iter:help: doesn't have default vals
[ clap::parser::validator] Validator::validate
[ clap::parser::validator] Validator::validate_conflicts
[ clap::parser::validator] Validator::validate_exclusive
[ clap::parser::validator] Validator::validate_required: required=ChildGraph([])
[ clap::parser::validator] Validator::gather_requires
[ clap::parser::validator] Validator::validate_required: is_exclusive_present=false
[ clap::parser::validator] Validator::validate_required_unless
[ clap::parser::validator] Validator::validate_matched_args
[ clap::parser::arg_matcher] ArgMatcher::get_global_values: global_arg_vec=[help, help]

second

[ clap::builder::command] Command::_do_parse
[ clap::builder::command] Command::_build: name="clap-hyphen"
[ clap::builder::command] Command::_propagate:clap-hyphen
[ clap::builder::command] Command::_check_help_and_version: clap-hyphen
[ clap::builder::command] Command::_check_help_and_version: Removing generated version
[ clap::builder::command] Command::_propagate_global_args:clap-hyphen
[ clap::builder::command] Command::_propagate removing run's help
[ clap::builder::command] Command::_propagate pushing help to run
[ clap::builder::command] Command::_derive_display_order:clap-hyphen
[ clap::builder::command] Command::_derive_display_order:run
[clap::builder::debug_asserts] Command::_debug_asserts
[clap::builder::debug_asserts] Arg::_debug_asserts:help
[clap::builder::debug_asserts] Command::_verify_positionals
[ clap::parser::parser] Parser::get_matches_with
[ clap::parser::parser] Parser::get_matches_with: Begin parsing 'RawOsStr("run")' ([114, 117, 110])
[ clap::parser::parser] Parser::get_matches_with: Positional counter...1
[ clap::parser::parser] Parser::get_matches_with: Low index multiples...false
[ clap::parser::parser] Parser::possible_subcommand: arg=Ok("run")
[ clap::parser::parser] Parser::get_matches_with: sc=Some("run")
[ clap::parser::parser] Parser::parse_subcommand
[ clap::output::usage] Usage::get_required_usage_from: incls=[], matcher=false, incl_last=true
[ clap::output::usage] Usage::get_required_usage_from: unrolled_reqs={}
[ clap::output::usage] Usage::get_required_usage_from: ret_val={}
[ clap::builder::command] Command::_build_subcommand Setting bin_name of run to "test run"
[ clap::builder::command] Command::_build_subcommand Setting display_name of run to "clap-hyphen-run"
[ clap::builder::command] Command::_build: name="run"
[ clap::builder::command] Command::_propagate:run
[ clap::builder::command] Command::_check_help_and_version: run
[ clap::builder::command] Command::_check_help_and_version: Removing generated version
[ clap::builder::command] Command::_propagate_global_args:run
[ clap::builder::command] Command::_derive_display_order:run
[clap::builder::debug_asserts] Command::_debug_asserts
[clap::builder::debug_asserts] Arg::_debug_asserts:flag
[clap::builder::debug_asserts] Arg::_debug_asserts:query
[clap::builder::debug_asserts] Arg::_debug_asserts:args
[clap::builder::debug_asserts] Arg::_debug_asserts:help
[clap::builder::debug_asserts] Command::_verify_positionals
[ clap::parser::parser] Parser::parse_subcommand: About to parse sc=run
[ clap::parser::parser] Parser::get_matches_with
[ clap::parser::parser] Parser::get_matches_with: Begin parsing 'RawOsStr("query")' ([113, 117, 101, 114, 121])
[ clap::parser::parser] Parser::get_matches_with: Positional counter...1
[ clap::parser::parser] Parser::get_matches_with: Low index multiples...false
[ clap::parser::parser] Parser::possible_subcommand: arg=Ok("query")
[ clap::parser::parser] Parser::get_matches_with: sc=None
[ clap::parser::parser] Parser::split_arg_values; arg=query, val=RawOsStr("query")
[ clap::parser::parser] Parser::split_arg_values; trailing_values=false, DontDelimTrailingVals=false
[ clap::parser::parser] Parser::get_matches_with: Begin parsing 'RawOsStr("--flag")' ([45, 45, 102, 108, 97, 103])
[ clap::parser::parser] Parser::get_matches_with: Positional counter...2
[ clap::parser::parser] Parser::get_matches_with: Low index multiples...false
[ clap::parser::parser] Parser::possible_subcommand: arg=Ok("--flag")
[ clap::parser::parser] Parser::get_matches_with: sc=None
[ clap::parser::parser] Parser::parse_long_arg
[ clap::parser::parser] Parser::parse_long_arg: Does it contain '='...
[ clap::parser::parser] Parser::parse_long_arg: Found valid arg or flag '--flag'
[ clap::parser::parser] Parser::parse_long_arg("flag"): Presence validated
[ clap::parser::parser] Parser::resolve_pending: id=query
[ clap::parser::parser] Parser::react action=StoreValue, identifier=Some(Index), source=CommandLine
[ clap::parser::parser] Parser::remove_overrides: id=query
[ clap::parser::arg_matcher] ArgMatcher::start_occurrence_of_arg: id=query
[ clap::builder::command] Command::groups_for_arg: id=query
[ clap::parser::parser] Parser::push_arg_values: ["query"]
[ clap::parser::parser] Parser::add_single_val_to_arg: cur_idx:=1
[ clap::builder::command] Command::groups_for_arg: id=query
[ clap::parser::arg_matcher] ArgMatcher::needs_more_vals: o=query, resolved=1, pending=0
[ clap::parser::parser] Parser::react action=IncOccurrence, identifier=Some(Long), source=CommandLine
[ clap::parser::parser] Parser::react: cur_idx:=2
[ clap::parser::parser] Parser::remove_overrides: id=flag
[ clap::parser::parser] Parser::remove_overrides:iter:flag: removing
[ clap::parser::arg_matcher] ArgMatcher::start_occurrence_of_arg: id=flag
[ clap::builder::command] Command::groups_for_arg: id=flag
[ clap::parser::parser] Parser::get_matches_with: After parse_long_arg ValuesDone
[ clap::parser::parser] Parser::add_defaults
[ clap::parser::parser] Parser::add_defaults:iter:flag:
[ clap::parser::parser] Parser::add_default_value:iter:flag: doesn't have default missing vals
[ clap::parser::parser] Parser::add_default_value: doesn't have conditional defaults
[ clap::parser::parser] Parser::add_default_value:iter:flag: doesn't have default vals
[ clap::parser::parser] Parser::add_defaults:iter:query:
[ clap::parser::parser] Parser::add_default_value:iter:query: doesn't have default missing vals
[ clap::parser::parser] Parser::add_default_value: doesn't have conditional defaults
[ clap::parser::parser] Parser::add_default_value:iter:query: has default vals
[ clap::parser::parser] Parser::add_default_value:iter:query: was used
[ clap::parser::parser] Parser::add_defaults:iter:args:
[ clap::parser::parser] Parser::add_default_value:iter:args: doesn't have default missing vals
[ clap::parser::parser] Parser::add_default_value: doesn't have conditional defaults
[ clap::parser::parser] Parser::add_default_value:iter:args: doesn't have default vals
[ clap::parser::parser] Parser::add_defaults:iter:help:
[ clap::parser::parser] Parser::add_default_value:iter:help: doesn't have default missing vals
[ clap::parser::parser] Parser::add_default_value: doesn't have conditional defaults
[ clap::parser::parser] Parser::add_default_value:iter:help: doesn't have default vals
[ clap::parser::validator] Validator::validate
[ clap::parser::validator] Validator::validate_conflicts
[ clap::parser::validator] Validator::validate_exclusive
[ clap::parser::validator] Validator::validate_exclusive:iter:query
[ clap::parser::validator] Validator::validate_exclusive:iter:flag
[ clap::parser::validator] Validator::validate_conflicts::iter: id=query
[ clap::parser::validator] Conflicts::gather_conflicts: arg=query
[ clap::builder::command] Command::groups_for_arg: id=query
[ clap::parser::validator] Conflicts::gather_direct_conflicts id=query, conflicts=[]
[ clap::builder::command] Command::groups_for_arg: id=flag
[ clap::parser::validator] Conflicts::gather_direct_conflicts id=flag, conflicts=[flag]
[ clap::parser::validator] Conflicts::gather_conflicts: conflicts=[]
[ clap::parser::validator] Validator::validate_conflicts::iter: id=flag
[ clap::parser::validator] Conflicts::gather_conflicts: arg=flag
[ clap::parser::validator] Conflicts::gather_conflicts: conflicts=[]
[ clap::parser::validator] Validator::validate_required: required=ChildGraph([])
[ clap::parser::validator] Validator::gather_requires
[ clap::parser::validator] Validator::gather_requires:iter:query
[ clap::parser::validator] Validator::gather_requires:iter:flag
[ clap::parser::validator] Validator::validate_required: is_exclusive_present=false
[ clap::parser::validator] Validator::validate_required_unless
[ clap::parser::validator] Validator::validate_matched_args
[ clap::parser::validator] Validator::validate_matched_args:iter:query: vals=Flatten {
inner: FlattenCompat {
iter: Fuse {
iter: Some(
Iter(
[
[
AnyValue {
inner: alloc::string::String,
},
],
],
),
),
},
frontiter: None,
backiter: None,
},
}
[ clap::parser::validator] Validator::validate_arg_num_vals
[ clap::parser::validator] Validator::validate_arg_values: arg="query"
[ clap::parser::validator] Validator::validate_arg_values: checking validator...
[ clap::parser::validator] good
[ clap::parser::validator] Validator::validate_arg_num_occurs: "query"=1
[ clap::parser::validator] Validator::validate_matched_args:iter:flag: vals=Flatten {
inner: FlattenCompat {
iter: Fuse {
iter: Some(
Iter(
[
[],
],
),
),
},
frontiter: None,
backiter: None,
},
}
[ clap::parser::validator] Validator::validate_arg_num_vals
[ clap::parser::validator] Validator::validate_arg_values: arg="flag"
[ clap::parser::validator] Validator::validate_arg_num_occurs: "flag"=1
[ clap::parser::parser] Parser::add_defaults
[ clap::parser::parser] Parser::add_defaults:iter:help:
[ clap::parser::parser] Parser::add_default_value:iter:help: doesn't have default missing vals
[ clap::parser::parser] Parser::add_default_value: doesn't have conditional defaults
[ clap::parser::parser] Parser::add_default_value:iter:help: doesn't have default vals
[ clap::parser::validator] Validator::validate
[ clap::parser::validator] Validator::validate_conflicts
[ clap::parser::validator] Validator::validate_exclusive
[ clap::parser::validator] Validator::validate_required: required=ChildGraph([])
[ clap::parser::validator] Validator::gather_requires
[ clap::parser::validator] Validator::validate_required: is_exclusive_present=false
[ clap::parser::validator] Validator::validate_required_unless
[ clap::parser::validator] Validator::validate_matched_args
[ clap::parser::arg_matcher] ArgMatcher::get_global_values: global_arg_vec=[help, help]

@tedinski
Copy link

I ran into this as well. I expected short and long args to be treated identically w.r.t. allow_hyphen_values, instead if you have "allow_hyphen_values" enabled as a final positional argument, clap will recognize long options before it but not short options.

fn main() {
    let config = CompilerArgs::parse();
    println!("{:?}", config);
}

use anyhow::Result;
use clap::Parser;

#[derive(Debug, Parser)]
#[clap(name = "clap-bug", allow_hyphen_values(true))]
pub struct CompilerArgs {
    /// a flag
    #[clap(long, short = 'O')]
    pub other: bool,

    /// Eat the rest
    #[clap(allow_hyphen_values = true, min_values(0))]
    pub remainder: Vec<String>,
}

fn test_case(args: &[&str]) -> Result<()> {
    println!("Beginning test case {:?}", args);
    let config = CompilerArgs::try_parse_from(args)?;
    println!("Got {:?}", config);
    assert!(config.other);
    Ok(())
}

#[test]
fn check_just_long() -> Result<()> {
    test_case(&["clap-bug", "--other"])
    // always works
}
#[test]
fn check_just_short() -> Result<()> {
    test_case(&["clap-bug", "-O"])
    // always fails: other = false, remainder = ["-O"]
    // expected: other = true, remainder = []
}
#[test]
fn check_short() -> Result<()> {
    test_case(&["clap-bug", "-O", "--extra"])
    // always fails: other = false, remainder = ["-O", "--extra"]
    // expected: other = true, remainder = ["--extra"]
}
#[test]
fn check_long() -> Result<()> {
    test_case(&["clap-bug", "--other", "--extra"])
    // Without AppSettings::AllowHyphenValues fails:
    // error: Found argument '--extra' which wasn't expected, or isn't valid in this context
    // With AppSettings::AllowHyphenValues, works. This seems odd.
    // I expected it to work without, and probably don't want to globally enable that option.
}
#[test]
fn check_long_delimiter() -> Result<()> {
    test_case(&["clap-bug", "--other", "--", "--extra"])
    // always works
}

Is there any way to get this behavior from clap 3.x? (That is, greedily parsing short options too, not just long, and only switch to collecting the remainder at an unrecognized option.) This is reduced from a failed attempt to upgrade from 2.x.

(I thought we might be able to switch to requiring --, but it turns out this will break things, not an option.)

@epage epage added M-breaking-change Meta: Implementing or merging this will introduce a breaking change. A-parsing Area: Parser's logic and needs it changed somehow. labels Aug 26, 2022
@epage epage added this to the 4.0 milestone Aug 26, 2022
@epage
Copy link
Member

epage commented Aug 26, 2022

At this point, we've probably had the behavior long enough that I would be hesitant to change it during 3.0. I am getting close on 4.0.0 being ready and already need to look at some allow_hyphen_value behavior, so I can look at this as part of that

epage pushed a commit to epage/clap that referenced this issue Sep 7, 2022
…first pos

This makes it match up with `Command::allow_hyphen_values` which was the
guiding factor for what the behavior should be.

This supersedes clap-rs#4039

Fixes clap-rs#3880
Fixes clap-rs#1538
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-parsing Area: Parser's logic and needs it changed somehow. C-bug Category: Updating dependencies M-breaking-change Meta: Implementing or merging this will introduce a breaking change.
Projects
None yet
3 participants