libvirt/tools/bash-completion/vsh
Lin Ma 8a4343a436 vsh: Fix completion error in case of multiple mac addresses
We know that the bash completer automatically handle colon by preceding
it with an escape character backslash.
While our bash autompletion file vsh completes multiple items, In case
there're multiple items which have same prefix and the content of completion
items contain colon(say mac address), The vsh needs to correctly hands
the backslash which are added by bash completer, Otherwise the completion
won't be successful. This patch fixes this problem.

e.g.:

 # virsh domiflist --domain VM
 Interface   Type      Source    Model    MAC
-------------------------------------------------------------
 vnet0       network   default   virtio   52:54:00:fb:7b:f5
 vnet1       bridge    br0       virtio   52:54:00:80:1b:21

Before:
 # virsh detach-interface --domain VM --mac <TAB>
 # virsh detach-interface --domain VM --mac 52\:54\:00\:<TAB><TAB>

After:
 # virsh detach-interface --domain VM --mac <TAB>
 # virsh detach-interface --domain VM --mac 52\:54\:00\:<TAB><TAB>
 52:54:00:80:1b:21  52:54:00:fb:7b:f5
 # virsh detach-interface --domain VM --mac 52\:54\:00\:

Signed-off-by: Lin Ma <lma@suse.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
2020-11-10 18:34:18 +01:00

69 lines
2.1 KiB
Bash

#
# virsh & virt-admin completion command
#
_vsh_complete()
{
local words cword c=0 i=0 cur RO URI CMDLINE INPUT A
# Here, $COMP_WORDS is an array of words on the bash
# command line that user wants to complete. However, when
# parsing command line, the default set of word breaks is
# applied. This doesn't work for us as it mangles libvirt
# arguments, e.g. connection URI (with the default set it's
# split into multiple items within the array). Fortunately,
# there's a fixup function for the array.
_get_comp_words_by_ref -n "\"'><=;|&(:" -w words -i cword
COMP_WORDS=( "${words[@]}" )
COMP_CWORD=${cword}
cur=${COMP_WORDS[$COMP_CWORD]}
# See what URI is user trying to connect to and if they are
# connecting RO. Honour that.
while [ $c -le $COMP_CWORD ]; do
word="${COMP_WORDS[c]}"
case "$word" in
-r|--readonly) RO=1 ;;
-c|--connect) c=$((++c)); URI=${COMP_WORDS[c]} ;;
*) if [ $c -ne 0 ] && [ $i -eq 0 ]; then i=$c; break; fi ;;
esac
c=$((++c))
done
CMDLINE=
if [ -n "${RO}" ]; then
CMDLINE="${CMDLINE} -r"
fi
if [ -n "${URI}" ]; then
CMDLINE="${CMDLINE} -c ${URI}"
fi
INPUT=( "${COMP_WORDS[@]:$i:$COMP_CWORD}" )
INPUT[-1]=${INPUT[-1]//\\:/:}
# Uncomment these lines for easy debug.
# echo;
# echo "RO=${flag_ro}";
# echo "URI=${URI}";
# echo "CMDLINE=${CMDLINE}";
# echo "INPUT[${#INPUT[@]}]=**${INPUT[@]}**";
# echo "cur=${cur}";
# echo;
# return 0;
# Small shortcut here. According to manpage:
# When the function is executed, the first argument ($1) is
# the name of the command whose arguments are being
# completed.
# Therefore, we might just run $1.
A=($($1 ${CMDLINE} complete -- "${INPUT[@]}" 2>/dev/null))
COMPREPLY=($(compgen -W "${A[*]%--}" -- ${cur}))
__ltrim_colon_completions "$cur"
return 0
} &&
complete -o default -o filenames -F _vsh_complete virsh &&
complete -o default -o filenames -F _vsh_complete virt-admin
# vim: ft=sh:et:ts=4:sw=4:tw=80