clap icon indicating copy to clipboard operation
clap copied to clipboard

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

Open david0u0 opened this issue 2 years ago • 0 comments

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]

david0u0 avatar Jun 28 '22 09:06 david0u0