Ben Grande d13a21a734
fix: avoid echo usage
Echo can interpret operand as an option and checking every variable to
be echoed is troublesome while with printf, if the format specifier is
present before the operand, printing as string can be enforced.
2024-08-06 18:12:46 +02:00

190 lines
5.6 KiB
Bash

# bash completion for qvm -*- shell-script -*-
## vim: set ft=bash
## SPDX-FileCopyrightText: 2018 Bernhard Haaber <https://forum.qubes-os.org/u/haaber>
## SPDX-FileCopyrightText: 2018 Ivan <https://github.com/taradiddles>
##
## SPDX-License-Identifier: GPL-2.0-only
## Credits:
## - https://www.mail-archive.com/qubes-users@googlegroups.com/msg20088.html
## - https://github.com/taradiddles/qubes-os-qvm-bash-completion
# ---------------------------------------------------------------------------
# COMP_CWORD related functions
# Get the relative position of COMP_CWORD with option words ignored
# Note: This logic is flawed when using option arguments (eg. -s blah).
# Unfortunately there is no way to solve this except parsing every
# known option for a given qvm-* command
_get-cword-pos() {
local index=0
local i
for ((i=1; i<=COMP_CWORD; i++)); do
[[ ${COMP_WORDS[i]} == -* ]] && continue
((index++))
done
printf '%s\n' "${index}"
}
# Get the relative position of the first COMP_CWORD with option words ignored
# Note: Same limitation as _get-cword-pos() above.
_get-first-cword() {
local i
for ((i=1; i<=COMP_CWORD; i++)); do
[[ ${COMP_WORDS[i]} == -* ]] && continue
printf '%s\n' "${COMP_WORDS[i]}"
return 0
done
printf '%s\n' ""
}
# ---------------------------------------------------------------------------
# Completion functions (set COMPREPLY)
# Sets COMPREPLY to an array of qubes in a given state
_complete-qubes() {
local qubes
local state="${1}"
local state_re=''
local cur="${COMP_WORDS[COMP_CWORD]}"
case "${state}" in
running|halted|paused)
state_re="${state}"
;;
runtrans)
state_re='\(running\|transient\)'
;;
any_state)
state_re='[^|]\+'
;;
esac
qubes=$(qvm-ls --raw-data | grep -v -e '^dom0|' | \
grep -i -e "^[^|]\+|${state_re}|" | cut -f1 -d"|")
mapfile -t COMPREPLY < <(compgen -W "${qubes}" -- "${cur}")
return 0
}
# Sets COMPREPLY to an array of qube properties (prefs, features, tags, service)
_complete-qubeprops() {
local qube="${1}"
local property="${2}"
local props
local cur="${COMP_WORDS[COMP_CWORD]}"
if qvm-check "${qube}" > /dev/null 2>&1; then
case "${property}" in
prefs|features|tags|service)
props=$("qvm-${property}" "${qube}" | \
cut -f1 -d " ")
;;
esac
fi
mapfile -t COMPREPLY < <(compgen -W "${props}" -- "${cur}")
}
# Sets COMPREPLY to an array of qvm-tags options
_complete-qvm-tags-actions() {
local cur="${COMP_WORDS[COMP_CWORD]}"
local options=$(qvm-tags --help | \
sed -ne 's/.*VMNAME {\([^}]\+\)}.*/\1/p' | tr ',' '\n')
mapfile -t COMPREPLY < <(compgen -W "${options}" -- "${cur}")
}
# Sets COMPREPLY to an array of file names
_complete-filenames() {
local cur="${COMP_WORDS[COMP_CWORD]}"
mapfile -t COMPREPLY < <(compgen -f -- "$cur")
return 0
}
# ---------------------------------------------------------------------------
# "Link" completion functions to qvm-* commands
# complete each argument with qubes in any state
_qvmcmd-any_state-all_args() {
_complete-qubes "any_state"
}
complete -F _qvmcmd-any_state-all_args qvm-backup
complete -F _qvmcmd-any_state-all_args qvm-ls
# complete the first argument with qubes in a given state
_qvmcmd-in_state() {
local state="$1"
[ "$(_get-cword-pos "${COMP_CWORD}")" = 1 ] &&
_complete-qubes "${state}"
}
_qvmcmd-any_state() { _qvmcmd-in_state "any_state"; }
complete -F _qvmcmd-any_state qvm-check
complete -F _qvmcmd-any_state qvm-clone
complete -F _qvmcmd-any_state qvm-firewall
complete -F _qvmcmd-any_state qvm-remove
complete -F _qvmcmd-any_state qvm-run
complete -F _qvmcmd-any_state qvm-service
complete -F _qvmcmd-any_state qvm-start-gui
complete -F _qvmcmd-any_state qvm-usb
_qvmcmd-halted() { _qvmcmd-in_state "halted"; }
complete -F _qvmcmd-halted qvm-start
_qvmcmd-paused() { _qvmcmd-in_state "paused"; }
complete -F _qvmcmd-paused qvm-unpause
_qvmcmd-running() { _qvmcmd-in_state "running"; }
complete -F _qvmcmd-running qvm-pause
complete -F _qvmcmd-running qvm-shutdown
_qvmcmd-runtrans() { _qvmcmd-in_state "runtrans"; }
complete -F _qvmcmd-runtrans qvm-kill
# complete the first argument with qubes in any state
# complete n>=2 arguments with filenames
_qvmcmd-any_state-filenames() {
if [ "$(_get-cword-pos "${COMP_CWORD}")" = 1 ]; then
_complete-qubes "any_state"
else
_complete-filenames
fi
}
complete -F _qvmcmd-any_state-filenames qvm-copy-to-vm
complete -F _qvmcmd-any_state-filenames qvm-move-to-vm
# complete the first argument with qubes in any state
# complete the second argument with qube properties (features, prefs, ...)
_qvmcmd-any_state-qubeprop() {
local property="$1"
case "$(_get-cword-pos "${COMP_CWORD}")" in
1) _complete-qubes "any_state" ;;
2) _complete-qubeprops "$(_get-first-cword)" "${property}" ;;
esac
}
_qvmcmd-any_state-qubeprefs() { _qvmcmd-any_state-qubeprop "prefs"; }
complete -F _qvmcmd-any_state-qubeprefs qvm-prefs
_qvmcmd-any_state-qubefeatures() { _qvmcmd-any_state-qubeprop "features"; }
complete -F _qvmcmd-any_state-qubefeatures qvm-features
_qvmcmd-any_state-qubeservice() { _qvmcmd-any_state-qubeprop "service"; }
complete -F _qvmcmd-any_state-qubeservice qvm-service
# complete the first argument with qubes in any state
# complete the second argument with qvm-tags actions
# complete the third argument with qube properties (features, prefs, ...)
_qvmcmd-any_state-qubetags() {
case "$(_get-cword-pos "${COMP_CWORD}")" in
1) _complete-qubes "any_state" ;;
2) _complete-qvm-tags-actions ;;
3) _complete-qubeprops "$(_get-first-cword)" "tags" ;;
esac
}
complete -F _qvmcmd-any_state-qubetags qvm-tags