@@ -110,7 +110,7 @@ __podman_process_completion_results() {
110
110
111
111
if (( (directive & shellCompDirectiveFilterFileExt) != 0 )) ; then
112
112
# File extension filtering
113
- local fullFilter filter filteringCmd
113
+ local fullFilter= " " filter filteringCmd
114
114
115
115
# Do not use quotes around the $completions variable or else newline
116
116
# characters will be kept.
@@ -141,20 +141,71 @@ __podman_process_completion_results() {
141
141
__podman_handle_special_char " $cur " =
142
142
143
143
# Print the activeHelp statements before we finish
144
+ __podman_handle_activeHelp
145
+ }
146
+
147
+ __podman_handle_activeHelp () {
148
+ # Print the activeHelp statements
144
149
if (( ${# activeHelp[*]} != 0 )) ; then
145
- printf " \n" ;
146
- printf " %s\n" " ${activeHelp[@]} "
147
- printf " \n"
148
-
149
- # The prompt format is only available from bash 4.4.
150
- # We test if it is available before using it.
151
- if (x=${PS1@ P} ) 2> /dev/null; then
152
- printf " %s" " ${PS1@ P}${COMP_LINE[@]} "
153
- else
154
- # Can't print the prompt. Just print the
155
- # text the user had typed, it is workable enough.
156
- printf " %s" " ${COMP_LINE[@]} "
150
+ if [ -z $COMP_TYPE ]; then
151
+ # Bash v3 does not set the COMP_TYPE variable.
152
+ printf " \n" ;
153
+ printf " %s\n" " ${activeHelp[@]} "
154
+ printf " \n"
155
+ __podman_reprint_commandLine
156
+ return
157
157
fi
158
+
159
+ # Only print ActiveHelp on the second TAB press
160
+ if [ $COMP_TYPE -eq 63 ]; then
161
+ printf " \n"
162
+ printf " %s\n" " ${activeHelp[@]} "
163
+
164
+ if (( ${# COMPREPLY[*]} == 0 )) ; then
165
+ # When there are no completion choices from the program, file completion
166
+ # may kick in if the program has not disabled it; in such a case, we want
167
+ # to know if any files will match what the user typed, so that we know if
168
+ # there will be completions presented, so that we know how to handle ActiveHelp.
169
+ # To find out, we actually trigger the file completion ourselves;
170
+ # the call to _filedir will fill COMPREPLY if files match.
171
+ if (( (directive & shellCompDirectiveNoFileComp) == 0 )) ; then
172
+ __podman_debug " Listing files"
173
+ _filedir
174
+ fi
175
+ fi
176
+
177
+ if (( ${# COMPREPLY[*]} != 0 )) ; then
178
+ # If there are completion choices to be shown, print a delimiter.
179
+ # Re-printing the command-line will automatically be done
180
+ # by the shell when it prints the completion choices.
181
+ printf -- " --"
182
+ else
183
+ # When there are no completion choices at all, we need
184
+ # to re-print the command-line since the shell will
185
+ # not be doing it itself.
186
+ __podman_reprint_commandLine
187
+ fi
188
+ elif [ $COMP_TYPE -eq 37 ] || [ $COMP_TYPE -eq 42 ]; then
189
+ # For completion type: menu-complete/menu-complete-backward and insert-completions
190
+ # the completions are immediately inserted into the command-line, so we first
191
+ # print the activeHelp message and reprint the command-line since the shell won't.
192
+ printf " \n"
193
+ printf " %s\n" " ${activeHelp[@]} "
194
+
195
+ __podman_reprint_commandLine
196
+ fi
197
+ fi
198
+ }
199
+
200
+ __podman_reprint_commandLine () {
201
+ # The prompt format is only available from bash 4.4.
202
+ # We test if it is available before using it.
203
+ if (x=${PS1@ P} ) 2> /dev/null; then
204
+ printf " %s" " ${PS1@ P}${COMP_LINE[@]} "
205
+ else
206
+ # Can't print the prompt. Just print the
207
+ # text the user had typed, it is workable enough.
208
+ printf " %s" " ${COMP_LINE[@]} "
158
209
fi
159
210
}
160
211
@@ -165,6 +216,8 @@ __podman_extract_activeHelp() {
165
216
local endIndex=${# activeHelpMarker}
166
217
167
218
while IFS=' ' read -r comp; do
219
+ [[ -z $comp ]] && continue
220
+
168
221
if [[ ${comp: 0: endIndex} == $activeHelpMarker ]]; then
169
222
comp=${comp: endIndex}
170
223
__podman_debug " ActiveHelp found: $comp "
@@ -187,16 +240,21 @@ __podman_handle_completion_types() {
187
240
# If the user requested inserting one completion at a time, or all
188
241
# completions at once on the command-line we must remove the descriptions.
189
242
# https://github.com/spf13/cobra/issues/1508
190
- local tab=$' \t ' comp
191
- while IFS=' ' read -r comp; do
192
- [[ -z $comp ]] && continue
193
- # Strip any description
194
- comp=${comp%% $tab * }
195
- # Only consider the completions that match
196
- if [[ $comp == " $cur " * ]]; then
197
- COMPREPLY+=(" $comp " )
198
- fi
199
- done < <( printf " %s\n" " ${completions[@]} " )
243
+
244
+ # If there are no completions, we don't need to do anything
245
+ (( ${# completions[@]} == 0 )) && return 0
246
+
247
+ local tab=$' \t '
248
+
249
+ # Strip any description and escape the completion to handled special characters
250
+ IFS=$' \n ' read -ra completions -d ' ' < <( printf " %q\n" " ${completions[@]%% $tab * } " )
251
+
252
+ # Only consider the completions that match
253
+ IFS=$' \n ' read -ra COMPREPLY -d ' ' < <( IFS=$' \n ' ; compgen -W " ${completions[*]} " -- " ${cur} " )
254
+
255
+ # compgen looses the escaping so we need to escape all completions again since they will
256
+ # all be inserted on the command-line.
257
+ IFS=$' \n ' read -ra COMPREPLY -d ' ' < <( printf " %q\n" " ${COMPREPLY[@]} " )
200
258
;;
201
259
202
260
* )
@@ -207,11 +265,25 @@ __podman_handle_completion_types() {
207
265
}
208
266
209
267
__podman_handle_standard_completion_case () {
210
- local tab=$' \t ' comp
268
+ local tab=$' \t '
269
+
270
+ # If there are no completions, we don't need to do anything
271
+ (( ${# completions[@]} == 0 )) && return 0
211
272
212
273
# Short circuit to optimize if we don't have descriptions
213
274
if [[ " ${completions[*]} " != * $tab * ]]; then
214
- IFS=$' \n ' read -ra COMPREPLY -d ' ' < <( compgen -W " ${completions[*]} " -- " $cur " )
275
+ # First, escape the completions to handle special characters
276
+ IFS=$' \n ' read -ra completions -d ' ' < <( printf " %q\n" " ${completions[@]} " )
277
+ # Only consider the completions that match what the user typed
278
+ IFS=$' \n ' read -ra COMPREPLY -d ' ' < <( IFS=$' \n ' ; compgen -W " ${completions[*]} " -- " ${cur} " )
279
+
280
+ # compgen looses the escaping so, if there is only a single completion, we need to
281
+ # escape it again because it will be inserted on the command-line. If there are multiple
282
+ # completions, we don't want to escape them because they will be printed in a list
283
+ # and we don't want to show escape characters in that list.
284
+ if (( ${# COMPREPLY[@]} == 1 )) ; then
285
+ COMPREPLY[0]=$( printf " %q" " ${COMPREPLY[0]} " )
286
+ fi
215
287
return 0
216
288
fi
217
289
@@ -220,23 +292,39 @@ __podman_handle_standard_completion_case() {
220
292
# Look for the longest completion so that we can format things nicely
221
293
while IFS=' ' read -r compline; do
222
294
[[ -z $compline ]] && continue
223
- # Strip any description before checking the length
224
- comp=${compline%% $tab * }
295
+
296
+ # Before checking if the completion matches what the user typed,
297
+ # we need to strip any description and escape the completion to handle special
298
+ # characters because those escape characters are part of what the user typed.
299
+ # Don't call "printf" in a sub-shell because it will be much slower
300
+ # since we are in a loop.
301
+ printf -v comp " %q" " ${compline%% $tab * } " & > /dev/null || comp=$( printf " %q" " ${compline%% $tab * } " )
302
+
225
303
# Only consider the completions that match
226
304
[[ $comp == " $cur " * ]] || continue
305
+
306
+ # The completions matches. Add it to the list of full completions including
307
+ # its description. We don't escape the completion because it may get printed
308
+ # in a list if there are more than one and we don't want show escape characters
309
+ # in that list.
227
310
COMPREPLY+=(" $compline " )
311
+
312
+ # Strip any description before checking the length, and again, don't escape
313
+ # the completion because this length is only used when printing the completions
314
+ # in a list and we don't want show escape characters in that list.
315
+ comp=${compline%% $tab * }
228
316
if (( ${# comp} > longest)) ; then
229
317
longest=${# comp}
230
318
fi
231
319
done < <( printf " %s\n" " ${completions[@]} " )
232
320
233
- # If there is a single completion left, remove the description text
321
+ # If there is a single completion left, remove the description text and escape any special characters
234
322
if (( ${# COMPREPLY[*]} == 1 )) ; then
235
323
__podman_debug " COMPREPLY[0]: ${COMPREPLY[0]} "
236
- comp= " ${COMPREPLY[0]%% $tab * } "
237
- __podman_debug " Removed description from single completion, which is now: ${comp } "
238
- COMPREPLY[0]= $comp
239
- else # Format the descriptions
324
+ COMPREPLY[0]= $( printf " %q " " ${COMPREPLY[0]%% $tab * } " )
325
+ __podman_debug " Removed description from single completion, which is now: ${COMPREPLY[0] } "
326
+ else
327
+ # Format the descriptions
240
328
__podman_format_comp_descriptions $longest
241
329
fi
242
330
}
0 commit comments