From 3ba6f59c53695e0bd5b0b48f3f74532ad6611999 Mon Sep 17 00:00:00 2001 From: sigoden Date: Fri, 25 Aug 2023 12:35:53 +0800 Subject: [PATCH] fix: dashes parsing --- src/matcher.rs | 27 ++++++++++--------- tests/compgen.rs | 25 ++++++++++++++++- ...gration__compgen__assing_option_value.snap | 12 +++++++++ .../integration__compgen__dashes_at.snap | 14 ++++++++++ 4 files changed, 64 insertions(+), 14 deletions(-) create mode 100644 tests/snapshots/integration__compgen__dashes_at.snap diff --git a/src/matcher.rs b/src/matcher.rs index 3b9cb454..3475af1a 100644 --- a/src/matcher.rs +++ b/src/matcher.rs @@ -22,7 +22,7 @@ pub(crate) struct Matcher<'a, 'b> { args: &'b [String], flag_option_args: Vec>>, positional_args: Vec<&'b str>, - dashes: Vec, + dashes: Option, arg_comp: ArgComp, choice_fns: HashSet<&'a str>, script_path: Option, @@ -69,7 +69,7 @@ impl<'a, 'b> Matcher<'a, 'b> { let mut arg_index = 1; let mut flag_option_args = vec![vec![]]; let mut positional_args = vec![]; - let mut dashes = vec![]; + let mut dashes = None; let mut split_last_arg_at = None; let mut arg_comp = ArgComp::Any; let mut choice_fns = HashSet::new(); @@ -77,7 +77,7 @@ impl<'a, 'b> Matcher<'a, 'b> { if root.delegated() { positional_args = args.iter().skip(1).map(|v| v.as_str()).collect(); } else { - let mut is_rest_args_positional = false; // arg(like -f --foo) will be positional arg + let mut is_rest_args_positional = false; // option(e.g. -f --foo) will be treated as positional arg if let Some(arg) = args.last() { if arg.starts_with('-') { arg_comp = ArgComp::FlagOrOption; @@ -89,7 +89,6 @@ impl<'a, 'b> Matcher<'a, 'b> { let cmd = cmds[cmd_level].1; let arg = args[arg_index].as_str(); if arg == "--" { - dashes.push(positional_args.len()); if is_rest_args_positional { add_positional_arg( &mut positional_args, @@ -98,8 +97,13 @@ impl<'a, 'b> Matcher<'a, 'b> { cmd, ); } + if dashes.is_none() { + dashes = Some(positional_args.len()); + if arg_index != args_len - 1 { + is_rest_args_positional = true + } + } } else if is_rest_args_positional - || !dashes.is_empty() || (cmd.no_flags_options_subcommands() && !KNOWN_OPTIONS.contains(&arg)) { add_positional_arg( @@ -267,11 +271,8 @@ impl<'a, 'b> Matcher<'a, 'b> { pub(crate) fn to_arg_values_for_choice_fn(&self) -> Vec { let mut output: Vec = self.to_arg_values_base(); - if !self.dashes.is_empty() { - output.push(ArgcValue::Multiple( - "_dashes".into(), - self.dashes.iter().map(|v| v.to_string()).collect(), - )); + if let Some(idx) = self.dashes { + output.push(ArgcValue::Single("_dashes".into(), idx.to_string())); } let last_cmd = self.cmds[self.cmds.len() - 1].1; if let Some(name) = &last_cmd.name { @@ -627,13 +628,13 @@ impl<'a, 'b> Matcher<'a, 'b> { while param_index < params_len && arg_index < args_len { let param = &cmd.positional_params[param_index]; if param.multiple() { - let dash_idx = self.dashes.first().cloned().unwrap_or_default(); + let dashes_at = self.dashes.unwrap_or_default(); let takes = if param_index == 0 - && dash_idx > 0 + && dashes_at > 0 && params_len == 2 && cmd.positional_params[1].multiple() { - dash_idx + dashes_at } else { (args_len - arg_index).saturating_sub(params_len - param_index) + 1 }; diff --git a/tests/compgen.rs b/tests/compgen.rs index 398ed8c9..b5c16e14 100644 --- a/tests/compgen.rs +++ b/tests/compgen.rs @@ -432,6 +432,25 @@ cmda() { :; } snapshot_compgen!(SCRIPT, vec![vec!["prog", ""],]); } +#[test] +fn dashes_at() { + let script = r###" +# @arg val*[`_choice_fn`] +_choice_fn() { + if [[ -z "$argc__dashes" ]]; then + echo -e "abc\ndef\nghi" + else + echo -e "v1\nv2" + fi +} +"###; + + snapshot_compgen!( + script, + vec![vec!["prog", "abc", ""], vec!["prog", "abc", "--", ""],] + ); +} + #[test] fn no_space() { let script = r###" @@ -520,7 +539,11 @@ _choice_fn() { snapshot_compgen!( script, - vec![vec!["prog", "--oa=abc"], vec!["prog", "oa=abc"],] + vec![ + vec!["prog", "--oa=abc"], + vec!["prog", "oa=abc"], + vec!["prog", "--", "--oa=abc"] + ] ); } diff --git a/tests/snapshots/integration__compgen__assing_option_value.snap b/tests/snapshots/integration__compgen__assing_option_value.snap index 72ffe18c..dc644bc4 100644 --- a/tests/snapshots/integration__compgen__assing_option_value.snap +++ b/tests/snapshots/integration__compgen__assing_option_value.snap @@ -24,4 +24,16 @@ argc__index=0 /color:green argc__positionals=([0]="oa=abc") /color:green argc_val=oa=abc /color:green +************ COMPGEN `prog -- --oa=abc` ************ +__argc_filter= /color:green +ARGC_COMPGEN=1 /color:green +ARGC_FILTER=--oa=abc /color:green +ARGC_LAST_ARG=--oa=abc /color:green +ARGC_VARS=YXJnY192YWw9Jy0tb2E9YWJjJzthcmdjX19hcmdzPSggcHJvZyAtLSAnLS1vYT1hYmMnICk7YXJnY19faW5kZXg9MDthcmdjX19kYXNoZXM9MDthcmdjX19wb3NpdGlvbmFscz0oICctLW9hPWFiYycgKTs= /color:green +argc__args=([0]="prog" [1]="--" [2]="--oa=abc") /color:green +argc__dashes=0 /color:green +argc__index=0 /color:green +argc__positionals=([0]="--oa=abc") /color:green +argc_val=--oa=abc /color:green + diff --git a/tests/snapshots/integration__compgen__dashes_at.snap b/tests/snapshots/integration__compgen__dashes_at.snap new file mode 100644 index 00000000..f6aa7356 --- /dev/null +++ b/tests/snapshots/integration__compgen__dashes_at.snap @@ -0,0 +1,14 @@ +--- +source: tests/compgen.rs +expression: data +--- +************ COMPGEN `prog abc ` ************ +abc /color:green +def /color:green +ghi /color:green + +************ COMPGEN `prog abc -- ` ************ +v1 /color:green +v2 /color:green + +