diff options
author | Jussi Pakkanen <jpakkane@gmail.com> | 2019-03-04 18:40:13 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-04 18:40:13 +0200 |
commit | ee863d33c134a78636c71392eac3a7c6939317e5 (patch) | |
tree | c100edef6537d461f1fc6de140cc303326ee9d46 | |
parent | 94bb29738eb00f873c3467eba0bada4ca58d8ab9 (diff) | |
parent | 75f436542cf58cc54817d095788b24ea1101d95f (diff) | |
download | meson-ee863d33c134a78636c71392eac3a7c6939317e5.zip meson-ee863d33c134a78636c71392eac3a7c6939317e5.tar.gz meson-ee863d33c134a78636c71392eac3a7c6939317e5.tar.bz2 |
Merge pull request #2601 from 1ace/feature/completion
Add completion scripts for Bash and Zsh
-rw-r--r-- | data/shell-completions/bash/meson | 441 | ||||
-rw-r--r-- | data/shell-completions/zsh/_meson | 18 | ||||
-rw-r--r-- | mesonbuild/mesonmain.py | 2 | ||||
-rw-r--r-- | mesonbuild/mtest.py | 4 |
4 files changed, 461 insertions, 4 deletions
diff --git a/data/shell-completions/bash/meson b/data/shell-completions/bash/meson new file mode 100644 index 0000000..d757e96 --- /dev/null +++ b/data/shell-completions/bash/meson @@ -0,0 +1,441 @@ +_meson() { + command="${COMP_WORDS[1]}" + case "$command" in + setup |\ + configure |\ + install |\ + introspect |\ + init |\ + test |\ + wrap |\ + subprojects |\ + help) + _meson-$command "${COMP_WORDS[@]:1}" + ;; + *) + _meson-setup "${COMP_WORDS[@]}" + ;; + esac +} && +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 |\ + libdir |\ + libexecdir |\ + bindir |\ + sbindir |\ + includedir |\ + datadir |\ + mandir |\ + infodir |\ + localedir |\ + sysconfdir |\ + localstatedir |\ + sharedstatedir) + _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)) + ;; + *) + return 1;; + esac + return 0 +} + +_meson-setup() { + + shortopts=( + h + D + v + ) + + longopts=( + help + prefix + libdir + libexecdir + bindir + sbindir + includedir + datadir + mandir + infodir + localedir + sysconfdir + localstatedir + sharedstatedir + backend + buildtype + strip + unity + werror + layout + default-library + warnlevel + stdsplit + errorlogs + cross-file + version + wrap-mode + ) + + local cur prev + if _get_comp_words_by_ref cur prev &>/dev/null && + [ "${prev:0:2}" = '--' ] && _meson_complete_option "${prev:2}" "$cur"; then + return + elif _get_comp_words_by_ref cur prev &>/dev/null && + [ "${prev:0:1}" = '-' ] && [ "${prev:1:2}" != '-' ] && _meson_complete_option "${prev:1}"; then + return + elif _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 [[ "$cur" == "--"* ]]; then + COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}' -- "${cur:2}")) + elif [[ "$cur" == "-"* ]]; then + COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}' -- "${cur:2}")) + COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}' -- "${cur:1}")) + else + _filedir -d + if [ -z "$cur" ]; then + COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}')) + COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}')) + fi + + if [ $COMP_CWORD -eq 1 ]; then + COMPREPLY+=($(compgen -W 'setup configure test introspect' -- "$cur")) + fi + fi +} + +_meson-configure() { + + shortopts=( + h + D + ) + + longopts=( + help + clearcache + ) + + 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 [[ "$cur" == "--"* ]]; then + COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}' -- "${cur:2}")) + elif [[ "$cur" == "-"* ]]; then + COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}' -- "${cur:2}")) + COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}' -- "${cur:1}")) + else + 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-test() { + shortopts=( + q + v + t + C + ) + + longopts=( + quiet + verbose + timeout-multiplier + repeat + no-rebuild + gdb + list + wrapper --wrap + no-suite + suite + no-stdsplit + print-errorlogs + benchmark + logbase + num-processes + setup + test-args + ) + + local cur prev + if _get_comp_words_by_ref -n ':' cur prev &>/dev/null; then + case $prev in + --repeat) + # number, can't be completed + return + ;; + --wrapper) + _command_offset $COMP_CWORD + return + ;; + -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 [[ "$cur" == "--"* ]]; then + COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}' -- "${cur:2}")) + elif [[ "$cur" == "-"* && ${#cur} -gt 1 ]]; then + COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}' -- "${cur:1}")) + else + 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-introspect() { + shortopts=( + h + ) + + longopts=( + targets + installed + target-files + buildsystem-files + buildoptions + tests + benchmarks + dependencies + projectinfo + ) + + local cur prev + if _get_comp_words_by_ref cur prev &>/dev/null; then + case $prev in + --target-files) + for i in "${!COMP_WORDS[@]}"; do + opt="${COMP_WORDS[i]}" + dir="${COMP_WORDS[i+1]}" + case "$opt" in + -C) + break + ;; + esac + dir=. + done + tests_json=$(meson introspect "$dir" --targets) + if [ $? -eq 0 ]; then + tests=$(python3 -c 'import sys, json +for target in json.load(sys.stdin): + print(target["id"]) +' <<< "$tests_json") + COMPREPLY=($(compgen -W '$tests' -- "$cur")) + fi + return + ;; + esac + else + cur="${COMP_WORDS[COMP_CWORD]}" + fi + + if [[ "$cur" == "--"* ]]; then + COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}' -- "${cur:2}")) + elif [[ "$cur" == "-"* ]]; then + COMPREPLY+=($(compgen -P '--' -W '${longopts[*]}' -- "${cur:2}")) + COMPREPLY+=($(compgen -P '-' -W '${shortopts[*]}' -- "${cur:1}")) + else + 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-wrap() { + : TODO +} diff --git a/data/shell-completions/zsh/_meson b/data/shell-completions/zsh/_meson index 481d04c..b48b0f8 100644 --- a/data/shell-completions/zsh/_meson +++ b/data/shell-completions/zsh/_meson @@ -49,8 +49,22 @@ local -a meson_commands=( # TODO: implement build option completion (( $+functions[__meson_build_options] )) || __meson_build_options() {} -# TODO: implement target name completion -(( $+functions[__meson_targets] )) || __meson_targets() {} + +(( $+functions[__meson_targets] )) || __meson_targets() { + local tests_json + # TODO: get builddir out of the cmdline and pass it here + if tests_json="$(_call_program meson meson introspect --targets)"; + then + local -a tests_ids=$(_call_program python3 python3 -c 'import sys, json; +for target in json.load(sys.stdin): + print(target["id"]) +' <<< "$tests_json") + _describe -t "tests" "Meson tests IDs" tests_ids + else + _message -r "current working directory is not a build directory" + fi +} + # `meson introspect` currently can provide that information in JSON. # We can: # 1) pipe its output to python3 -m json.tool | grep "$alovelyregex" | cut <...> diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py index 822a943..91a52b1 100644 --- a/mesonbuild/mesonmain.py +++ b/mesonbuild/mesonmain.py @@ -28,6 +28,8 @@ from .environment import detect_msys2_arch from .wrap import wraptool +# Note: when adding arguments, please also add them to the completion +# scripts in $MESONSRC/data/shell-completions/ class CommandLineParser: def __init__(self): self.term_width = shutil.get_terminal_size().columns diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py index 02b728e..77a0f82 100644 --- a/mesonbuild/mtest.py +++ b/mesonbuild/mtest.py @@ -943,6 +943,7 @@ def list_tests(th): tests = th.get_tests() for t in tests: print(th.get_pretty_suite(t)) + return not tests def rebuild_all(wd): if not os.path.isfile(os.path.join(wd, 'build.ninja')): @@ -996,8 +997,7 @@ def run(options): try: th = TestHarness(options) if options.list: - list_tests(th) - return 0 + return list_tests(th) if not options.args: return th.doit() return th.run_special() |