From 84da70a0f36e7d6fc87919ca4a69b20bc9d43f72 Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Thu, 1 Jul 2021 20:01:44 +0200 Subject: update shell completion scripts The new cobra v1.2.0 release brings a number of bug fixes for shell completion scripts. Regenerate the scripts with `make completions` to sync them with the upstream version, currently we have some custom ones to avoid some upstream bugs. Because the new cobra version has all fixes we should use the upstream scripts. Add a check to CI to ensure we always use the up to date scripts. [NO TESTS NEEDED] Signed-off-by: Paul Holzinger --- completions/bash/podman | 192 +++++++++++++++---------------- completions/bash/podman-remote | 192 +++++++++++++++---------------- completions/fish/podman-remote.fish | 114 +++++++++--------- completions/fish/podman.fish | 114 +++++++++--------- completions/powershell/podman-remote.ps1 | 30 ++--- completions/powershell/podman.ps1 | 30 ++--- completions/zsh/_podman | 2 - completions/zsh/_podman-remote | 2 - 8 files changed, 336 insertions(+), 340 deletions(-) (limited to 'completions') diff --git a/completions/bash/podman b/completions/bash/podman index 17d1e86b7..dcac09db5 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -1,38 +1,29 @@ -# bash completion for podman -*- shell-script -*- +# bash completion V2 for podman -*- shell-script -*- __podman_debug() { - if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then + if [[ -n ${BASH_COMP_DEBUG_FILE:-} ]]; then echo "$*" >> "${BASH_COMP_DEBUG_FILE}" fi } -__podman_perform_completion() +# Macs have bash3 for which the bash-completion package doesn't include +# _init_completion. This is a minimal version of that function. +__podman_init_completion() { - __podman_debug - __podman_debug "========= starting completion logic ==========" - __podman_debug "cur is ${cur}, words[*] is ${words[*]}, #words[@] is ${#words[@]}, cword is $cword" - - # The user could have moved the cursor backwards on the command-line. - # We need to trigger completion from the $cword location, so we need - # to truncate the command-line ($words) up to the $cword location. - words=("${words[@]:0:$cword+1}") - __podman_debug "Truncated words[*]: ${words[*]}," - - local shellCompDirectiveError=1 - local shellCompDirectiveNoSpace=2 - local shellCompDirectiveNoFileComp=4 - local shellCompDirectiveFilterFileExt=8 - local shellCompDirectiveFilterDirs=16 - local shellCompDirectiveLegacyCustomComp=32 - local shellCompDirectiveLegacyCustomArgsComp=64 + COMPREPLY=() + _get_comp_words_by_ref "$@" cur prev words cword +} - local out requestComp lastParam lastChar comp directive args flagPrefix +# This function calls the podman program to obtain the completion +# results and the directive. It fills the 'out' and 'directive' vars. +__podman_get_completion_results() { + local requestComp lastParam lastChar args # Prepare the command to request completions for the program. # Calling ${words[0]} instead of directly podman allows to handle aliases args=("${words[@]:1}") - requestComp="${words[0]} __completeNoDesc ${args[*]}" + requestComp="${words[0]} __complete ${args[*]}" lastParam=${words[$((${#words[@]}-1))]} lastChar=${lastParam:$((${#lastParam}-1)):1} @@ -42,14 +33,13 @@ __podman_perform_completion() # If the last parameter is complete (there is a space following it) # We add an extra empty parameter so we can indicate this to the go method. __podman_debug "Adding extra empty parameter" - requestComp="${requestComp} \"\"" + requestComp="${requestComp} ''" fi # When completing a flag with an = (e.g., podman -n=) # bash focuses on the part after the =, so we need to remove # the flag part from $cur if [[ "${cur}" == -*=* ]]; then - flagPrefix="${cur%%=*}=" cur="${cur#*=}" fi @@ -67,6 +57,14 @@ __podman_perform_completion() fi __podman_debug "The completion directive is: ${directive}" __podman_debug "The completions are: ${out[*]}" +} + +__podman_process_completion_results() { + local shellCompDirectiveError=1 + local shellCompDirectiveNoSpace=2 + local shellCompDirectiveNoFileComp=4 + local shellCompDirectiveFilterFileExt=8 + local shellCompDirectiveFilterDirs=16 if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then # Error code. No completion. @@ -77,12 +75,16 @@ __podman_perform_completion() if [[ $(type -t compopt) = "builtin" ]]; then __podman_debug "Activating no space" compopt -o nospace + else + __podman_debug "No space directive not supported in this version of bash" fi fi if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then if [[ $(type -t compopt) = "builtin" ]]; then __podman_debug "Activating no file completion" compopt +o default + else + __podman_debug "No file completion directive not supported in this version of bash" fi fi fi @@ -113,87 +115,56 @@ __podman_perform_completion() __podman_debug "Listing directories in ." _filedir -d fi - elif [ $((directive & shellCompDirectiveLegacyCustomComp)) -ne 0 ]; then - local cmd - __podman_debug "Legacy custom completion. Directive: $directive, cmds: ${out[*]}" - - # The following variables should get their value through the commands - # we have received as completions and are parsing below. - local last_command - local nouns - - # Execute every command received - while IFS='' read -r cmd; do - __podman_debug "About to execute: $cmd" - eval "$cmd" - done < <(printf "%s\n" "${out[@]}") - - __podman_debug "last_command: $last_command" - __podman_debug "nouns[0]: ${nouns[0]}, nouns[1]: ${nouns[1]}" - - if [ $((directive & shellCompDirectiveLegacyCustomArgsComp)) -ne 0 ]; then - # We should call the global legacy custom completion function, if it is defined - if declare -F __podman_custom_func >/dev/null; then - # Use command name qualified legacy custom func - __podman_debug "About to call: __podman_custom_func" - __podman_custom_func - elif declare -F __custom_func >/dev/null; then - # Otherwise fall back to unqualified legacy custom func for compatibility - __podman_debug "About to call: __custom_func" - __custom_func - fi - fi else - local tab - tab=$(printf '\t') - local longest=0 - # Look for the longest completion so that we can format things nicely - while IFS='' read -r comp; do - comp=${comp%%$tab*} - if ((${#comp}>longest)); then - longest=${#comp} - fi - done < <(printf "%s\n" "${out[@]}") - - local completions=() - while IFS='' read -r comp; do - if [ -z "$comp" ]; then - continue - fi - - __podman_debug "Original comp: $comp" - comp="$(__podman_format_comp_descriptions "$comp" "$longest")" - __podman_debug "Final comp: $comp" - completions+=("$comp") - done < <(printf "%s\n" "${out[@]}") - - while IFS='' read -r comp; do - # Although this script should only be used for bash - # there may be programs that still convert the bash - # script into a zsh one. To continue supporting those - # programs, we do this single adaptation for zsh - if [ -n "${ZSH_VERSION}" ]; then - # zsh completion needs --flag= prefix - COMPREPLY+=("$flagPrefix$comp") - else - COMPREPLY+=("$comp") - fi - done < <(compgen -W "${completions[*]}" -- "$cur") - - # If there is a single completion left, remove the description text - if [ ${#COMPREPLY[*]} -eq 1 ]; then - __podman_debug "COMPREPLY[0]: ${COMPREPLY[0]}" - comp="${COMPREPLY[0]%% *}" - __podman_debug "Removed description from single completion, which is now: ${comp}" - COMPREPLY=() - COMPREPLY+=("$comp") - fi + __podman_handle_standard_completion_case fi __podman_handle_special_char "$cur" : __podman_handle_special_char "$cur" = } +__podman_handle_standard_completion_case() { + local tab comp + tab=$(printf '\t') + + local longest=0 + # Look for the longest completion so that we can format things nicely + while IFS='' read -r comp; do + # Strip any description before checking the length + comp=${comp%%$tab*} + # Only consider the completions that match + comp=$(compgen -W "$comp" -- "$cur") + if ((${#comp}>longest)); then + longest=${#comp} + fi + done < <(printf "%s\n" "${out[@]}") + + local completions=() + while IFS='' read -r comp; do + if [ -z "$comp" ]; then + continue + fi + + __podman_debug "Original comp: $comp" + comp="$(__podman_format_comp_descriptions "$comp" "$longest")" + __podman_debug "Final comp: $comp" + completions+=("$comp") + done < <(printf "%s\n" "${out[@]}") + + while IFS='' read -r comp; do + COMPREPLY+=("$comp") + done < <(compgen -W "${completions[*]}" -- "$cur") + + # If there is a single completion left, remove the description text + if [ ${#COMPREPLY[*]} -eq 1 ]; then + __podman_debug "COMPREPLY[0]: ${COMPREPLY[0]}" + comp="${COMPREPLY[0]%% *}" + __podman_debug "Removed description from single completion, which is now: ${comp}" + COMPREPLY=() + COMPREPLY+=("$comp") + fi +} + __podman_handle_special_char() { local comp="$1" @@ -252,12 +223,31 @@ __podman_format_comp_descriptions() __start_podman() { - local cur prev words cword + local cur prev words cword split COMPREPLY=() - _get_comp_words_by_ref -n "=:" cur prev words cword - __podman_perform_completion + # Call _init_completion from the bash-completion package + # to prepare the arguments properly + if declare -F _init_completion >/dev/null 2>&1; then + _init_completion -n "=:" || return + else + __podman_init_completion -n "=:" || return + fi + + __podman_debug + __podman_debug "========= starting completion logic ==========" + __podman_debug "cur is ${cur}, words[*] is ${words[*]}, #words[@] is ${#words[@]}, cword is $cword" + + # The user could have moved the cursor backwards on the command-line. + # We need to trigger completion from the $cword location, so we need + # to truncate the command-line ($words) up to the $cword location. + words=("${words[@]:0:$cword+1}") + __podman_debug "Truncated words[*]: ${words[*]}," + + local out directive + __podman_get_completion_results + __podman_process_completion_results } if [[ $(type -t compopt) = "builtin" ]]; then diff --git a/completions/bash/podman-remote b/completions/bash/podman-remote index 43a5ce959..7bd10abb2 100644 --- a/completions/bash/podman-remote +++ b/completions/bash/podman-remote @@ -1,38 +1,29 @@ -# bash completion for podman-remote -*- shell-script -*- +# bash completion V2 for podman-remote -*- shell-script -*- __podman-remote_debug() { - if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then + if [[ -n ${BASH_COMP_DEBUG_FILE:-} ]]; then echo "$*" >> "${BASH_COMP_DEBUG_FILE}" fi } -__podman-remote_perform_completion() +# Macs have bash3 for which the bash-completion package doesn't include +# _init_completion. This is a minimal version of that function. +__podman-remote_init_completion() { - __podman-remote_debug - __podman-remote_debug "========= starting completion logic ==========" - __podman-remote_debug "cur is ${cur}, words[*] is ${words[*]}, #words[@] is ${#words[@]}, cword is $cword" - - # The user could have moved the cursor backwards on the command-line. - # We need to trigger completion from the $cword location, so we need - # to truncate the command-line ($words) up to the $cword location. - words=("${words[@]:0:$cword+1}") - __podman-remote_debug "Truncated words[*]: ${words[*]}," - - local shellCompDirectiveError=1 - local shellCompDirectiveNoSpace=2 - local shellCompDirectiveNoFileComp=4 - local shellCompDirectiveFilterFileExt=8 - local shellCompDirectiveFilterDirs=16 - local shellCompDirectiveLegacyCustomComp=32 - local shellCompDirectiveLegacyCustomArgsComp=64 + COMPREPLY=() + _get_comp_words_by_ref "$@" cur prev words cword +} - local out requestComp lastParam lastChar comp directive args flagPrefix +# This function calls the podman-remote program to obtain the completion +# results and the directive. It fills the 'out' and 'directive' vars. +__podman-remote_get_completion_results() { + local requestComp lastParam lastChar args # Prepare the command to request completions for the program. # Calling ${words[0]} instead of directly podman-remote allows to handle aliases args=("${words[@]:1}") - requestComp="${words[0]} __completeNoDesc ${args[*]}" + requestComp="${words[0]} __complete ${args[*]}" lastParam=${words[$((${#words[@]}-1))]} lastChar=${lastParam:$((${#lastParam}-1)):1} @@ -42,14 +33,13 @@ __podman-remote_perform_completion() # If the last parameter is complete (there is a space following it) # We add an extra empty parameter so we can indicate this to the go method. __podman-remote_debug "Adding extra empty parameter" - requestComp="${requestComp} \"\"" + requestComp="${requestComp} ''" fi # When completing a flag with an = (e.g., podman-remote -n=) # bash focuses on the part after the =, so we need to remove # the flag part from $cur if [[ "${cur}" == -*=* ]]; then - flagPrefix="${cur%%=*}=" cur="${cur#*=}" fi @@ -67,6 +57,14 @@ __podman-remote_perform_completion() fi __podman-remote_debug "The completion directive is: ${directive}" __podman-remote_debug "The completions are: ${out[*]}" +} + +__podman-remote_process_completion_results() { + local shellCompDirectiveError=1 + local shellCompDirectiveNoSpace=2 + local shellCompDirectiveNoFileComp=4 + local shellCompDirectiveFilterFileExt=8 + local shellCompDirectiveFilterDirs=16 if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then # Error code. No completion. @@ -77,12 +75,16 @@ __podman-remote_perform_completion() if [[ $(type -t compopt) = "builtin" ]]; then __podman-remote_debug "Activating no space" compopt -o nospace + else + __podman-remote_debug "No space directive not supported in this version of bash" fi fi if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then if [[ $(type -t compopt) = "builtin" ]]; then __podman-remote_debug "Activating no file completion" compopt +o default + else + __podman-remote_debug "No file completion directive not supported in this version of bash" fi fi fi @@ -113,87 +115,56 @@ __podman-remote_perform_completion() __podman-remote_debug "Listing directories in ." _filedir -d fi - elif [ $((directive & shellCompDirectiveLegacyCustomComp)) -ne 0 ]; then - local cmd - __podman-remote_debug "Legacy custom completion. Directive: $directive, cmds: ${out[*]}" - - # The following variables should get their value through the commands - # we have received as completions and are parsing below. - local last_command - local nouns - - # Execute every command received - while IFS='' read -r cmd; do - __podman-remote_debug "About to execute: $cmd" - eval "$cmd" - done < <(printf "%s\n" "${out[@]}") - - __podman-remote_debug "last_command: $last_command" - __podman-remote_debug "nouns[0]: ${nouns[0]}, nouns[1]: ${nouns[1]}" - - if [ $((directive & shellCompDirectiveLegacyCustomArgsComp)) -ne 0 ]; then - # We should call the global legacy custom completion function, if it is defined - if declare -F __podman-remote_custom_func >/dev/null; then - # Use command name qualified legacy custom func - __podman-remote_debug "About to call: __podman-remote_custom_func" - __podman-remote_custom_func - elif declare -F __custom_func >/dev/null; then - # Otherwise fall back to unqualified legacy custom func for compatibility - __podman-remote_debug "About to call: __custom_func" - __custom_func - fi - fi else - local tab - tab=$(printf '\t') - local longest=0 - # Look for the longest completion so that we can format things nicely - while IFS='' read -r comp; do - comp=${comp%%$tab*} - if ((${#comp}>longest)); then - longest=${#comp} - fi - done < <(printf "%s\n" "${out[@]}") - - local completions=() - while IFS='' read -r comp; do - if [ -z "$comp" ]; then - continue - fi - - __podman-remote_debug "Original comp: $comp" - comp="$(__podman-remote_format_comp_descriptions "$comp" "$longest")" - __podman-remote_debug "Final comp: $comp" - completions+=("$comp") - done < <(printf "%s\n" "${out[@]}") - - while IFS='' read -r comp; do - # Although this script should only be used for bash - # there may be programs that still convert the bash - # script into a zsh one. To continue supporting those - # programs, we do this single adaptation for zsh - if [ -n "${ZSH_VERSION}" ]; then - # zsh completion needs --flag= prefix - COMPREPLY+=("$flagPrefix$comp") - else - COMPREPLY+=("$comp") - fi - done < <(compgen -W "${completions[*]}" -- "$cur") - - # If there is a single completion left, remove the description text - if [ ${#COMPREPLY[*]} -eq 1 ]; then - __podman-remote_debug "COMPREPLY[0]: ${COMPREPLY[0]}" - comp="${COMPREPLY[0]%% *}" - __podman-remote_debug "Removed description from single completion, which is now: ${comp}" - COMPREPLY=() - COMPREPLY+=("$comp") - fi + __podman-remote_handle_standard_completion_case fi __podman-remote_handle_special_char "$cur" : __podman-remote_handle_special_char "$cur" = } +__podman-remote_handle_standard_completion_case() { + local tab comp + tab=$(printf '\t') + + local longest=0 + # Look for the longest completion so that we can format things nicely + while IFS='' read -r comp; do + # Strip any description before checking the length + comp=${comp%%$tab*} + # Only consider the completions that match + comp=$(compgen -W "$comp" -- "$cur") + if ((${#comp}>longest)); then + longest=${#comp} + fi + done < <(printf "%s\n" "${out[@]}") + + local completions=() + while IFS='' read -r comp; do + if [ -z "$comp" ]; then + continue + fi + + __podman-remote_debug "Original comp: $comp" + comp="$(__podman-remote_format_comp_descriptions "$comp" "$longest")" + __podman-remote_debug "Final comp: $comp" + completions+=("$comp") + done < <(printf "%s\n" "${out[@]}") + + while IFS='' read -r comp; do + COMPREPLY+=("$comp") + done < <(compgen -W "${completions[*]}" -- "$cur") + + # If there is a single completion left, remove the description text + if [ ${#COMPREPLY[*]} -eq 1 ]; then + __podman-remote_debug "COMPREPLY[0]: ${COMPREPLY[0]}" + comp="${COMPREPLY[0]%% *}" + __podman-remote_debug "Removed description from single completion, which is now: ${comp}" + COMPREPLY=() + COMPREPLY+=("$comp") + fi +} + __podman-remote_handle_special_char() { local comp="$1" @@ -252,12 +223,31 @@ __podman-remote_format_comp_descriptions() __start_podman-remote() { - local cur prev words cword + local cur prev words cword split COMPREPLY=() - _get_comp_words_by_ref -n "=:" cur prev words cword - __podman-remote_perform_completion + # Call _init_completion from the bash-completion package + # to prepare the arguments properly + if declare -F _init_completion >/dev/null 2>&1; then + _init_completion -n "=:" || return + else + __podman-remote_init_completion -n "=:" || return + fi + + __podman-remote_debug + __podman-remote_debug "========= starting completion logic ==========" + __podman-remote_debug "cur is ${cur}, words[*] is ${words[*]}, #words[@] is ${#words[@]}, cword is $cword" + + # The user could have moved the cursor backwards on the command-line. + # We need to trigger completion from the $cword location, so we need + # to truncate the command-line ($words) up to the $cword location. + words=("${words[@]:0:$cword+1}") + __podman-remote_debug "Truncated words[*]: ${words[*]}," + + local out directive + __podman-remote_get_completion_results + __podman-remote_process_completion_results } if [[ $(type -t compopt) = "builtin" ]]; then diff --git a/completions/fish/podman-remote.fish b/completions/fish/podman-remote.fish index b3a4a173a..bcfacbb00 100644 --- a/completions/fish/podman-remote.fish +++ b/completions/fish/podman-remote.fish @@ -1,7 +1,7 @@ # fish completion for podman-remote -*- shell-script -*- function __podman_remote_debug - set file "$BASH_COMP_DEBUG_FILE" + set -l file "$BASH_COMP_DEBUG_FILE" if test -n "$file" echo "$argv" >> $file end @@ -10,32 +10,38 @@ end function __podman_remote_perform_completion __podman_remote_debug "Starting __podman_remote_perform_completion" - set args (string split -- " " (string trim -l (commandline -c))) - set lastArg "$args[-1]" + # Extract all args except the last one + set -l args (commandline -opc) + # Extract the last arg and escape it in case it is a space + set -l lastArg (string escape -- (commandline -ct)) __podman_remote_debug "args: $args" __podman_remote_debug "last arg: $lastArg" - set emptyArg "" - if test -z "$lastArg" - __podman_remote_debug "Setting emptyArg" - set emptyArg \"\" - end - __podman_remote_debug "emptyArg: $emptyArg" + set -l requestComp "$args[1] __complete $args[2..-1] $lastArg" - set requestComp "$args[1] __complete $args[2..-1] $emptyArg" __podman_remote_debug "Calling $requestComp" + set -l results (eval $requestComp 2> /dev/null) + + # Some programs may output extra empty lines after the directive. + # Let's ignore them or else it will break completion. + # Ref: https://github.com/spf13/cobra/issues/1279 + for line in $results[-1..1] + if test (string trim -- $line) = "" + # Found an empty line, remove it + set results $results[1..-2] + else + # Found non-empty line, we have our proper output + break + end + end - # Call the command as a sub-shell so that we can redirect any errors - # For example, if $requestComp has an unmatched quote - # https://github.com/spf13/cobra/issues/1214 - set results (fish -c "$requestComp" 2> /dev/null) - set comps $results[1..-2] - set directiveLine $results[-1] + set -l comps $results[1..-2] + set -l directiveLine $results[-1] # For Fish, when completing a flag with an = (e.g., -n=) # completions must be prefixed with the flag - set flagPrefix (string match -r -- '-.*=' "$lastArg") + set -l flagPrefix (string match -r -- '-.*=' "$lastArg") __podman_remote_debug "Comps: $comps" __podman_remote_debug "DirectiveLine: $directiveLine" @@ -58,7 +64,7 @@ function __podman_remote_prepare_completions # Start fresh set --erase __podman_remote_comp_results - set results (__podman_remote_perform_completion) + set -l results (__podman_remote_perform_completion) __podman_remote_debug "Completion results: $results" if test -z "$results" @@ -67,39 +73,39 @@ function __podman_remote_prepare_completions return 1 end - set directive (string sub --start 2 $results[-1]) + set -l directive (string sub --start 2 $results[-1]) set --global __podman_remote_comp_results $results[1..-2] __podman_remote_debug "Completions are: $__podman_remote_comp_results" __podman_remote_debug "Directive is: $directive" - set shellCompDirectiveError 1 - set shellCompDirectiveNoSpace 2 - set shellCompDirectiveNoFileComp 4 - set shellCompDirectiveFilterFileExt 8 - set shellCompDirectiveFilterDirs 16 + set -l shellCompDirectiveError 1 + set -l shellCompDirectiveNoSpace 2 + set -l shellCompDirectiveNoFileComp 4 + set -l shellCompDirectiveFilterFileExt 8 + set -l shellCompDirectiveFilterDirs 16 if test -z "$directive" set directive 0 end - set compErr (math (math --scale 0 $directive / $shellCompDirectiveError) % 2) + set -l compErr (math (math --scale 0 $directive / $shellCompDirectiveError) % 2) if test $compErr -eq 1 __podman_remote_debug "Received error directive: aborting." # Might as well do file completion, in case it helps return 1 end - set filefilter (math (math --scale 0 $directive / $shellCompDirectiveFilterFileExt) % 2) - set dirfilter (math (math --scale 0 $directive / $shellCompDirectiveFilterDirs) % 2) + set -l filefilter (math (math --scale 0 $directive / $shellCompDirectiveFilterFileExt) % 2) + set -l dirfilter (math (math --scale 0 $directive / $shellCompDirectiveFilterDirs) % 2) if test $filefilter -eq 1; or test $dirfilter -eq 1 __podman_remote_debug "File extension filtering or directory filtering not supported" # Do full file completion instead return 1 end - set nospace (math (math --scale 0 $directive / $shellCompDirectiveNoSpace) % 2) - set nofiles (math (math --scale 0 $directive / $shellCompDirectiveNoFileComp) % 2) + set -l nospace (math (math --scale 0 $directive / $shellCompDirectiveNoSpace) % 2) + set -l nofiles (math (math --scale 0 $directive / $shellCompDirectiveNoFileComp) % 2) __podman_remote_debug "nospace: $nospace, nofiles: $nofiles" @@ -109,34 +115,34 @@ function __podman_remote_prepare_completions # may not already be filtered so as to allow fish to match on different # criteria than the prefix. if test $nospace -ne 0; or test $nofiles -eq 0 - set prefix (commandline -t) + set -l prefix (commandline -t | string escape --style=regex) __podman_remote_debug "prefix: $prefix" - set completions - for comp in $__podman_remote_comp_results - if test (string match -e -r -- "^$prefix" "$comp") - set -a completions $comp - end - end + set -l completions (string match -r -- "^$prefix.*" $__podman_remote_comp_results) set --global __podman_remote_comp_results $completions __podman_remote_debug "Filtered completions are: $__podman_remote_comp_results" # Important not to quote the variable for count to work - set numComps (count $__podman_remote_comp_results) + set -l numComps (count $__podman_remote_comp_results) __podman_remote_debug "numComps: $numComps" if test $numComps -eq 1; and test $nospace -ne 0 - # To support the "nospace" directive we trick the shell - # by outputting an extra, longer completion. - # We must first split on \t to get rid of the descriptions because - # the extra character we add to the fake second completion must be - # before the description. We don't need descriptions anyway since - # there is only a single real completion which the shell will expand - # immediately. - __podman_remote_debug "Adding second completion to perform nospace directive" - set split (string split --max 1 \t $__podman_remote_comp_results[1]) - set --global __podman_remote_comp_results $split[1] $split[1]. - __podman_remote_debug "Completions are now: $__podman_remote_comp_results" + # We must first split on \t to get rid of the descriptions to be + # able to check what the actual completion will be. + # We don't need descriptions anyway since there is only a single + # real completion which the shell will expand immediately. + set -l split (string split --max 1 \t $__podman_remote_comp_results[1]) + + # Fish won't add a space if the completion ends with any + # of the following characters: @=/:., + set -l lastChar (string sub -s -1 -- $split) + if not string match -r -q "[@=/:.,]" -- "$lastChar" + # In other cases, to support the "nospace" directive we trick the shell + # by outputting an extra, longer completion. + __podman_remote_debug "Adding second completion to perform nospace directive" + set --global __podman_remote_comp_results $split[1] $split[1]. + __podman_remote_debug "Completions are now: $__podman_remote_comp_results" + end end if test $numComps -eq 0; and test $nofiles -eq 0 @@ -152,10 +158,14 @@ end # Since Fish completions are only loaded once the user triggers them, we trigger them ourselves # so we can properly delete any completions provided by another script. -# The space after the program name is essential to trigger completion for the program -# and not completion of the program name itself. -complete --do-complete "podman-remote " > /dev/null 2>&1 -# Using '> /dev/null 2>&1' since '&>' is not supported in older versions of fish. +# Only do this if the program can be found, or else fish may print some errors; besides, +# the existing completions will only be loaded if the program can be found. +if type -q "podman-remote" + # The space after the program name is essential to trigger completion for the program + # and not completion of the program name itself. + # Also, we use '> /dev/null 2>&1' since '&>' is not supported in older versions of fish. + complete --do-complete "podman-remote " > /dev/null 2>&1 +end # Remove any pre-existing completions for the program since we will be handling all of them. complete -c podman-remote -e diff --git a/completions/fish/podman.fish b/completions/fish/podman.fish index 05dd2d72b..6394535a9 100644 --- a/completions/fish/podman.fish +++ b/completions/fish/podman.fish @@ -1,7 +1,7 @@ # fish completion for podman -*- shell-script -*- function __podman_debug - set file "$BASH_COMP_DEBUG_FILE" + set -l file "$BASH_COMP_DEBUG_FILE" if test -n "$file" echo "$argv" >> $file end @@ -10,32 +10,38 @@ end function __podman_perform_completion __podman_debug "Starting __podman_perform_completion" - set args (string split -- " " (string trim -l (commandline -c))) - set lastArg "$args[-1]" + # Extract all args except the last one + set -l args (commandline -opc) + # Extract the last arg and escape it in case it is a space + set -l lastArg (string escape -- (commandline -ct)) __podman_debug "args: $args" __podman_debug "last arg: $lastArg" - set emptyArg "" - if test -z "$lastArg" - __podman_debug "Setting emptyArg" - set emptyArg \"\" - end - __podman_debug "emptyArg: $emptyArg" + set -l requestComp "$args[1] __complete $args[2..-1] $lastArg" - set requestComp "$args[1] __complete $args[2..-1] $emptyArg" __podman_debug "Calling $requestComp" + set -l results (eval $requestComp 2> /dev/null) + + # Some programs may output extra empty lines after the directive. + # Let's ignore them or else it will break completion. + # Ref: https://github.com/spf13/cobra/issues/1279 + for line in $results[-1..1] + if test (string trim -- $line) = "" + # Found an empty line, remove it + set results $results[1..-2] + else + # Found non-empty line, we have our proper output + break + end + end - # Call the command as a sub-shell so that we can redirect any errors - # For example, if $requestComp has an unmatched quote - # https://github.com/spf13/cobra/issues/1214 - set results (fish -c "$requestComp" 2> /dev/null) - set comps $results[1..-2] - set directiveLine $results[-1] + set -l comps $results[1..-2] + set -l directiveLine $results[-1] # For Fish, when completing a flag with an = (e.g., -n=) # completions must be prefixed with the flag - set flagPrefix (string match -r -- '-.*=' "$lastArg") + set -l flagPrefix (string match -r -- '-.*=' "$lastArg") __podman_debug "Comps: $comps" __podman_debug "DirectiveLine: $directiveLine" @@ -58,7 +64,7 @@ function __podman_prepare_completions # Start fresh set --erase __podman_comp_results - set results (__podman_perform_completion) + set -l results (__podman_perform_completion) __podman_debug "Completion results: $results" if test -z "$results" @@ -67,39 +73,39 @@ function __podman_prepare_completions return 1 end - set directive (string sub --start 2 $results[-1]) + set -l directive (string sub --start 2 $results[-1]) set --global __podman_comp_results $results[1..-2] __podman_debug "Completions are: $__podman_comp_results" __podman_debug "Directive is: $directive" - set shellCompDirectiveError 1 - set shellCompDirectiveNoSpace 2 - set shellCompDirectiveNoFileComp 4 - set shellCompDirectiveFilterFileExt 8 - set shellCompDirectiveFilterDirs 16 + set -l shellCompDirectiveError 1 + set -l shellCompDirectiveNoSpace 2 + set -l shellCompDirectiveNoFileComp 4 + set -l shellCompDirectiveFilterFileExt 8 + set -l shellCompDirectiveFilterDirs 16 if test -z "$directive" set directive 0 end - set compErr (math (math --scale 0 $directive / $shellCompDirectiveError) % 2) + set -l compErr (math (math --scale 0 $directive / $shellCompDirectiveError) % 2) if test $compErr -eq 1 __podman_debug "Received error directive: aborting." # Might as well do file completion, in case it helps return 1 end - set filefilter (math (math --scale 0 $directive / $shellCompDirectiveFilterFileExt) % 2) - set dirfilter (math (math --scale 0 $directive / $shellCompDirectiveFilterDirs) % 2) + set -l filefilter (math (math --scale 0 $directive / $shellCompDirectiveFilterFileExt) % 2) + set -l dirfilter (math (math --scale 0 $directive / $shellCompDirectiveFilterDirs) % 2) if test $filefilter -eq 1; or test $dirfilter -eq 1 __podman_debug "File extension filtering or directory filtering not supported" # Do full file completion instead return 1 end - set nospace (math (math --scale 0 $directive / $shellCompDirectiveNoSpace) % 2) - set nofiles (math (math --scale 0 $directive / $shellCompDirectiveNoFileComp) % 2) + set -l nospace (math (math --scale 0 $directive / $shellCompDirectiveNoSpace) % 2) + set -l nofiles (math (math --scale 0 $directive / $shellCompDirectiveNoFileComp) % 2) __podman_debug "nospace: $nospace, nofiles: $nofiles" @@ -109,34 +115,34 @@ function __podman_prepare_completions # may not already be filtered so as to allow fish to match on different # criteria than the prefix. if test $nospace -ne 0; or test $nofiles -eq 0 - set prefix (commandline -t) + set -l prefix (commandline -t | string escape --style=regex) __podman_debug "prefix: $prefix" - set completions - for comp in $__podman_comp_results - if test (string match -e -r -- "^$prefix" "$comp") - set -a completions $comp - end - end + set -l completions (string match -r -- "^$prefix.*" $__podman_comp_results) set --global __podman_comp_results $completions __podman_debug "Filtered completions are: $__podman_comp_results" # Important not to quote the variable for count to work - set numComps (count $__podman_comp_results) + set -l numComps (count $__podman_comp_results) __podman_debug "numComps: $numComps" if test $numComps -eq 1; and test $nospace -ne 0 - # To support the "nospace" directive we trick the shell - # by outputting an extra, longer completion. - # We must first split on \t to get rid of the descriptions because - # the extra character we add to the fake second completion must be - # before the description. We don't need descriptions anyway since - # there is only a single real completion which the shell will expand - # immediately. - __podman_debug "Adding second completion to perform nospace directive" - set split (string split --max 1 \t $__podman_comp_results[1]) - set --global __podman_comp_results $split[1] $split[1]. - __podman_debug "Completions are now: $__podman_comp_results" + # We must first split on \t to get rid of the descriptions to be + # able to check what the actual completion will be. + # We don't need descriptions anyway since there is only a single + # real completion which the shell will expand immediately. + set -l split (string split --max 1 \t $__podman_comp_results[1]) + + # Fish won't add a space if the completion ends with any + # of the following characters: @=/:., + set -l lastChar (string sub -s -1 -- $split) + if not string match -r -q "[@=/:.,]" -- "$lastChar" + # In other cases, to support the "nospace" directive we trick the shell + # by outputting an extra, longer completion. + __podman_debug "Adding second completion to perform nospace directive" + set --global __podman_comp_results $split[1] $split[1]. + __podman_debug "Completions are now: $__podman_comp_results" + end end if test $numComps -eq 0; and test $nofiles -eq 0 @@ -152,10 +158,14 @@ end # Since Fish completions are only loaded once the user triggers them, we trigger them ourselves # so we can properly delete any completions provided by another script. -# The space after the program name is essential to trigger completion for the program -# and not completion of the program name itself. -complete --do-complete "podman " > /dev/null 2>&1 -# Using '> /dev/null 2>&1' since '&>' is not supported in older versions of fish. +# Only do this if the program can be found, or else fish may print some errors; besides, +# the existing completions will only be loaded if the program can be found. +if type -q "podman" + # The space after the program name is essential to trigger completion for the program + # and not completion of the program name itself. + # Also, we use '> /dev/null 2>&1' since '&>' is not supported in older versions of fish. + complete --do-complete "podman " > /dev/null 2>&1 +end # Remove any pre-existing completions for the program since we will be handling all of them. complete -c podman -e diff --git a/completions/powershell/podman-remote.ps1 b/completions/powershell/podman-remote.ps1 index 875684b34..e065d0426 100644 --- a/completions/powershell/podman-remote.ps1 +++ b/completions/powershell/podman-remote.ps1 @@ -123,19 +123,6 @@ Register-ArgumentCompleter -CommandName 'podman-remote' -ScriptBlock { $Space = "" } - if (($Directive -band $ShellCompDirectiveNoFileComp) -ne 0 ) { - __podman-remote_debug "ShellCompDirectiveNoFileComp is called" - - if ($Values.Length -eq 0) { - # Just print an empty string here so the - # shell does not start to complete paths. - # We cannot use CompletionResult here because - # it does not accept an empty string as argument. - "" - return - } - } - if ((($Directive -band $ShellCompDirectiveFilterFileExt) -ne 0 ) -or (($Directive -band $ShellCompDirectiveFilterDirs) -ne 0 )) { __podman-remote_debug "ShellCompDirectiveFilterFileExt ShellCompDirectiveFilterDirs are not supported" @@ -148,13 +135,26 @@ Register-ArgumentCompleter -CommandName 'podman-remote' -ScriptBlock { # filter the result $_.Name -like "$WordToComplete*" - # Join the flag back if we have a equal sign flag + # Join the flag back if we have an equal sign flag if ( $IsEqualFlag ) { __podman-remote_debug "Join the equal sign flag back to the completion value" $_.Name = $Flag + "=" + $_.Name } } + if (($Directive -band $ShellCompDirectiveNoFileComp) -ne 0 ) { + __podman-remote_debug "ShellCompDirectiveNoFileComp is called" + + if ($Values.Length -eq 0) { + # Just print an empty string here so the + # shell does not start to complete paths. + # We cannot use CompletionResult here because + # it does not accept an empty string as argument. + "" + return + } + } + # Get the current mode $Mode = (Get-PSReadLineKeyHandler | Where-Object {$_.Key -eq "Tab" }).Function __podman-remote_debug "Mode: $Mode" @@ -216,7 +216,7 @@ Register-ArgumentCompleter -CommandName 'podman-remote' -ScriptBlock { Default { # Like MenuComplete but we don't want to add a space here because # the user need to press space anyway to get the completion. - # Description will not be shown because that's not possible with TabCompleteNext + # Description will not be shown because thats not possible with TabCompleteNext [System.Management.Automation.CompletionResult]::new($($comp.Name | __podman-remote_escapeStringWithSpecialChars), "$($comp.Name)", 'ParameterValue', "$($comp.Description)") } } diff --git a/completions/powershell/podman.ps1 b/completions/powershell/podman.ps1 index 619c5beea..fa856eee4 100644 --- a/completions/powershell/podman.ps1 +++ b/completions/powershell/podman.ps1 @@ -123,19 +123,6 @@ Register-ArgumentCompleter -CommandName 'podman' -ScriptBlock { $Space = "" } - if (($Directive -band $ShellCompDirectiveNoFileComp) -ne 0 ) { - __podman_debug "ShellCompDirectiveNoFileComp is called" - - if ($Values.Length -eq 0) { - # Just print an empty string here so the - # shell does not start to complete paths. - # We cannot use CompletionResult here because - # it does not accept an empty string as argument. - "" - return - } - } - if ((($Directive -band $ShellCompDirectiveFilterFileExt) -ne 0 ) -or (($Directive -band $ShellCompDirectiveFilterDirs) -ne 0 )) { __podman_debug "ShellCompDirectiveFilterFileExt ShellCompDirectiveFilterDirs are not supported" @@ -148,13 +135,26 @@ Register-ArgumentCompleter -CommandName 'podman' -ScriptBlock { # filter the result $_.Name -like "$WordToComplete*" - # Join the flag back if we have a equal sign flag + # Join the flag back if we have an equal sign flag if ( $IsEqualFlag ) { __podman_debug "Join the equal sign flag back to the completion value" $_.Name = $Flag + "=" + $_.Name } } + if (($Directive -band $ShellCompDirectiveNoFileComp) -ne 0 ) { + __podman_debug "ShellCompDirectiveNoFileComp is called" + + if ($Values.Length -eq 0) { + # Just print an empty string here so the + # shell does not start to complete paths. + # We cannot use CompletionResult here because + # it does not accept an empty string as argument. + "" + return + } + } + # Get the current mode $Mode = (Get-PSReadLineKeyHandler | Where-Object {$_.Key -eq "Tab" }).Function __podman_debug "Mode: $Mode" @@ -216,7 +216,7 @@ Register-ArgumentCompleter -CommandName 'podman' -ScriptBlock { Default { # Like MenuComplete but we don't want to add a space here because # the user need to press space anyway to get the completion. - # Description will not be shown because that's not possible with TabCompleteNext + # Description will not be shown because thats not possible with TabCompleteNext [System.Management.Automation.CompletionResult]::new($($comp.Name | __podman_escapeStringWithSpecialChars), "$($comp.Name)", 'ParameterValue', "$($comp.Description)") } } diff --git a/completions/zsh/_podman b/completions/zsh/_podman index b25e9cb08..9bad56d9a 100644 --- a/completions/zsh/_podman +++ b/completions/zsh/_podman @@ -17,8 +17,6 @@ _podman() local shellCompDirectiveNoFileComp=4 local shellCompDirectiveFilterFileExt=8 local shellCompDirectiveFilterDirs=16 - local shellCompDirectiveLegacyCustomComp=32 - local shellCompDirectiveLegacyCustomArgsComp=64 local lastParam lastChar flagPrefix requestComp out directive comp lastComp noSpace local -a completions diff --git a/completions/zsh/_podman-remote b/completions/zsh/_podman-remote index fc2984cfd..5132d0e53 100644 --- a/completions/zsh/_podman-remote +++ b/completions/zsh/_podman-remote @@ -17,8 +17,6 @@ _podman-remote() local shellCompDirectiveNoFileComp=4 local shellCompDirectiveFilterFileExt=8 local shellCompDirectiveFilterDirs=16 - local shellCompDirectiveLegacyCustomComp=32 - local shellCompDirectiveLegacyCustomArgsComp=64 local lastParam lastChar flagPrefix requestComp out directive comp lastComp noSpace local -a completions -- cgit v1.2.3-54-g00ecf