Skip to content

Commit 09d5664

Browse files
kangastamarckhouzamJeffFaer
authored
Add similar whitespace escape logic to bash v2 completions than in other completions (#1743)
Signed-off-by: Toni Kangas <[email protected]> Signed-off-by: Marc Khouzam <[email protected]> Co-authored-by: Marc Khouzam <[email protected]> Co-authored-by: Jeffrey Faer <[email protected]>
1 parent 6c3c116 commit 09d5664

File tree

1 file changed

+56
-19
lines changed

1 file changed

+56
-19
lines changed

bash_completionsV2.go

+56-19
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,8 @@ __%[1]s_extract_activeHelp() {
201201
local endIndex=${#activeHelpMarker}
202202
203203
while IFS='' read -r comp; do
204+
[[ -z $comp ]] && continue
205+
204206
if [[ ${comp:0:endIndex} == $activeHelpMarker ]]; then
205207
comp=${comp:endIndex}
206208
__%[1]s_debug "ActiveHelp found: $comp"
@@ -223,16 +225,21 @@ __%[1]s_handle_completion_types() {
223225
# If the user requested inserting one completion at a time, or all
224226
# completions at once on the command-line we must remove the descriptions.
225227
# https://github.com/spf13/cobra/issues/1508
226-
local tab=$'\t' comp
227-
while IFS='' read -r comp; do
228-
[[ -z $comp ]] && continue
229-
# Strip any description
230-
comp=${comp%%%%$tab*}
231-
# Only consider the completions that match
232-
if [[ $comp == "$cur"* ]]; then
233-
COMPREPLY+=("$comp")
234-
fi
235-
done < <(printf "%%s\n" "${completions[@]}")
228+
229+
# If there are no completions, we don't need to do anything
230+
(( ${#completions[@]} == 0 )) && return 0
231+
232+
local tab=$'\t'
233+
234+
# Strip any description and escape the completion to handled special characters
235+
IFS=$'\n' read -ra completions -d '' < <(printf "%%q\n" "${completions[@]%%%%$tab*}")
236+
237+
# Only consider the completions that match
238+
IFS=$'\n' read -ra COMPREPLY -d '' < <(IFS=$'\n'; compgen -W "${completions[*]}" -- "${cur}")
239+
240+
# compgen looses the escaping so we need to escape all completions again since they will
241+
# all be inserted on the command-line.
242+
IFS=$'\n' read -ra COMPREPLY -d '' < <(printf "%%q\n" "${COMPREPLY[@]}")
236243
;;
237244
238245
*)
@@ -243,11 +250,25 @@ __%[1]s_handle_completion_types() {
243250
}
244251
245252
__%[1]s_handle_standard_completion_case() {
246-
local tab=$'\t' comp
253+
local tab=$'\t'
254+
255+
# If there are no completions, we don't need to do anything
256+
(( ${#completions[@]} == 0 )) && return 0
247257
248258
# Short circuit to optimize if we don't have descriptions
249259
if [[ "${completions[*]}" != *$tab* ]]; then
250-
IFS=$'\n' read -ra COMPREPLY -d '' < <(compgen -W "${completions[*]}" -- "$cur")
260+
# First, escape the completions to handle special characters
261+
IFS=$'\n' read -ra completions -d '' < <(printf "%%q\n" "${completions[@]}")
262+
# Only consider the completions that match what the user typed
263+
IFS=$'\n' read -ra COMPREPLY -d '' < <(IFS=$'\n'; compgen -W "${completions[*]}" -- "${cur}")
264+
265+
# compgen looses the escaping so, if there is only a single completion, we need to
266+
# escape it again because it will be inserted on the command-line. If there are multiple
267+
# completions, we don't want to escape them because they will be printed in a list
268+
# and we don't want to show escape characters in that list.
269+
if (( ${#COMPREPLY[@]} == 1 )); then
270+
COMPREPLY[0]=$(printf "%%q" "${COMPREPLY[0]}")
271+
fi
251272
return 0
252273
fi
253274
@@ -256,23 +277,39 @@ __%[1]s_handle_standard_completion_case() {
256277
# Look for the longest completion so that we can format things nicely
257278
while IFS='' read -r compline; do
258279
[[ -z $compline ]] && continue
259-
# Strip any description before checking the length
260-
comp=${compline%%%%$tab*}
280+
281+
# Before checking if the completion matches what the user typed,
282+
# we need to strip any description and escape the completion to handle special
283+
# characters because those escape characters are part of what the user typed.
284+
# Don't call "printf" in a sub-shell because it will be much slower
285+
# since we are in a loop.
286+
printf -v comp "%%q" "${compline%%%%$tab*}" &>/dev/null || comp=$(printf "%%q" "${compline%%%%$tab*}")
287+
261288
# Only consider the completions that match
262289
[[ $comp == "$cur"* ]] || continue
290+
291+
# The completions matches. Add it to the list of full completions including
292+
# its description. We don't escape the completion because it may get printed
293+
# in a list if there are more than one and we don't want show escape characters
294+
# in that list.
263295
COMPREPLY+=("$compline")
296+
297+
# Strip any description before checking the length, and again, don't escape
298+
# the completion because this length is only used when printing the completions
299+
# in a list and we don't want show escape characters in that list.
300+
comp=${compline%%%%$tab*}
264301
if ((${#comp}>longest)); then
265302
longest=${#comp}
266303
fi
267304
done < <(printf "%%s\n" "${completions[@]}")
268305
269-
# If there is a single completion left, remove the description text
306+
# If there is a single completion left, remove the description text and escape any special characters
270307
if ((${#COMPREPLY[*]} == 1)); then
271308
__%[1]s_debug "COMPREPLY[0]: ${COMPREPLY[0]}"
272-
comp="${COMPREPLY[0]%%%%$tab*}"
273-
__%[1]s_debug "Removed description from single completion, which is now: ${comp}"
274-
COMPREPLY[0]=$comp
275-
else # Format the descriptions
309+
COMPREPLY[0]=$(printf "%%q" "${COMPREPLY[0]%%%%$tab*}")
310+
__%[1]s_debug "Removed description from single completion, which is now: ${COMPREPLY[0]}"
311+
else
312+
# Format the descriptions
276313
__%[1]s_format_comp_descriptions $longest
277314
fi
278315
}

0 commit comments

Comments
 (0)