From 77b2590e3219d85baa17355463431175164c20cd Mon Sep 17 00:00:00 2001 From: sarafael Date: Thu, 14 Jan 2021 14:24:00 +0100 Subject: [PATCH 1/8] add bash complete script --- ac-reframe.sh | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 ac-reframe.sh diff --git a/ac-reframe.sh b/ac-reframe.sh new file mode 100644 index 0000000000..bdbfd9d9c8 --- /dev/null +++ b/ac-reframe.sh @@ -0,0 +1,52 @@ +#/usr/bin/env bash + +_bin=/home/sarafael/repos/reframe/bin/reframe + +_cli_options=$(${_bin} --help | grep -o -e ' --[a-z\-]*' -e ' -[a-zA-Z]' --) + +_cli_options_completions() +{ + local cur prev + + cur=${COMP_WORDS[COMP_CWORD]} + prev=${COMP_WORDS[COMP_CWORD-1]} + + COMPREPLY=($(compgen -W "${_cli_options}" -- "${cur}")) + + case ${prev} in + -n|--name) + # exclude the -n from the command line to get the test names + local COMP_WORDS_NO_FLAGS=() + local index=0 + while [[ "$index" -lt "$((COMP_CWORD-1))" ]] + do + COMP_WORDS_NO_FLAGS+=("${COMP_WORDS[$index]}") + let index++ + done + + local subfunction=$(echo "${COMP_WORDS_NO_FLAGS[*]} -l") + local names=$($(echo ${subfunction} | tr % ' ') | grep 'found in ' | awk '{print$2}') + + COMPREPLY=($(compgen -W "$(echo ${names})" -- "${cur}")) + ;; + -c|--checkpath|-C|--config-file) + COMPREPLY=( $( compgen -f -- $cur ) ) + # COMPREPLY=( $( compgen -o plusdirs -f -X '!*.py' -- $cur ) ) + ;; + esac +} + +complete -o filenames -F _cli_options_completions reframe +# complete -o filenames -o dirnames -F _cli_options_completions reframe + + + + +# _cli_options=$(/home/sarafael/repos/reframe/bin/reframe --help | grep -o -e ' --[a-z\-]*' -e ' -[a-zA-Z]' --) +# +# _cli_options_completions() +# { +# COMPREPLY=($(compgen -W "${_cli_options}" -- "${COMP_WORDS[COMP_CWORD]}")) +# } +# +# complete -F _cli_options_completions reframe From ded068e7490cdabe76373672e7de55de2353dbbf Mon Sep 17 00:00:00 2001 From: sarafael Date: Thu, 14 Jan 2021 16:26:31 +0100 Subject: [PATCH 2/8] clean up comments --- ac-reframe.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ac-reframe.sh b/ac-reframe.sh index bdbfd9d9c8..dba740ef42 100644 --- a/ac-reframe.sh +++ b/ac-reframe.sh @@ -15,19 +15,19 @@ _cli_options_completions() case ${prev} in -n|--name) - # exclude the -n from the command line to get the test names - local COMP_WORDS_NO_FLAGS=() + # exclude `-n` from the command line to get the test names + local ALL_BEFORE_CURRENT_WORD=() local index=0 while [[ "$index" -lt "$((COMP_CWORD-1))" ]] do - COMP_WORDS_NO_FLAGS+=("${COMP_WORDS[$index]}") + ALL_BEFORE_CURRENT_WORD+=("${COMP_WORDS[$index]}") let index++ done - local subfunction=$(echo "${COMP_WORDS_NO_FLAGS[*]} -l") - local names=$($(echo ${subfunction} | tr % ' ') | grep 'found in ' | awk '{print$2}') + local list_command=$(echo "${ALL_BEFORE_CURRENT_WORD[*]} -l") + local test_names=$($(echo ${list_command} | tr % ' ') | grep 'found in ' | awk '{print$2}') - COMPREPLY=($(compgen -W "$(echo ${names})" -- "${cur}")) + COMPREPLY=($(compgen -W "$(echo ${test_names})" -- "${cur}")) ;; -c|--checkpath|-C|--config-file) COMPREPLY=( $( compgen -f -- $cur ) ) From 59a741051ccb124d7c3ada3f9f7239b788e8d3cd Mon Sep 17 00:00:00 2001 From: rafael Date: Thu, 14 Jan 2021 16:58:26 +0100 Subject: [PATCH 3/8] fix hardcoded path --- ac-reframe.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ac-reframe.sh b/ac-reframe.sh index dba740ef42..adb35cd3ff 100644 --- a/ac-reframe.sh +++ b/ac-reframe.sh @@ -1,6 +1,6 @@ #/usr/bin/env bash -_bin=/home/sarafael/repos/reframe/bin/reframe +_bin=reframe _cli_options=$(${_bin} --help | grep -o -e ' --[a-z\-]*' -e ' -[a-zA-Z]' --) From 891a6725d094cbe81f90af56c38007b9d0458912 Mon Sep 17 00:00:00 2001 From: sarafael Date: Fri, 22 Jan 2021 17:26:07 +0100 Subject: [PATCH 4/8] update complete script --- ac-reframe.sh | 98 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 58 insertions(+), 40 deletions(-) diff --git a/ac-reframe.sh b/ac-reframe.sh index adb35cd3ff..036b06f952 100644 --- a/ac-reframe.sh +++ b/ac-reframe.sh @@ -1,52 +1,70 @@ #/usr/bin/env bash + _bin=reframe _cli_options=$(${_bin} --help | grep -o -e ' --[a-z\-]*' -e ' -[a-zA-Z]' --) -_cli_options_completions() +_complete_test_name() { - local cur prev - - cur=${COMP_WORDS[COMP_CWORD]} - prev=${COMP_WORDS[COMP_CWORD-1]} - - COMPREPLY=($(compgen -W "${_cli_options}" -- "${cur}")) - - case ${prev} in - -n|--name) - # exclude `-n` from the command line to get the test names - local ALL_BEFORE_CURRENT_WORD=() - local index=0 - while [[ "$index" -lt "$((COMP_CWORD-1))" ]] - do - ALL_BEFORE_CURRENT_WORD+=("${COMP_WORDS[$index]}") - let index++ - done - - local list_command=$(echo "${ALL_BEFORE_CURRENT_WORD[*]} -l") - local test_names=$($(echo ${list_command} | tr % ' ') | grep 'found in ' | awk '{print$2}') - - COMPREPLY=($(compgen -W "$(echo ${test_names})" -- "${cur}")) - ;; - -c|--checkpath|-C|--config-file) - COMPREPLY=( $( compgen -f -- $cur ) ) - # COMPREPLY=( $( compgen -o plusdirs -f -X '!*.py' -- $cur ) ) - ;; - esac -} + name_line=("${COMP_WORDS[0]}") + for i in ${!COMP_WORDS[@]}; do + if [ "${COMP_WORDS[$i]}" == -c ] || [ "${COMP_WORDS[$i]}" == --checkpath ] ; then + path="${COMP_WORDS[$(($i+1))]}" + if [[ -a "$path" ]] ; then + name_line+=("-c" "$path") + fi + fi -complete -o filenames -F _cli_options_completions reframe -# complete -o filenames -o dirnames -F _cli_options_completions reframe + if [ "${COMP_WORDS[$i]}" == -R ] || [ "${COMP_WORDS[$i]}" == --recursive ] ; then + name_line+=("-R") + fi + + if [ "${COMP_WORDS[$i]}" == -t ] || [ "${COMP_WORDS[$i]}" == --tags ]; then + tags="${COMP_WORDS[$(($i+1))]}" + name_line+=("-t" "$tags") + fi + + if [ "${COMP_WORDS[$i]}" == -p ] || [ "${COMP_WORDS[$i]}" == --prgenv ]; then + prgenv="${COMP_WORDS[$(($i+1))]}" + name_line+=("-p" "prgenv") + fi + if [ "${COMP_WORDS[$i]}" == --system ]; then + system="${COMP_WORDS[$(($i+1))]}" + name_line+=("-p" "system") + fi + done + + name_line+=("-l") + echo ${name_line[@]} +} +_cli_options_completions() +{ + local cur prev + cur=${COMP_WORDS[COMP_CWORD]} + prev=${COMP_WORDS[COMP_CWORD-1]} + + COMPREPLY=($(compgen -W "${_cli_options}" -- "${cur}")) + + case ${prev} in + -n|--name) + local test_names=$(_complete_test_name) + test_names=$($(echo $test_names) 2>&1 | grep 'found in ' | awk '{print$2}') + COMPREPLY=($(compgen -W "$(echo ${test_names})" -- "${cur}")) + ;; + -t|--tag|-x|--exclude|-p|--prgenv|--system) + COMPREPLY=() + ;; + -c|--checkpath|--module-path|--report-file|--module-mappings|-C|--config-file) + COMPREPLY=($(compgen -f -- $cur)) + ;; + --prefix|-o|--output|-s|--stage|--perflogdir) + COMPREPLY=($(compgen -d -- $cur)) + ;; + esac +} -# _cli_options=$(/home/sarafael/repos/reframe/bin/reframe --help | grep -o -e ' --[a-z\-]*' -e ' -[a-zA-Z]' --) -# -# _cli_options_completions() -# { -# COMPREPLY=($(compgen -W "${_cli_options}" -- "${COMP_WORDS[COMP_CWORD]}")) -# } -# -# complete -F _cli_options_completions reframe +complete -o filenames -F _cli_options_completions reframe From 463e981299d1aba581920165a31bbd8d057733ef Mon Sep 17 00:00:00 2001 From: sarafael Date: Fri, 22 Jan 2021 17:52:18 +0100 Subject: [PATCH 5/8] fix for iterm --- ac-reframe.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ac-reframe.sh b/ac-reframe.sh index 036b06f952..97da424c5b 100644 --- a/ac-reframe.sh +++ b/ac-reframe.sh @@ -3,7 +3,7 @@ _bin=reframe -_cli_options=$(${_bin} --help | grep -o -e ' --[a-z\-]*' -e ' -[a-zA-Z]' --) +_cli_options=$(${_bin} --help | grep -o -E -e ' [-]+[a-zA-Z\-]+') _complete_test_name() { From ef45c1adf0b709ef171d8b9ce5c6217f073e233a Mon Sep 17 00:00:00 2001 From: sarafael Date: Fri, 5 Feb 2021 11:42:00 +0100 Subject: [PATCH 6/8] use argcomplete --- ac-reframe.sh | 70 ------------------------------------ bin/reframe | 1 + reframe/frontend/argparse.py | 3 ++ reframe/frontend/cli.py | 5 ++- 4 files changed, 6 insertions(+), 73 deletions(-) delete mode 100644 ac-reframe.sh diff --git a/ac-reframe.sh b/ac-reframe.sh deleted file mode 100644 index 97da424c5b..0000000000 --- a/ac-reframe.sh +++ /dev/null @@ -1,70 +0,0 @@ -#/usr/bin/env bash - - -_bin=reframe - -_cli_options=$(${_bin} --help | grep -o -E -e ' [-]+[a-zA-Z\-]+') - -_complete_test_name() -{ - name_line=("${COMP_WORDS[0]}") - for i in ${!COMP_WORDS[@]}; do - if [ "${COMP_WORDS[$i]}" == -c ] || [ "${COMP_WORDS[$i]}" == --checkpath ] ; then - path="${COMP_WORDS[$(($i+1))]}" - if [[ -a "$path" ]] ; then - name_line+=("-c" "$path") - fi - fi - - if [ "${COMP_WORDS[$i]}" == -R ] || [ "${COMP_WORDS[$i]}" == --recursive ] ; then - name_line+=("-R") - fi - - if [ "${COMP_WORDS[$i]}" == -t ] || [ "${COMP_WORDS[$i]}" == --tags ]; then - tags="${COMP_WORDS[$(($i+1))]}" - name_line+=("-t" "$tags") - fi - - if [ "${COMP_WORDS[$i]}" == -p ] || [ "${COMP_WORDS[$i]}" == --prgenv ]; then - prgenv="${COMP_WORDS[$(($i+1))]}" - name_line+=("-p" "prgenv") - fi - - if [ "${COMP_WORDS[$i]}" == --system ]; then - system="${COMP_WORDS[$(($i+1))]}" - name_line+=("-p" "system") - fi - done - - name_line+=("-l") - echo ${name_line[@]} -} - - -_cli_options_completions() -{ - local cur prev - cur=${COMP_WORDS[COMP_CWORD]} - prev=${COMP_WORDS[COMP_CWORD-1]} - - COMPREPLY=($(compgen -W "${_cli_options}" -- "${cur}")) - - case ${prev} in - -n|--name) - local test_names=$(_complete_test_name) - test_names=$($(echo $test_names) 2>&1 | grep 'found in ' | awk '{print$2}') - COMPREPLY=($(compgen -W "$(echo ${test_names})" -- "${cur}")) - ;; - -t|--tag|-x|--exclude|-p|--prgenv|--system) - COMPREPLY=() - ;; - -c|--checkpath|--module-path|--report-file|--module-mappings|-C|--config-file) - COMPREPLY=($(compgen -f -- $cur)) - ;; - --prefix|-o|--output|-s|--stage|--perflogdir) - COMPREPLY=($(compgen -d -- $cur)) - ;; - esac -} - -complete -o filenames -F _cli_options_completions reframe diff --git a/bin/reframe b/bin/reframe index 5623ef7c8b..37b749a4a2 100755 --- a/bin/reframe +++ b/bin/reframe @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +# PYTHON_ARGCOMPLETE_OK # # Copyright 2016-2020 Swiss National Supercomputing Centre (CSCS/ETH Zurich) # ReFrame Project Developers. See the top-level LICENSE file for details. diff --git a/reframe/frontend/argparse.py b/reframe/frontend/argparse.py index 67f0bce3ab..3bf4e08819 100644 --- a/reframe/frontend/argparse.py +++ b/reframe/frontend/argparse.py @@ -3,6 +3,7 @@ # # SPDX-License-Identifier: BSD-3-Clause +import argcomplete import argparse import os @@ -257,6 +258,8 @@ def parse_args(self, args=None, namespace=None): `add_argument()` call. If no default value was specified either, the attribute will be set to `None`.''' + argcomplete.autocomplete(self._holder) + # We always pass an empty namespace to our internal argparser and we do # the namespace resolution ourselves. We do this, because we want the # newly parsed options to completely override any options defined in diff --git a/reframe/frontend/cli.py b/reframe/frontend/cli.py index 45345b82a7..4f149431f6 100644 --- a/reframe/frontend/cli.py +++ b/reframe/frontend/cli.py @@ -439,13 +439,12 @@ def main(): help='Use a login shell for job scripts' ) + # Parse command line + options = argparser.parse_args() if len(sys.argv) == 1: argparser.print_help() sys.exit(1) - # Parse command line - options = argparser.parse_args() - # First configure logging with our generic configuration so as to be able # to print pretty messages; logging will be reconfigured by user's # configuration later From 780ca9ca069820ee6daf1bbef7bc0cea77046eb5 Mon Sep 17 00:00:00 2001 From: sarafael Date: Fri, 5 Feb 2021 13:23:45 +0100 Subject: [PATCH 7/8] add argcomplete on requirements --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index cc28e16ad4..a01ade12ac 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,4 +6,5 @@ pytest-parallel==0.1.0 coverage==5.3 setuptools==50.3.0 wcwidth==0.2.5 +argcomplete==1.12.2 #+pygelf%pygelf==0.3.6 From 3fb62fec40801c11c5196bf4c29d4c9c876d5c0b Mon Sep 17 00:00:00 2001 From: Vasileios Karakasis Date: Sat, 6 Feb 2021 23:57:35 +0100 Subject: [PATCH 8/8] Add documentation about auto-completion + scripts for enabling it --- docs/started.rst | 10 ++++++++ etc/reframe_completion.bash | 46 ++++++++++++++++++++++++++++++++++++ etc/reframe_completion.fish | 17 +++++++++++++ etc/reframe_completion.tcsh | 1 + reframe/frontend/argparse.py | 1 + 5 files changed, 75 insertions(+) create mode 100644 etc/reframe_completion.bash create mode 100644 etc/reframe_completion.fish create mode 100644 etc/reframe_completion.tcsh diff --git a/docs/started.rst b/docs/started.rst index 1ea87f041d..7cd1d958e9 100644 --- a/docs/started.rst +++ b/docs/started.rst @@ -90,6 +90,16 @@ All you need is a Python 3.6+ installation with ``pip``: For previous ReFrame versions you should install its requirements using ``pip install -r requirements.txt`` in a Python virtual environment. +Enabling auto-completion +------------------------ + +.. versionadded:: 3.4.1 + +You can enable auto-completion for ReFrame by sourcing in your shell the corresponding script in ``/etc/reframe_completion.``. +Auto-completion is supported for Bash, Tcsh and Fish shells. + + + Running the Unit Tests ---------------------- diff --git a/etc/reframe_completion.bash b/etc/reframe_completion.bash new file mode 100644 index 0000000000..57077f6a7d --- /dev/null +++ b/etc/reframe_completion.bash @@ -0,0 +1,46 @@ + +# Run something, muting output or redirecting it to the debug stream +# depending on the value of _ARC_DEBUG. +# If ARGCOMPLETE_USE_TEMPFILES is set, use tempfiles for IPC. +__python_argcomplete_run() { + if [[ -z "${ARGCOMPLETE_USE_TEMPFILES-}" ]]; then + __python_argcomplete_run_inner "$@" + return + fi + local tmpfile="$(mktemp)" + _ARGCOMPLETE_STDOUT_FILENAME="$tmpfile" __python_argcomplete_run_inner "$@" + local code=$? + cat "$tmpfile" + rm "$tmpfile" + return $code +} + +__python_argcomplete_run_inner() { + if [[ -z "${_ARC_DEBUG-}" ]]; then + "$@" 8>&1 9>&2 1>/dev/null 2>&1 + else + "$@" 8>&1 9>&2 1>&9 2>&1 + fi +} + +_python_argcomplete() { + local IFS=$'\013' + local SUPPRESS_SPACE=0 + if compopt +o nospace 2> /dev/null; then + SUPPRESS_SPACE=1 + fi + COMPREPLY=( $(IFS="$IFS" \ + COMP_LINE="$COMP_LINE" \ + COMP_POINT="$COMP_POINT" \ + COMP_TYPE="$COMP_TYPE" \ + _ARGCOMPLETE_COMP_WORDBREAKS="$COMP_WORDBREAKS" \ + _ARGCOMPLETE=1 \ + _ARGCOMPLETE_SUPPRESS_SPACE=$SUPPRESS_SPACE \ + __python_argcomplete_run "$1") ) + if [[ $? != 0 ]]; then + unset COMPREPLY + elif [[ $SUPPRESS_SPACE == 1 ]] && [[ "${COMPREPLY-}" =~ [=/:]$ ]]; then + compopt -o nospace + fi +} +complete -o nospace -o default -o bashdefault -F _python_argcomplete reframe diff --git a/etc/reframe_completion.fish b/etc/reframe_completion.fish new file mode 100644 index 0000000000..34768ff362 --- /dev/null +++ b/etc/reframe_completion.fish @@ -0,0 +1,17 @@ + +function __fish_reframe_complete + set -x _ARGCOMPLETE 1 + set -x _ARGCOMPLETE_DFS \t + set -x _ARGCOMPLETE_IFS \n + set -x _ARGCOMPLETE_SUPPRESS_SPACE 1 + set -x _ARGCOMPLETE_SHELL fish + set -x COMP_LINE (commandline -p) + set -x COMP_POINT (string length (commandline -cp)) + set -x COMP_TYPE + if set -q _ARC_DEBUG + reframe 8>&1 9>&2 1>/dev/null 2>&1 + else + reframe 8>&1 9>&2 1>&9 2>&1 + end +end +complete -c reframe -f -a '(__fish_reframe_complete)' diff --git a/etc/reframe_completion.tcsh b/etc/reframe_completion.tcsh new file mode 100644 index 0000000000..9560251631 --- /dev/null +++ b/etc/reframe_completion.tcsh @@ -0,0 +1 @@ +complete "reframe" 'p@*@`python-argcomplete-tcsh "reframe"`@' ; diff --git a/reframe/frontend/argparse.py b/reframe/frontend/argparse.py index 3bf4e08819..0c02d53c8f 100644 --- a/reframe/frontend/argparse.py +++ b/reframe/frontend/argparse.py @@ -258,6 +258,7 @@ def parse_args(self, args=None, namespace=None): `add_argument()` call. If no default value was specified either, the attribute will be set to `None`.''' + # Enable auto-completion argcomplete.autocomplete(self._holder) # We always pass an empty namespace to our internal argparser and we do