205 lines
7.6 KiB
Plaintext
205 lines
7.6 KiB
Plaintext
# shellcheck shell=bash
|
|
# Bash completion for terractl (terraria-server-manager)
|
|
#
|
|
# Installed to <prefix>/share/bash-completion/completions/terractl, where the
|
|
# bash-completion package loads it automatically. Also works with 'sudo terractl'.
|
|
|
|
# Instances directory: default, or TERRARIA_BASE from /etc/default/terractl.
|
|
# The file is parsed rather than sourced, so nothing runs in your shell.
|
|
_terractl_base() {
|
|
local base=/var/lib/terraria/instances value
|
|
if [[ -r /etc/default/terractl ]]; then
|
|
value=$(sed -n 's/^[[:space:]]*TERRARIA_BASE=//p' /etc/default/terractl | tail -n 1)
|
|
value=${value%\"}; value=${value#\"}; value=${value%\'}; value=${value#\'}
|
|
if [[ -n $value ]]; then base=$value; fi
|
|
fi
|
|
printf '%s\n' "$base"
|
|
}
|
|
|
|
# Instance names. Reading the directory needs root or the 'terraria' group; if
|
|
# it isn't readable, fall back to the terraria@ services systemd knows about.
|
|
_terractl_instances() {
|
|
local base conf
|
|
base=$(_terractl_base)
|
|
if [[ -r $base && -x $base ]]; then
|
|
while IFS= read -r conf; do
|
|
conf=${conf%/instance.conf}
|
|
printf '%s\n' "${conf##*/}"
|
|
done < <(compgen -G "$base/*/instance.conf")
|
|
elif command -v systemctl >/dev/null 2>&1; then
|
|
systemctl list-units --all --plain --no-legend 'terraria@*.service' 2>/dev/null |
|
|
sed -n 's/^terraria@\([^ ]*\)\.service.*/\1/p'
|
|
fi
|
|
}
|
|
|
|
# Remotes this user added with 'terractl remote add'
|
|
_terractl_remotes() {
|
|
local f=${TERRACTL_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/terractl}/remotes.json
|
|
[[ -r $f ]] || return 0
|
|
python3 -c 'import json, sys; print("\n".join(json.load(open(sys.argv[1]))["remotes"]))' "$f" 2>/dev/null
|
|
}
|
|
|
|
# Instance names on a remote. This asks its daemon, so it can take a moment.
|
|
_terractl_remote_instances() {
|
|
timeout 5 terractl --host "$1" info 2>/dev/null </dev/null | sed -n 's/^instance=//p'
|
|
}
|
|
|
|
# [<remote>:]<name> for copy and move
|
|
_terractl_places() {
|
|
if [[ $cur == -* ]]; then
|
|
_terractl_reply "--with-server"
|
|
elif [[ $cur == *:* ]]; then
|
|
mapfile -t COMPREPLY < <(compgen -P "${cur%:*}:" -W "$(_terractl_remote_instances "${cur%:*}")" -- "${cur##*:}")
|
|
else
|
|
mapfile -t COMPREPLY < <(compgen -W "$(_terractl_instances) $(_terractl_remotes | sed 's/$/:/')" -- "$cur")
|
|
# After "<remote>:" comes an instance name, not a space
|
|
if [[ ${#COMPREPLY[@]} -eq 1 && ${COMPREPLY[0]} == *: ]]; then compopt -o nospace 2>/dev/null; fi
|
|
fi
|
|
# Readline sees only the part after the last ':'
|
|
if declare -F __ltrim_colon_completions >/dev/null 2>&1; then __ltrim_colon_completions "$cur"; fi
|
|
}
|
|
|
|
# Mods installed in an instance (*.tmod files), or enabled ones (enabled.json)
|
|
_terractl_mods() {
|
|
local mdir f
|
|
mdir="$(_terractl_base)/$1/data/Mods"
|
|
if [[ $2 == enabled ]]; then
|
|
[[ -r $mdir/enabled.json ]] && grep -o '"[^"]*"' "$mdir/enabled.json" | tr -d '"'
|
|
else
|
|
while IFS= read -r f; do
|
|
f=${f##*/}
|
|
printf '%s\n' "${f%.tmod}"
|
|
done < <(compgen -G "$mdir/*.tmod")
|
|
fi
|
|
}
|
|
|
|
# File names, optionally only those ending in .<extension> (folders always offered)
|
|
_terractl_files() {
|
|
if declare -F _filedir >/dev/null 2>&1; then
|
|
_filedir "$@"
|
|
else
|
|
compopt -o filenames 2>/dev/null
|
|
if [[ -n ${1:-} ]]; then
|
|
mapfile -t COMPREPLY < <(compgen -d -- "$cur"; compgen -f -X "!*.$1" -- "$cur")
|
|
else
|
|
mapfile -t COMPREPLY < <(compgen -f -- "$cur")
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Set COMPREPLY to the words matching what's typed so far
|
|
_terractl_reply() {
|
|
mapfile -t COMPREPLY < <(compgen -W "$1" -- "$cur")
|
|
}
|
|
|
|
_terractl() {
|
|
local cur words cword
|
|
if declare -F _init_completion >/dev/null 2>&1; then
|
|
# shellcheck disable=SC2034 # prev is set by _init_completion but not needed here
|
|
local prev
|
|
# -n : keeps "<remote>:<name>" (copy, move) in one word
|
|
_init_completion -n : || return
|
|
else
|
|
cur=${COMP_WORDS[COMP_CWORD]}
|
|
words=("${COMP_WORDS[@]}")
|
|
cword=$COMP_CWORD
|
|
fi
|
|
|
|
local commands="new list info start stop restart enable disable attach watch cmd mods reinstall delete rename export import"
|
|
local console="save say playing kick ban motd password time dawn noon dusk midnight settle seed version maxplayers port clear help"
|
|
|
|
# terractl --host <remote> <command> ...: the same as on this host, except
|
|
# that instance names come from the remote and mod names aren't offered
|
|
local host=""
|
|
if [[ ${words[1]:-} == --host || ${words[1]:-} == -H ]]; then
|
|
if (( cword == 2 )); then
|
|
_terractl_reply "$(_terractl_remotes)"
|
|
return
|
|
fi
|
|
host=${words[2]}
|
|
words=("${words[0]}" "${words[@]:3}")
|
|
cword=$((cword - 2))
|
|
commands+=" --help --version"
|
|
else
|
|
commands+=" copy move remote daemon prepare run --host --help --version"
|
|
fi
|
|
|
|
if (( cword == 1 )); then
|
|
_terractl_reply "$commands"
|
|
return
|
|
fi
|
|
|
|
local command=${words[1]}
|
|
case $command in
|
|
list|help|-h|--help|version|-V|--version)
|
|
return ;;
|
|
new)
|
|
# new <new name> [vanilla|tmodloader] [port]: the name is new, so nothing to offer
|
|
if (( cword == 3 )); then _terractl_reply "vanilla tmodloader"; fi
|
|
return ;;
|
|
import)
|
|
# import <new name> <file.tar.gz>: the name is new, so nothing to offer
|
|
if (( cword == 3 )); then _terractl_files tar.gz; fi
|
|
return ;;
|
|
copy|move)
|
|
_terractl_places
|
|
return ;;
|
|
remote)
|
|
if (( cword == 2 )); then
|
|
_terractl_reply "add list remove"
|
|
elif (( cword == 3 )) && [[ ${words[2]} == remove ]]; then
|
|
_terractl_reply "$(_terractl_remotes)"
|
|
fi
|
|
return ;;
|
|
daemon)
|
|
if (( cword == 2 )); then
|
|
_terractl_reply "enable disable status trust"
|
|
elif (( cword == 3 )) && [[ ${words[2]} == trust ]]; then
|
|
_terractl_reply "add list remove"
|
|
fi
|
|
return ;;
|
|
esac
|
|
|
|
if (( cword == 2 )); then
|
|
if [[ -n $host ]]; then
|
|
_terractl_reply "$(_terractl_remote_instances "$host")"
|
|
else
|
|
_terractl_reply "$(_terractl_instances)"
|
|
fi
|
|
return
|
|
fi
|
|
|
|
local instance=${words[2]}
|
|
case $command in
|
|
cmd)
|
|
if (( cword == 3 )); then _terractl_reply "$console"; fi ;;
|
|
reinstall)
|
|
if (( cword == 3 )); then _terractl_reply "--clean"; fi ;;
|
|
enable|disable)
|
|
if (( cword == 3 )); then _terractl_reply "--now"; fi ;;
|
|
watch)
|
|
# the number after -n is free-form
|
|
if [[ $cur == -* ]]; then _terractl_reply "-n -q"; fi ;;
|
|
delete)
|
|
_terractl_reply "-y --yes --no-backup" ;;
|
|
export)
|
|
if [[ $cur == -* ]]; then _terractl_reply "--with-server"; else _terractl_files tar.gz; fi ;;
|
|
mods)
|
|
if (( cword == 3 )); then
|
|
_terractl_reply "list add enable disable remove"
|
|
return
|
|
fi
|
|
case ${words[3]} in
|
|
add)
|
|
# .tmod files and folders (e.g. the Windows export folder)
|
|
_terractl_files tmod ;;
|
|
enable|remove)
|
|
if [[ -z $host ]]; then _terractl_reply "$(_terractl_mods "$instance" installed)"; fi ;;
|
|
disable)
|
|
if [[ -z $host ]]; then _terractl_reply "$(_terractl_mods "$instance" enabled)"; fi ;;
|
|
esac ;;
|
|
esac
|
|
}
|
|
|
|
complete -F _terractl terractl
|