Merge pull request #2601 from 1ace/feature/completion

Add completion scripts for Bash and Zsh
pull/5023/head
Jussi Pakkanen 6 years ago committed by GitHub
commit ee863d33c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 441
      data/shell-completions/bash/meson
  2. 18
      data/shell-completions/zsh/_meson
  3. 2
      mesonbuild/mesonmain.py
  4. 4
      mesonbuild/mtest.py

@ -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
}

@ -49,8 +49,22 @@ local -a meson_commands=(
# TODO: implement build option completion # TODO: implement build option completion
(( $+functions[__meson_build_options] )) || __meson_build_options() {} (( $+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. # `meson introspect` currently can provide that information in JSON.
# We can: # We can:
# 1) pipe its output to python3 -m json.tool | grep "$alovelyregex" | cut <...> # 1) pipe its output to python3 -m json.tool | grep "$alovelyregex" | cut <...>

@ -28,6 +28,8 @@ from .environment import detect_msys2_arch
from .wrap import wraptool from .wrap import wraptool
# Note: when adding arguments, please also add them to the completion
# scripts in $MESONSRC/data/shell-completions/
class CommandLineParser: class CommandLineParser:
def __init__(self): def __init__(self):
self.term_width = shutil.get_terminal_size().columns self.term_width = shutil.get_terminal_size().columns

@ -943,6 +943,7 @@ def list_tests(th):
tests = th.get_tests() tests = th.get_tests()
for t in tests: for t in tests:
print(th.get_pretty_suite(t)) print(th.get_pretty_suite(t))
return not tests
def rebuild_all(wd): def rebuild_all(wd):
if not os.path.isfile(os.path.join(wd, 'build.ninja')): if not os.path.isfile(os.path.join(wd, 'build.ninja')):
@ -996,8 +997,7 @@ def run(options):
try: try:
th = TestHarness(options) th = TestHarness(options)
if options.list: if options.list:
list_tests(th) return list_tests(th)
return 0
if not options.args: if not options.args:
return th.doit() return th.doit()
return th.run_special() return th.run_special()

Loading…
Cancel
Save