_meson() { command="${COMP_WORDS[1]}" meson_subcommands=( setup configure dist install introspect init test wrap subprojects help rewrite compile devenv env2mfile ) if [[ " ${meson_subcommands[*]} " =~ " ${command} " ]]; then _meson-$command "${COMP_WORDS[@]:1}" else _meson-setup "${COMP_WORDS[@]}" fi } && complete -F _meson meson _meson_complete_option() { option_string=$1 if [[ $# -eq 2 ]] && ! [[ "$option_string" == *=* ]]; then option_string="$option_string=$2" fi if [[ "$option_string" == *=* ]]; then _meson_complete_option_value "$option_string" else _meson_complete_option_name "$option_string" fi } _meson_complete_option_name() { option=$1 options=($(python3 -c 'import sys, json for option in json.load(sys.stdin): print(option["name"]) ' <<< "$(_meson_get_options)")) compopt -o nospace COMPREPLY=($(compgen -W '${options[@]}' -S= -- "$option")) } _meson_complete_option_value() { cur=$1 option_name=${cur%%=*} option_value=${cur#*=} if _meson_complete_filedir "$option_name" "$option_value"; then return fi # TODO: support all the option types options=($(python3 -c 'import sys, json for option in json.load(sys.stdin): if option["name"] != "'$option_name'": continue choices = [] if option["type"] == "boolean": choices.append("true") choices.append("false") elif option["type"] == "combo": for choice in option["choices"]: choices.append(choice) for choice in choices: if choice.startswith("'$cur'"): print(choice) ' <<< "$(_meson_get_options)")) COMPREPLY=("${options[@]}") } _meson_get_options() { local options for builddir in "${COMP_WORDS[@]}"; do if [ -d "$builddir" ]; then break fi builddir=. done options=$(meson introspect "$builddir" --buildoptions 2>/dev/null) && echo "$options" || echo '[]' } _meson_complete_filedir() { _filedir_in() { pushd "$1" &>/dev/null local COMPREPLY=() _filedir echo "${COMPREPLY[@]}" popd &>/dev/null } option=$1 cur=$2 case $option in prefix |\ bindir |\ datadir |\ includedir |\ infodir |\ libdir |\ licensedir |\ libexecdir |\ localedir |\ localstatedir |\ mandir |\ sbindir |\ sharedstatedir |\ sysconfdir |\ python.platlibdir |\ python.purelibdir |\ pkg-config-path |\ build.pkg-config-path |\ cmake-prefix-path |\ build.cmake-prefix-path) _filedir -d ;; cross-file) _filedir COMPREPLY+=($(_filedir_in "$XDG_DATA_DIRS"/meson/cross)) COMPREPLY+=($(_filedir_in /usr/local/share/meson/cross)) COMPREPLY+=($(_filedir_in /usr/share/meson/cross)) COMPREPLY+=($(_filedir_in "$XDG_DATA_HOME"/meson/cross)) COMPREPLY+=($(_filedir_in ~/.local/share/meson/cross)) ;; native-file) _filedir COMPREPLY+=($(_filedir_in "$XDG_DATA_DIRS"/meson/native)) COMPREPLY+=($(_filedir_in /usr/local/share/meson/native)) COMPREPLY+=($(_filedir_in /usr/share/meson/native)) COMPREPLY+=($(_filedir_in "$XDG_DATA_HOME"/meson/native)) COMPREPLY+=($(_filedir_in ~/.local/share/meson/native)) ;; *) return 1;; esac return 0 } _meson_compgen_options() { local -r cur=$1 if [[ ${cur:0:2} == -- ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}' -- "${cur:2}")) elif [[ ${cur:0:1} == - ]]; then if [[ ${#cur} == 1 ]]; then # Only add longopts if cur not "-something" COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}' -- "")) fi COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}' -- "${cur:1}")) else return 1 fi return 0 } _meson-setup() { shortopts=( h D v ) # backend-startup-project is currently VS backend only. longopts=( help prefix bindir datadir includedir infodir libdir libexecdir licensedir localedir localstatedir mandir sbindir sharedstatedir sysconfdir auto-features backend buildtype debug default-library errorlogs install-umask layout optimization prefer-static stdsplit strip unity unity-size warnlevel werror wrap-mode force-fallback-for pkgconfig.relocatable python.install-env python.platlibdir python.purelibdir pkg-config-path build.pkg-config-path cmake-prefix-path build.cmake-prefix-path native-file cross-file vsenv version fatal-meson-warnings reconfigure wipe ) local cur prev if _get_comp_words_by_ref cur prev &>/dev/null; then if [[ ${prev:0:2} == -- ]] && _meson_complete_option "${prev:2}" "$cur"; then return elif [[ ${prev:0:1} == - ]] && [[ ${prev:1:2} != - ]] && _meson_complete_option "${prev:1}"; then return fi fi if _get_comp_words_by_ref -n '=' cur prev &>/dev/null; then if [[ $prev == -D ]]; then _meson_complete_option "$cur" return fi else cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then _filedir -d if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi if [[ $COMP_CWORD == 1 ]]; then COMPREPLY+=($(compgen -W "${meson_subcommands[*]}" -- "$cur")) fi fi } _meson-configure() { shortopts=( h D ) longopts=( help prefix bindir datadir includedir infodir libdir libexecdir licensedir localedir localstatedir mandir sbindir sharedstatedir sysconfdir auto-features backend buildtype debug default-library errorlogs install-umask layout optimization prefer-static stdsplit strip unity unity-size warnlevel werror wrap-mode force-fallback-for backend-startup-project pkgconfig.relocatable python.install-env python.platlibdir python.purelibdir pkg-config-path build.pkg-config-path cmake-prefix-path build.cmake-prefix-path clearcache no-pager ) local cur prev if _get_comp_words_by_ref -n '=' cur prev &>/dev/null; then if [[ $prev == -D ]]; then _meson_complete_option "$cur" return fi else cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then for dir in "${COMP_WORDS[@]}"; do if [[ -d "$dir" ]]; then break fi dir=. done if [[ ! -d "$dir/meson-private" ]]; then _filedir -d fi if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi } _meson-dist() { : TODO } _meson-install() { : TODO } _meson-introspect() { shortopts=( h a i f ) longopts=( ast benchmarks buildoptions buildsystem-files dependencies scan-dependencies installed install-plan projectinfo targets tests backend all indent force-object-output ) local cur prev if ! _get_comp_words_by_ref cur prev &>/dev/null; then cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then for dir in "${COMP_WORDS[@]}"; do if [ -d "$dir" ]; then break fi dir=. done if [ ! -d "$dir/meson-private" ]; then _filedir -d fi if [ -z "$cur" ]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi } _meson-init() { shortopts=( h C n e d l b f ) longopts=( help name executable deps language build builddir force type version ) if ! _meson_compgen_options "$cur"; then if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi fi } _meson-test() { shortopts=( h q v t C ) longopts=( help maxfail repeat no-rebuild gdb gdb-path list wrapper suite no-suite no-stdsplit print-errorlogs benchmark logbase num-processes verbose quiet timeout-multiplier setup test-args ) local cur prev if _get_comp_words_by_ref -n ':' cur prev &>/dev/null; then case $prev in --maxfail | --repeat) # number, can't be completed return ;; --wrapper) _command_offset $COMP_CWORD return ;; --gdb-path | -C) _filedir -d return ;; --suite | --no-suite) for i in "${!COMP_WORDS[@]}"; do opt="${COMP_WORDS[i]}" dir="${COMP_WORDS[i+1]}" case "$opt" in -C) break ;; esac dir=. done suites=($(python3 -c 'import sys, json; for test in json.load(sys.stdin): for suite in test["suite"]: print(suite) ' <<< "$(meson introspect "$dir" --tests)")) # TODO COMPREPLY+=($(compgen -W "${suites[*]}" -- "$cur")) return ;; --logbase) # free string, can't be completed return ;; --num-processes) # number, can't be completed return ;; -t | --timeout-multiplier) # number, can't be completed return ;; --setup) # TODO return ;; --test-args) return ;; esac else cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then for dir in "${COMP_WORDS[@]}"; do if [ -d "$dir" ]; then break fi dir=. done if [ ! -d "$dir/meson-private" ]; then _filedir -d fi for i in "${!COMP_WORDS[@]}"; do opt="${COMP_WORDS[i]}" dir="${COMP_WORDS[i+1]}" case "$opt" in -C) break ;; esac dir=. done tests=($(python3 -c 'import sys, json; for test in json.load(sys.stdin): print(test["name"]) ' <<< "$(meson introspect "$dir" --tests)")) COMPREPLY+=($(compgen -W "${tests[*]}" -- "$cur")) if [ -z "$cur" ]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}' -- "${cur:2}")) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}' -- "${cur:1}")) fi fi } _meson-wrap() { : TODO } _meson-subprojects() { : TODO } _meson-help() { longopts=( setup configure dist install introspect init test wrap subprojects rewrite compile devenv env2mfile ) local cur prev if _get_comp_words_by_ref cur prev &>/dev/null; then COMPREPLY+=($(compgen -W '${longopts[*]}' -- "${cur}")) fi } _meson-rewrite() { : TODO } _meson-compile() { shortopts=( h C j l v ) longopts=( help clean jobs load-average verbose ninja-args vs-args xcode-args ) local cur prev if _get_comp_words_by_ref cur prev &>/dev/null; then if [[ ${prev:0:2} == -- ]] && _meson_complete_option "${prev:2}" "$cur"; then return elif [[ ${prev:0:1} == - ]] && [[ ${prev:1:2} != - ]] && _meson_complete_option "${prev:1}"; then return fi else cur="${COMP_WORDS[COMP_CWORD]}" fi if ! _meson_compgen_options "$cur"; then _filedir -d if [[ -z $cur ]]; then COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) fi if [[ $COMP_CWORD == 1 ]]; then COMPREPLY+=($(compgen -W "${meson_subcommands[*]}" -- "$cur")) fi fi } _meson-devenv() { : TODO } _meson-env2mfile() { : TODO }