Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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.

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
JeffFaer committed Mar 21, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent bcfcff7 commit a17ccbf
Showing 1 changed file with 24 additions and 7 deletions.
31 changes: 24 additions & 7 deletions bash_completionsV2.go
Original file line number Diff line number Diff line change
@@ -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}
@@ -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[@]}")
;;
*)
@@ -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
@@ -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

0 comments on commit a17ccbf

Please sign in to comment.