From 58e2f9b1a83e89630a861e525acc2952c40abbe6 Mon Sep 17 00:00:00 2001 From: Jeffrey Faer Date: Tue, 25 Nov 2025 15:43:21 -0700 Subject: [PATCH 1/3] fix(bash): Escape common prefixes that are inserted by the first completion request. --- bash_completionsV2.go | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/bash_completionsV2.go b/bash_completionsV2.go index d2397aa36..f448d55a4 100644 --- a/bash_completionsV2.go +++ b/bash_completionsV2.go @@ -288,18 +288,42 @@ __%[1]s_handle_completion_types() { # Only consider the completions that match IFS=$'\n' read -ra COMPREPLY -d '' < <(IFS=$'\n'; compgen -W "${completions[*]}" -- "${cur}") - # compgen looses the escaping so we need to escape all completions again since they will + # compgen removes escaping so we need to escape all completions again since they will # all be inserted on the command-line. - IFS=$'\n' read -ra COMPREPLY -d '' < <(printf "%%q\n" "${COMPREPLY[@]}") + __%[1]s_escape_compreply + ;; + + 63) + # Type: Listing completions after successive tabs + __%[1]s_handle_standard_completion_case + + # It seems unlikely that this should happen. If there's only a single + # completion, why wouldn't it have been inserted with the first tab? + # Regardless, if there's only a single completion, escape it. + if (( ${#COMPREPLY[@]} == 1)); then + __%[1]s_escape_compreply + fi + # Otherwise, these completion options will be displayed to the user in a + # list, and we don't want to show them escape sequences. ;; *) # Type: complete (normal completion) __%[1]s_handle_standard_completion_case + # On the first tab, Bash will automatically insert the common prefix of + # all the completion options. We need to make sure these options are + # escaped since some part of them may be inserted on the command-line. + # These completion options shouldn't be displayed to the user in a list + # yet. That'll happen on their next tab which will come in as COMP_TYPE=63. + __%[1]s_escape_compreply ;; esac } +__%[1]s_escape_compreply() { + IFS=$'\n' read -ra COMPREPLY -d '' < <(printf "%%q\n" "${COMPREPLY[@]}") +} + __%[1]s_handle_standard_completion_case() { local tab=$'\t' @@ -312,14 +336,8 @@ __%[1]s_handle_standard_completion_case() { IFS=$'\n' read -ra completions -d '' < <(printf "%%q\n" "${completions[@]}") # Only consider the completions that match what the user typed IFS=$'\n' read -ra COMPREPLY -d '' < <(IFS=$'\n'; compgen -W "${completions[*]}" -- "${cur}") + # Compgen removes escaping, so COMPREPLY will be unescaped here. - # compgen looses the escaping so, if there is only a single completion, we need to - # escape it again because it will be inserted on the command-line. If there are multiple - # completions, we don't want to escape them because they will be printed in a list - # and we don't want to show escape characters in that list. - if (( ${#COMPREPLY[@]} == 1 )); then - COMPREPLY[0]=$(printf "%%q" "${COMPREPLY[0]}") - fi return 0 fi @@ -354,10 +372,10 @@ __%[1]s_handle_standard_completion_case() { fi done < <(printf "%%s\n" "${completions[@]}") - # If there is a single completion left, remove the description text and escape any special characters + # If there is a single completion left, remove the description text. if ((${#COMPREPLY[*]} == 1)); then __%[1]s_debug "COMPREPLY[0]: ${COMPREPLY[0]}" - COMPREPLY[0]=$(printf "%%q" "${COMPREPLY[0]%%%%$tab*}") + COMPREPLY[0]="${COMPREPLY[0]%%%%$tab*}" __%[1]s_debug "Removed description from single completion, which is now: ${COMPREPLY[0]}" else # Format the descriptions From 5d1cc673a4b7f1488a57ba7abf92527c3e5f2b9b Mon Sep 17 00:00:00 2001 From: Jeffrey Faer Date: Tue, 25 Nov 2025 16:58:16 -0700 Subject: [PATCH 2/3] fix spaces vs tabs --- bash_completionsV2.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bash_completionsV2.go b/bash_completionsV2.go index f448d55a4..29e1214cf 100644 --- a/bash_completionsV2.go +++ b/bash_completionsV2.go @@ -303,8 +303,8 @@ __%[1]s_handle_completion_types() { if (( ${#COMPREPLY[@]} == 1)); then __%[1]s_escape_compreply fi - # Otherwise, these completion options will be displayed to the user in a - # list, and we don't want to show them escape sequences. + # Otherwise, these completion options will be displayed to the user in a + # list, and we don't want to show them escape sequences. ;; *) From 1335af36b4521db627ef0b232a2ce726c38fa2db Mon Sep 17 00:00:00 2001 From: Jeffrey Faer Date: Wed, 26 Nov 2025 15:10:57 -0700 Subject: [PATCH 3/3] don't escape COMPREPLY if it's empty. Otherwise, we end up putting a single empty string in COMPREPLY. --- bash_completionsV2.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bash_completionsV2.go b/bash_completionsV2.go index 29e1214cf..944acf590 100644 --- a/bash_completionsV2.go +++ b/bash_completionsV2.go @@ -321,6 +321,9 @@ __%[1]s_handle_completion_types() { } __%[1]s_escape_compreply() { + if (( ${#COMPREPLY[@]} == 0 )); then + return + fi IFS=$'\n' read -ra COMPREPLY -d '' < <(printf "%%q\n" "${COMPREPLY[@]}") }