From 5a3dcf3e70d3a52084085c37595ff7a3b4a92dbd Mon Sep 17 00:00:00 2001 From: Guilherme Beltramini Date: Sun, 31 May 2026 13:25:06 -0300 Subject: [PATCH] Fix case when parameter appears in parenthesis --- core/cli_root/autocomplete_helpers.sh | 20 +++++++++---------- .../cli_root/test_autocomplete_helpers.sh | 14 +++++++++++++ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/core/cli_root/autocomplete_helpers.sh b/core/cli_root/autocomplete_helpers.sh index 98fa32a..cecfb62 100644 --- a/core/cli_root/autocomplete_helpers.sh +++ b/core/cli_root/autocomplete_helpers.sh @@ -86,16 +86,13 @@ _mycli_extract_parameters() { # _mycli_extract_parameters "$usage" # --> "--foo --help --some-flag" local -r usage=$1 - # Extract the parameters that: - # - start with a dash ("-") - # - are not preceded by any of "[a-zA-Z0-9_<" ("[" must appear in the beginning of the negation "[^...]") - # - end before any of "] =,": "--foo --foo=42 --bar]" or "-f, --foo" (only appears in the options) - # - exclude the 'parameter' "--" + # Normalize separators used in docopt alternatives/groups, split by whitespace, then extract + # option-like tokens while ignoring plain words that contain dashes (for example: "some-command"). echo "$usage" | - sed 's/^/ /' | - grep -oE -- '[^[a-zA-Z0-9_<]-[^] =,]+' | - sed 's/^[[:space:]]*//' | - grep -vE '^--$' || : + tr '()|' ' ' | + tr -s '[:space:]' '\n' | + sed -E 's/^\[+// ; s/[=,].*$// ; s/\]+$//' | + grep -E -- '^--?[[:alnum:]_][[:alnum:]_-]*$' || : } _mycli_extract_additional_commands() { @@ -260,7 +257,10 @@ _mycli_get_arg_description() { # the function `_mycli_extract_parameter_names`. local -r docopt_options_first_lines=$(sed -E '/^[[:space:]]{6,}/d' <<<"$docopt_options") - if line_number=$(grep -nE -- "(^| )$arg( |$)" <<<"$parameter_names_in_options" | cut -d: -f1); then + # Use exact token matching instead of regex so arguments containing regex characters + # never trigger parsing errors (for example: "(--my"). + line_number=$(awk -v needle="$arg" '{for (i = 1; i <= NF; i++) if ($i == needle) {print NR; exit}}' <<<"$parameter_names_in_options") + if [[ -n "$line_number" ]]; then sed -n "${line_number}p" <<<"$docopt_options_first_lines" | sed 's/^[[:space:]]*//' | grep -Eo ' {2,}.*' | diff --git a/tests/core/cli_root/test_autocomplete_helpers.sh b/tests/core/cli_root/test_autocomplete_helpers.sh index 57f14d5..e524725 100755 --- a/tests/core/cli_root/test_autocomplete_helpers.sh +++ b/tests/core/cli_root/test_autocomplete_helpers.sh @@ -110,6 +110,16 @@ EOF ) assertEquals "$expected" "$result" + # Parenthesized option groups should not leak parentheses into parameter names. + result=$(_mycli_extract_parameters "foo bar baz (--name=NAME | --id=ID)") + expected=$( + cat <<-EOF + --name + --id +EOF + ) + assertEquals "$expected" "$result" + # Concatenating the usage line and the "Options" section result=$(_mycli_extract_parameters "$(echo -e "foo bar --foo Options:\n--bar Some description\n-f, --foo")") expected=$( @@ -262,6 +272,10 @@ test__mycli_get_arg_description() { expected="" assertEquals "$expected" "$result" + result=$(_mycli_get_arg_description "(--my" "$DOCOPT_OPTIONS" "$PARAMETER_NAMES_IN_OPTIONS") + expected="" + assertEquals "$expected" "$result" + result=$(_mycli_get_arg_description "x" "$DOCOPT_OPTIONS" "$PARAMETER_NAMES_IN_OPTIONS") expected="" assertEquals "$expected" "$result"