diff --git a/bash_completion b/bash_completion index 64ca04c4c81..12172ab3a29 100644 --- a/bash_completion +++ b/bash_completion @@ -1352,10 +1352,12 @@ _comp_delimited() # `show-all-if-ambiguous` on, but even that has cases where it fails # and the last separator including everything before it is lost. # https://github.com/scop/bash-completion/pull/913#issuecomment-1490140309 - local i - for i in "${!COMPREPLY[@]}"; do - COMPREPLY[i]="$prefix${COMPREPLY[i]}" - done + if [[ $prefix ]]; then + local i + for i in "${!COMPREPLY[@]}"; do + COMPREPLY[i]="$prefix${COMPREPLY[i]}" + done + fi [[ $delimiter != : ]] || _comp_ltrim_colon_completions "$cur" } diff --git a/completions/cppcheck b/completions/cppcheck index 5867fc7f7ae..589c600d903 100644 --- a/completions/cppcheck +++ b/completions/cppcheck @@ -16,17 +16,8 @@ _comp_cmd_cppcheck() return ;; --enable) - # split comma-separated list - local split="" - if [[ $cur == ?*,* ]]; then - prev="${cur%,*}" - cur="${cur##*,}" - split="set" - fi - _comp_compgen -- -W 'all warning style performance portability - information unusedFunction missingInclude' && - [[ $split ]] && - _comp_compgen -Rv COMPREPLY -- -P "$prev," -W '"${COMPREPLY[@]}"' + _comp_delimited , -W 'all warning style performance portability + information unusedFunction missingInclude' return ;; --error-exitcode) diff --git a/completions/firefox b/completions/firefox index e84d6446ad2..b698753c3ed 100644 --- a/completions/firefox +++ b/completions/firefox @@ -5,7 +5,7 @@ _comp_cmd_firefox() local cur prev words cword was_split comp_args _comp_initialize -s -- "$@" || return - [[ $cur == -MOZ_LOG*=* ]] && prev=${cur%%=*} cur=${cur#*=} + [[ ! $was_split && $cur == -MOZ_LOG*=* ]] && prev=${cur%%=*} cur=${cur#*=} case $prev in --help | --version | --display | --UILocale | -MOZ_LOG | --new-window | --new-tab | \ diff --git a/completions/make b/completions/make index 94e2b73b9de..f9da4c90e11 100644 --- a/completions/make +++ b/completions/make @@ -110,9 +110,9 @@ _comp_cmd_make() elif [[ $cur == *=* ]]; then prev=${cur%%=*} cur=${cur#*=} - local diropt + local diropt="" [[ ${prev,,} == *dir?(ectory) ]] && diropt=-d - _comp_compgen_filedir $diropt + _comp_compgen_filedir ${diropt:+"$diropt"} else # before we check for makefiles, see if a path was specified # with -C/--directory diff --git a/completions/openssl b/completions/openssl index 4bd45cac9c0..1ed69e584c8 100644 --- a/completions/openssl +++ b/completions/openssl @@ -32,9 +32,9 @@ _comp_cmd_openssl__compgen_digests() "$1" dgst -h 2>&1 | _comp_awk '/^-.*[ \t]to use the .* message digest algorithm/ { print $1 }' )" - _comp_compgen -ac "${cur#-}" split -P "-" -- "$("$1" help 2>&1 | + _comp_compgen_split -- "$("$1" help 2>&1 | command sed -ne '/^Message Digest commands/,/^[[:space:]]*$/p' | - command sed -e 1d)" + command sed -e '1d;s/^/-/')" } _comp_cmd_openssl() diff --git a/completions/strings b/completions/strings index 45f0e6064c3..52464a80d62 100644 --- a/completions/strings +++ b/completions/strings @@ -38,8 +38,8 @@ _comp_cmd_strings() [[ ${COMPREPLY-} == *= ]] && compopt -o nospace return elif [[ $cur == @* ]]; then - _comp_compgen -c "${cur:1}" filedir - COMPREPLY=("${COMPREPLY[@]/#/@}") + _comp_compgen -c "${cur:1}" filedir && + COMPREPLY=("${COMPREPLY[@]/#/@}") return fi diff --git a/completions/tshark b/completions/tshark index 249670f87ad..b7e2f6a398c 100644 --- a/completions/tshark +++ b/completions/tshark @@ -2,7 +2,7 @@ _comp_cmd_tshark() { - local cur prev words cword comp_args prefix + local cur prev words cword comp_args prefix="" _comp_initialize -n : -- "$@" || return case $cur in diff --git a/doc/api-and-naming.md b/doc/api-and-naming.md index e7f4ee6ab96..824e351e154 100644 --- a/doc/api-and-naming.md +++ b/doc/api-and-naming.md @@ -172,7 +172,8 @@ The exit status is implementation-defined. - The `_comp_compgen -- COMPGEN_ARGS` returns whether there is at least one completion. This is useful when one wants to reuse the array content with - `"${tmp[@]}"` avoiding `nounset` error. + `"${tmp[@]}"` avoiding `nounset` error in Bash <= 4.3 for an empty array + `tmp`. - Some use other rules for the exit status. E.g., `help` and `usage` return whether there were options *before* filtering by cur. This is used for `_comp_compgen_help || _comp_compgen_usage`. @@ -206,8 +207,8 @@ in `_comp_compgen_mygen1`. _comp_compgen_mygen1() { local -a arr=(1 2 3) - _comp_compgen -av arr -- -W '4 5 6' - _comp_compgen_set "${arr[@]/#p}" + _comp_compgen -av arr -- -W '4 5 6' && + _comp_compgen_set "${arr[@]/#p}" } _comp_compgen -v arr mygen1 # fails to get the result in array `arr` @@ -222,8 +223,8 @@ assigning the final result. _comp_compgen_mygen1() { local -a arr=(1 2 3) - _comp_compgen -av arr -- -W '4 5 6' - _comp_compgen -U arr set "${arr[@]/#p}" + _comp_compgen -av arr -- -W '4 5 6' && + _comp_compgen -U arr set "${arr[@]/#p}" } ``` diff --git a/doc/styleguide.md b/doc/styleguide.md index 46c4b4dbf4a..51426c30808 100644 --- a/doc/styleguide.md +++ b/doc/styleguide.md @@ -111,6 +111,16 @@ E.g. write `${foo[bar]}`, not `${foo[$bar]}`, and similarly `${foo[bar+1]}` vs `${foo[((bar+1))]}` or `${foo[$((bar+1))]}`, `${foo[--i]}` vs `${foo[((--i))]}`. +## `((${#array[@]})) && cmd "${array[@]}"` + +When one uses the array expansion of the form `"${array[@]}"` or `${array[*]}`, +please make sure that the `array` is not empty. This is because of a strange +behavior of Bash <= 4.3, where `${array[@]}` and `${array[*]}` fail for the +`nounset` error when `array` is an empty array. It can be explicitly tested +with `((${#array[@]}))`, or the exit status of `_comp_compgen` that assigned +values to the array can be used (when the generator is designed to return the +appropriate exit status). + ## Loop variable names Use `i`, `j`, `k` for loop-local indices; `n` and `m` for lengths; some other