Skip to content

Commit

Permalink
fix(bash): Fix bash completion for suggestions that contain special c…
Browse files Browse the repository at this point in the history
…haracters.

Special characters include whitepace, so this is more general than
 spf13#1743. This should also fix spf13#1740.

I added some test cases to cobra-completion-testing. This PR makes them
pass. It also doesn't trip any of the performance regression tests. I'm
happy to submit those tests as a PR as well.
  - https://github.com/JeffFaer/cobra-completion-testing/tree/special_characters
  - JeffFaer/cobra-completion-testing@52254c1
  • Loading branch information
JeffFaer committed Mar 21, 2024
1 parent bcfcff7 commit 3c78872
Showing 1 changed file with 24 additions and 7 deletions.
31 changes: 24 additions & 7 deletions bash_completionsV2.go
Expand Up @@ -59,7 +59,10 @@ __%[1]s_get_completion_results() {
# Prepare the command to request completions for the program.
# Calling ${words[0]} instead of directly %[1]s allows handling aliases
args=("${words[@]:1}")
requestComp="${words[0]} %[2]s ${args[*]}"
requestComp="${words[0]} %[2]s"
if [[ "${#args[@]}" -gt 0 ]]; then
requestComp+="$(printf " %%q" "${args[@]}")"
fi
lastParam=${words[$((${#words[@]}-1))]}
lastChar=${lastParam:$((${#lastParam}-1)):1}
Expand Down Expand Up @@ -224,15 +227,24 @@ __%[1]s_handle_completion_types() {
# completions at once on the command-line we must remove the descriptions.
# https://github.com/spf13/cobra/issues/1508
local tab=$'\t' comp
while IFS='' read -r comp; do
local matches=()
for comp in "${completions[@]}"; do
[[ -z $comp ]] && continue
# Strip any description
comp=${comp%%%%$tab*}
# Only consider the completions that match
if [[ $comp == "$cur"* ]]; then
COMPREPLY+=("$comp")
fi
done < <(printf "%%s\n" "${completions[@]}")
# Strictly speaking we could append directly to COMPREPLY here.
# But there's a pretty big performance hit involved with
# creating one subshell to printf %%q for each completion that
# matches. Instead, batch all the matches up so we can quote
# them all at once in a single printf call.
matches+=( "$comp" )
fi
done
while IFS='' read -r comp; do
COMPREPLY+=( "$comp" )
done < <(printf "%%q\n" "${matches[@]}")
;;
*)
Expand All @@ -247,7 +259,12 @@ __%[1]s_handle_standard_completion_case() {
# Short circuit to optimize if we don't have descriptions
if [[ "${completions[*]}" != *$tab* ]]; then
IFS=$'\n' read -ra COMPREPLY -d '' < <(compgen -W "${completions[*]}" -- "$cur")
# compgen's -W option respects shell quoting, so we need to escape.
local compgen_words="$(printf "%%q\n" "${completions[@]}")"
# compgen appears to respect shell quoting _after_ checking whether
# they have the right prefix, so we also need to quote cur.
local compgen_cur="$(printf "%%q" "${cur}")"
IFS=$'\n' read -ra COMPREPLY -d '' < <(IFS=$'\n'; compgen -W "${compgen_words}" -- "${compgen_cur}")
return 0
fi
Expand All @@ -271,7 +288,7 @@ __%[1]s_handle_standard_completion_case() {
__%[1]s_debug "COMPREPLY[0]: ${COMPREPLY[0]}"
comp="${COMPREPLY[0]%%%%$tab*}"
__%[1]s_debug "Removed description from single completion, which is now: ${comp}"
COMPREPLY[0]=$comp
COMPREPLY[0]="$(printf "%%q" "${comp}")"
else # Format the descriptions
__%[1]s_format_comp_descriptions $longest
fi
Expand Down

0 comments on commit 3c78872

Please sign in to comment.