2024-07-08 19:59:27 +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
echo ${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
echo "${COMP_WORDS[i]}"
return 0
done
echo ""
}
# ---------------------------------------------------------------------------
# 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 '^dom0|' | \
grep -i "^[^|]\+|${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