@@ -201,6 +201,8 @@ __%[1]s_extract_activeHelp() {
201
201
local endIndex=${#activeHelpMarker}
202
202
203
203
while IFS='' read -r comp; do
204
+ [[ -z $comp ]] && continue
205
+
204
206
if [[ ${comp:0:endIndex} == $activeHelpMarker ]]; then
205
207
comp=${comp:endIndex}
206
208
__%[1]s_debug "ActiveHelp found: $comp"
@@ -223,16 +225,21 @@ __%[1]s_handle_completion_types() {
223
225
# If the user requested inserting one completion at a time, or all
224
226
# completions at once on the command-line we must remove the descriptions.
225
227
# 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[@]}")
236
243
;;
237
244
238
245
*)
@@ -243,11 +250,25 @@ __%[1]s_handle_completion_types() {
243
250
}
244
251
245
252
__%[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
247
257
248
258
# Short circuit to optimize if we don't have descriptions
249
259
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
251
272
return 0
252
273
fi
253
274
@@ -256,23 +277,39 @@ __%[1]s_handle_standard_completion_case() {
256
277
# Look for the longest completion so that we can format things nicely
257
278
while IFS='' read -r compline; do
258
279
[[ -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
+
261
288
# Only consider the completions that match
262
289
[[ $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.
263
295
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*}
264
301
if ((${#comp}>longest)); then
265
302
longest=${#comp}
266
303
fi
267
304
done < <(printf "%%s\n" "${completions[@]}")
268
305
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
270
307
if ((${#COMPREPLY[*]} == 1)); then
271
308
__%[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
276
313
__%[1]s_format_comp_descriptions $longest
277
314
fi
278
315
}
0 commit comments