diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b972e3..6a962d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ For breaking changes, check [here](#breaking-changes). ## Unreleased - Populate `:msg` in the `:error-fn` data for `dispatch` command errors (`:no-match`, `:input-exhausted`), like option errors already carry it +- zsh completion: classify an option without a `:desc` as an option. It was added as a value, which offered it where zsh hides described options ## 0.12.81 diff --git a/src/babashka/cli.cljc b/src/babashka/cli.cljc index 4b8bb1a..7cfd912 100644 --- a/src/babashka/cli.cljc +++ b/src/babashka/cli.cljc @@ -1711,7 +1711,7 @@ complete -F " fn " " names-sp " ") :zsh (str "#compdef " names-sp " " fn "() { - local -a lines described optdescribed bare + local -a lines described optdescribed bareopt bare lines=(\"${(@f)$(\"${words[1]}\" org.babashka.cli/completions complete --shell zsh -- \"${(@)words[2,CURRENT]}\" 2>/dev/null)}\") local do_files= l v d for l in $lines; do @@ -1721,8 +1721,11 @@ complete -F " fn " " names-sp " # _describe eats backslashes and splits on ':', so escape both v=\"${v//\\\\/\\\\\\\\}\"; d=\"${d//\\\\/\\\\\\\\}\" v=\"${v//:/\\\\:}\"; d=\"${d//:/\\\\:}\" - if [[ -z $d ]]; then bare+=(\"$v\") - elif [[ $v == -* ]]; then optdescribed+=(\"$v:$d\") + # an option is an option with or without a description: classifying an + # undescribed one as a value would offer it where zsh hides the rest + if [[ $v == -* ]]; then + if [[ -z $d ]]; then bareopt+=(\"$v\"); else optdescribed+=(\"$v:$d\"); fi + elif [[ -z $d ]]; then bare+=(\"$v\") else described+=(\"$v:$d\"); fi done local ret=1 @@ -1735,6 +1738,7 @@ complete -F " fn " " names-sp " # flags-only word), so their merged-alias display lines cannot inflate the # column layout of another group (( $#optdescribed )) && { _describe -t options option optdescribed; ret=0; } + (( $#bareopt )) && { _describe -t options option bareopt; ret=0; } (( $#bare )) && { _describe -t values value bare; ret=0; } [[ -n $do_files ]] && { _files; ret=0; } return $ret diff --git a/test/babashka/cli/completion_test.cljc b/test/babashka/cli/completion_test.cljc index a40b210..4fb12d2 100644 --- a/test/babashka/cli/completion_test.cljc +++ b/test/babashka/cli/completion_test.cljc @@ -160,6 +160,15 @@ (snippet-via-cmd cmd-table {:prog "myprogram"} shell)) shell)))) +(deftest zsh-snippet-option-classification-test + (let [zsh (snippet-via-cmd cmd-table {:prog "myprogram"} "zsh")] + (testing "a dash-prefixed candidate is classified as an option before its description is considered" + (is (str/includes? zsh "if [[ $v == -* ]]")) + (is (not (str/includes? zsh "elif [[ $v == -* ]]")))) + (testing "an option without a description is added under the options tag" + (is (str/includes? zsh "bareopt+=(\"$v\")")) + (is (str/includes? zsh "_describe -t options option bareopt"))))) + (defn- complete-out "Run the completion handler for `cmdline` and return its emitted `value\\tdescription` lines as a set of strings." diff --git a/test/resources/completion/completion.zsh b/test/resources/completion/completion.zsh index a1ac447..b9f8f3c 100644 --- a/test/resources/completion/completion.zsh +++ b/test/resources/completion/completion.zsh @@ -1,6 +1,6 @@ #compdef myprogram _babashka_cli_complete_myprogram() { - local -a lines described optdescribed bare + local -a lines described optdescribed bareopt bare lines=("${(@f)$("${words[1]}" org.babashka.cli/completions complete --shell zsh -- "${(@)words[2,CURRENT]}" 2>/dev/null)}") local do_files= l v d for l in $lines; do @@ -10,8 +10,11 @@ _babashka_cli_complete_myprogram() { # _describe eats backslashes and splits on ':', so escape both v="${v//\\/\\\\}"; d="${d//\\/\\\\}" v="${v//:/\\:}"; d="${d//:/\\:}" - if [[ -z $d ]]; then bare+=("$v") - elif [[ $v == -* ]]; then optdescribed+=("$v:$d") + # an option is an option with or without a description: classifying an + # undescribed one as a value would offer it where zsh hides the rest + if [[ $v == -* ]]; then + if [[ -z $d ]]; then bareopt+=("$v"); else optdescribed+=("$v:$d"); fi + elif [[ -z $d ]]; then bare+=("$v") else described+=("$v:$d"); fi done local ret=1 @@ -24,6 +27,7 @@ _babashka_cli_complete_myprogram() { # flags-only word), so their merged-alias display lines cannot inflate the # column layout of another group (( $#optdescribed )) && { _describe -t options option optdescribed; ret=0; } + (( $#bareopt )) && { _describe -t options option bareopt; ret=0; } (( $#bare )) && { _describe -t values value bare; ret=0; } [[ -n $do_files ]] && { _files; ret=0; } return $ret