summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLevente Polyak <anthraxx@archlinux.org>2023-03-23 23:37:58 +0100
committerLevente Polyak <anthraxx@archlinux.org>2023-05-20 00:08:13 +0200
commitf961e2e94803dd46c4fa5941eb15a7d4612bd0f0 (patch)
tree541932d2483ca5b340477ddae24c4a67d6c5f192
parent645a5a9f047ada2fd76d6149ed24aa888547a52d (diff)
downloaddevtools-f961e2e94803dd46c4fa5941eb15a7d4612bd0f0.tar.xz
completion: implemented structured declarative bash completions
This will make it tremendously easier to add arguments, subcommands and special positional option handling. Instead of the need to code the nested structure via bash and switch cases, we can simply declare functions and arrays with the matching names according to the subcommands or argument labels. Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
-rw-r--r--contrib/completion/bash/devtools.in506
1 files changed, 424 insertions, 82 deletions
diff --git a/contrib/completion/bash/devtools.in b/contrib/completion/bash/devtools.in
index a353b99..e3ae023 100644
--- a/contrib/completion/bash/devtools.in
+++ b/contrib/completion/bash/devtools.in
@@ -2,89 +2,431 @@
#
# SPDX-License-Identifier: GPL-3.0-or-later
-_devtools_compgen() {
- local i r
- COMPREPLY=($(compgen -W '$*' -- "$cur"))
- for ((i=1; i < ${#COMP_WORDS[@]}-1; i++)); do
- for r in "${!COMPREPLY[@]}"; do
- if [[ ${COMP_WORDS[i]} = "${COMPREPLY[r]}" ]]; then
- unset 'COMPREPLY[r]'; break
- fi
- done
- done
-}
-
-_pkgrepo_pkg() {
- _devtools_compgen "$(
- command pacman "-$1"
- )"
-}
-
-_pkgrepo() {
- local cur prev
- COMPREPLY=()
- cur=$(_get_cword)
- prev=${COMP_WORDS[COMP_CWORD-1]}
-
- _pkgrepo_pkg Slq
- true
-} &&
-complete -F _pkgrepo pkgrepo
-
-_makechrootpkg() {
- local cur
- COMPREPLY=()
- _get_comp_words_by_ref cur
-
- case $cur in
- -*)
- COMPREPLY=( $( compgen -W '-I -c -h -l -r -u' -- "$cur" ) )
- ;;
- *)
- _filedir
- return 0
- ;;
- esac
-
- true
-} &&
+_DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@}
+# shellcheck source=src/lib/valid-tags.sh
+source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-tags.sh
+# shellcheck source=src/lib/valid-repos.sh
+source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-repos.sh
+
+_binary_arch=${_arch[*]:0:-1}
+_colors=(never always auto)
+
+
+_makechrootpkg_args=(
+ -h
+ -c
+ -d
+ -D
+ -u
+ -r
+ -I
+ -l
+ -n
+ -T
+ -U
+)
+_makechrootpkg_args_d_opts() { _filedir -d; }
+_makechrootpkg_args_D_opts() { _filedir -d; }
+_makechrootpkg_args_r_opts() { _filedir -d; }
+_makechrootpkg_args_I_opts() { _filedir '*.pkg.tar.*'; }
+_makechrootpkg_args_l_opts() { _filedir -d; }
+_makechrootpkg_args_U_opts() { :; }
+_makechrootpkg() { __devtools_complete _makechrootpkg; }
complete -F _makechrootpkg makechrootpkg
-_mkarchroot() {
- local cur
- COMPREPLY=()
- _get_comp_words_by_ref cur
-
- case $cur in
- -*)
- COMPREPLY=( $( compgen -W '-C -M -c -h' -- "$cur" ) )
- ;;
- *)
- _filedir
- return 0
- ;;
- esac
-
- true
-} &&
+
+_makerepropkg_args=(
+ -h
+ -d
+ -c
+ -M
+)
+_makerepropkg_args_c_opts() { _filedir -d; }
+_makerepropkg_args_M_opts() { _filedir '*.conf'; }
+_makerepropkg_opts() { _filedir '*.pkg.tar.*'; }
+_makerepropkg() { __devtools_complete _makerepropkg; }
+complete -F _makerepropkg makerepropkg
+
+
+_mkarchroot_args=(
+ -U
+ -C
+ -M
+ -c
+ -h
+)
+_mkarchroot_args_U_opts() { _filedir '*.pkg.tar.*'; }
+_mkarchroot_args_C_opts() { _filedir '*.conf'; }
+_mkarchroot_args_M_opts() { _filedir '*.conf'; }
+_mkarchroot_args_c_opts() { _filedir -d; }
+_mkarchroot_opts() {
+ local args
+ args=$(__pkgctl_word_count_after_subcommand)
+ if (( args == 0 )); then
+ _filedir -d
+ elif (( args >= 1 )); then
+ _devtools_completions_all_packages
+ fi
+}
+_mkarchroot() { __devtools_complete _mkarchroot; }
complete -F _mkarchroot mkarchroot
-_arch-nspawn() {
- local cur
- COMPREPLY=()
- _get_comp_words_by_ref cur
-
- case $cur in
- -*)
- COMPREPLY=( $( compgen -W '-C -M -c -h' -- "$cur" ) )
- ;;
- *)
- _filedir
- return 0
- ;;
- esac
-
- true
-} &&
-complete -F _arch-nspawn arch-nspawn
-# ex:et ts=2 sw=2 ft=sh
+
+_arch_nspawn_args=(
+ -C
+ -M
+ -c
+ -f
+ -s
+ -h
+)
+_arch_nspawn_args_C_opts() { _filedir '*.conf'; }
+_arch_nspawn_args_M_opts() { _filedir '*.conf'; }
+_arch_nspawn_args_c_opts() { _filedir -d; }
+_arch_nspawn_args_f_opts() { _filedir; }
+_arch_nspawn_opts() {
+ local args
+ args=$(__pkgctl_word_count_after_subcommand)
+ if (( args == 0 )); then
+ _filedir -d
+ fi
+}
+_arch_nspawn() { __devtools_complete _arch_nspawn; }
+complete -F _arch_nspawn arch-nspawn
+
+
+_sogrep_args=(
+ -v --verbose
+ -r --refresh
+ -h --help
+)
+_sogrep_opts() {
+ local args
+ args=$(__pkgctl_word_count_after_subcommand)
+ if (( args == 0 )); then
+ _devtools_completions_repo all
+ fi
+}
+_sogrep() { __devtools_complete _sogrep; }
+complete -F _sogrep sogrep
+
+
+_offload_build_args=(
+ -r --repo
+ -a --arch
+ -s --server
+ -h --help
+)
+_offload_build_args__repo_opts() { _devtools_completions_build_repo; }
+_offload_build_args_r_opts() { _offload_build_args__repo_opts; }
+_offload_build_args__arch_opts() { _devtools_completions_arch; }
+_offload_build_args_a_opts() { _offload_build_args__arch_opts; }
+_offload_build_args__server_opts() { :; }
+_offload_build_args_s_opts() { _offload_build_args__server_opts; }
+_offload_build() { __devtools_complete _offload_build; }
+complete -F _offload_build offload-build
+
+
+_pkgctl_cmds=(
+ auth
+ build
+ db
+ diff
+ release
+ repo
+ version
+)
+_pkgctl_args=(
+ -V --version
+ -h --help
+)
+
+
+_pkgctl_auth_cmds=(
+ login
+ status
+)
+
+
+_pkgctl_auth_login_args=(
+ -g --gen-access-token
+ -h --help
+)
+
+
+_pkgctl_auth_status_args=(
+ -t --show-token
+ -h --help
+)
+
+
+_pkgctl_build_args=(
+ --arch
+ --repo
+
+ -s --staging
+ -t --testing
+ -o --offload
+ -c --clean
+
+ --pkgver
+ --pkgrel
+ --rebuild
+ -e --edit
+
+ -r --release
+ -m --message
+ -u --db-update
+
+ -h --help
+)
+_pkgctl_build_args__arch_opts() { _devtools_completions_arch; }
+_pkgctl_build_args__repo_opts() { _devtools_completions_repo; }
+_pkgctl_build_args__pkgver_opts() { :; }
+_pkgctl_build_args__pkgrel_opts() { :; }
+_pkgctl_build_args__message_opts() { :; }
+_pkgctl_build_args_m_opts() { _pkgctl_build_args__message_opts; }
+_pkgctl_build_opts() { _filedir -d; }
+
+
+_pkgctl_db_cmds=(
+ move
+ remove
+ update
+)
+
+
+_pkgctl_db_move_args=(
+ -h --help
+)
+_pkgctl_db_move_opts() {
+ local subcommand args
+ subcommand=(db move)
+ args=$(__pkgctl_word_count_after_subcommand "${subcommand[@]}")
+
+ if (( args == 0 )); then
+ _devtools_completions_repo
+ elif (( args == 1 )); then
+ _devtools_completions_repo
+ elif (( args >= 2 )); then
+ _devtools_completions_all_packages
+ fi
+}
+
+
+_pkgctl_db_remove_args=(
+ -a --arch
+ -h --help
+)
+_pkgctl_db_remove_opts() {
+ local subcommand args
+ subcommand=(db remove)
+ args=$(__pkgctl_word_count_after_subcommand "${subcommand[@]}")
+
+ if (( args == 0 )); then
+ _devtools_completions_repo
+ elif (( args >= 1 )); then
+ _devtools_completions_all_packages
+ fi
+}
+
+
+_pkgctl_db_update_args=(
+ -h --help
+)
+
+
+_pkgctl_release_args=(
+ -m --message
+ -r --repo
+ -s --staging
+ -t --testing
+ -u --db-update
+ -h --help
+)
+_pkgctl_release_args__message_opts() { :; }
+_pkgctl_release_args_m_opts() { _pkgctl_release_args__message_opts; }
+_pkgctl_release_args__repo_opts() { _devtools_completions_repo; }
+_pkgctl_release_args_r_opts() { _pkgctl_release_args__repo_opts; }
+_pkgctl_release_opts() { _filedir -d; }
+
+
+_pkgctl_repo_cmds=(
+ clone
+ configure
+ create
+ web
+)
+
+
+_pkgctl_repo_clone_args=(
+ -m --maintainer
+ -u --unprivileged
+ --universe
+ -h --help
+)
+_pkgctl_repo_clone_args__maintainer_opts() { :; }
+_pkgctl_repo_clone_args_m_opts() { _pkgctl_repo_clone_args__maintainer_opts; }
+_pkgctl_repo_clone_opts() { _devtools_completions_all_packages; }
+
+
+_pkgctl_repo_configure_args=(
+ -h --help
+)
+_pkgctl_repo_configure_opts() { _filedir -d; }
+
+
+_pkgctl_repo_create_args=(
+ -c --clone
+ -h --help
+)
+
+
+_pkgctl_repo_web_args=(
+ -h --help
+)
+_pkgctl_repo_web_opts() { _filedir -d; }
+
+
+_pkgctl_diff_args=(
+ -l --list
+ -d --diffoscope
+ -p --pkginfo
+ -b --buildinfo
+ -m --makepkg-config
+ -u -U --unified
+ -y --side-by-side
+ --color
+ -W --width
+ -P --pool
+ -v --verbose
+ -h --help
+)
+_pkgctl_diff_args__makepkg_config_opts() { _filedir '*.conf'; }
+_pkgctl_diff_args_m_opts() { _pkgctl_diff_args__makepkg_config_opts; }
+_pkgctl_diff_args__width_opts() { :; }
+_pkgctl_diff_args_W_opts() { _pkgctl_diff_args__width_opts; }
+_pkgctl_diff_args__color_opts() { _devtools_completions_color; }
+_pkgctl_diff_args__pool_opts() { _filedir -d; }
+_pkgctl_diff_args_P_opts() { _pkgctl_diff_args__pool_opts; }
+_pkgctl_diff_opts() { _devtools_completions_all_packages; }
+
+
+_pkgctl_version_args=(
+ -h --help
+)
+
+
+_devtools_completions_color() {
+ mapfile -t COMPREPLY < <(compgen -W "${_colors[*]}" -- "$cur")
+}
+_devtools_completions_arch() {
+ mapfile -t COMPREPLY < <(compgen -W "${_arch[*]}" -- "$cur")
+}
+_devtools_completions_repo() {
+ local optional=${1:-}
+ mapfile -t COMPREPLY < <(compgen -W "${optional} ${_repos[*]}" -- "$cur")
+}
+_devtools_completions_build_repo() {
+ mapfile -t COMPREPLY < <(compgen -W "${_build_repos[*]}" -- "$cur")
+}
+_devtools_completions_all_packages() {
+ mapfile -t COMPREPLY < <(compgen -W "$(pacman -Sql)" -- "$cur")
+}
+
+__devtools_complete() {
+ local service=$1
+ local cur prev
+
+ # Don't break words at : and =
+ COMP_WORDBREAKS=${COMP_WORDBREAKS//[:=]}
+
+ cur=$(_get_cword)
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ __pkgctl_handle_subcommands "${service}"
+ return 0
+}
+
+__pkgctl_has_func() {
+ declare -f -- "${1}" &>/dev/null
+}
+
+__pkgctl_has_array() {
+ declare -p -- "${1}" &>/dev/null
+}
+
+__pkgctl_is_subcommand() {
+ __pkgctl_has_array "${1}"_args || \
+ __pkgctl_has_array "${1}"_cmds
+}
+
+__pkgctl_words_after_subcommand() {
+ local subcommand=("$@")
+ local subcommand_idx=0
+ local word prev_word
+ for ((i = 1; i < ${#COMP_WORDS[@]}; ++i)); do
+ word=${COMP_WORDS[i]}
+ prev_word=${COMP_WORDS[i-1]}
+ # skip options and the current typing
+ if [[ ${word} == -* ]] || [[ ${word} == "${cur}" ]]; then
+ continue
+ fi
+ # skip until we resolved the passed subcommand
+ if (( subcommand_idx < ${#subcommand[@]} )); then
+ if [[ $word == "${subcommand[$subcommand_idx]}" ]]; then
+ subcommand_idx=$(( subcommand_idx + 1 ))
+ fi
+ continue
+ fi
+ # skip previous options as they belong to the argument
+ if [[ ${prev_word} == -* ]] && __pkgctl_has_func "${service_name}_args${prev_word//-/_}_opts"; then
+ continue
+ fi
+ printf "%s\n" "${word}"
+ done
+}
+__pkgctl_word_count_after_subcommand() {
+ local subcommand=("$@")
+ mapfile -t words < <(__pkgctl_words_after_subcommand "${subcommand[@]}")
+ echo "${#words[@]}"
+}
+
+__pkgctl_handle_subcommands() {
+ local service_name=${1}
+ local index=${2:-0}
+ local word ref
+
+ # recurse into nested subcommands
+ for ((i = index + 1; i < ${#COMP_WORDS[@]}; ++i)); do
+ word=${COMP_WORDS[i]}
+ if [[ ${word} == -* ]] || [[ ${word} == "${cur}" ]]; then
+ continue
+ fi
+ if __pkgctl_is_subcommand "${service_name}_${word}"; then
+ __pkgctl_handle_subcommands "${service_name}_${word}" "${i}"
+ return
+ fi
+ done
+
+ # dynamic argument options
+ if [[ $prev == -* ]] && word=${prev//-/_} && __pkgctl_has_func "${service_name}_args${word}_opts"; then
+ "${service_name}_args${word}_opts"
+ # dynamic subcommand options
+ elif [[ $cur != -* ]] && __pkgctl_has_func "${service_name}_opts"; then
+ "${service_name}_opts"
+ # subcommand argument array
+ elif ( ! __pkgctl_has_array "${service_name}"_cmds || [[ $cur == -* ]] ) && __pkgctl_has_array "${service_name}_args"; then
+ declare -n ref="${service_name}_args"
+ mapfile -t COMPREPLY < <(compgen -W "${ref[*]}" -- "$cur")
+ # subcommand array
+ elif __pkgctl_has_array "${service_name}"_cmds; then
+ declare -n ref="${service_name}_cmds"
+ mapfile -t COMPREPLY < <(compgen -W "${ref[*]}" -- "$cur")
+ fi
+}
+
+
+_pkgctl() { __devtools_complete _pkgctl; }
+complete -F _pkgctl pkgctl
+# ex:noet ts=4 sw=4 ft=sh