From 396f21901160afd54adf21970f22f92c38006bef Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Fri, 18 Aug 2023 16:53:00 -0700 Subject: completion: add alias handling Bash completion is now smarter about handling aliases. In particular, if all completions for some input command are aliased to the same thing, we'll just complete with that thing. If you've already *typed* the full alias for a command, we'll complete the alias. So, for example, here there's more than one real command involved, so all aliases are shown: ```console $ spack con concretise concretize config containerise containerize ``` Here, there are two possibilities: `concretise` and `concretize`, but both map to `concretize` so we just complete that: ```console $ spack conc concretize ``` And here, the user has already typed `concretis`, so we just go with it as there is only one option: ```console spack concretis concretise ``` --- share/spack/bash/spack-completion.bash | 46 ++++++++++++++++++++++++++++++++ share/spack/qa/completion-test.sh | 6 +++++ share/spack/spack-completion.bash | 48 ++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+) (limited to 'share') diff --git a/share/spack/bash/spack-completion.bash b/share/spack/bash/spack-completion.bash index 0d740101fa..c0ead13813 100755 --- a/share/spack/bash/spack-completion.bash +++ b/share/spack/bash/spack-completion.bash @@ -139,6 +139,9 @@ _bash_completion_spack() { $subfunction COMPREPLY=($(compgen -W "$SPACK_COMPREPLY" -- "$cur")) fi + + # if every completion is an alias for the same thing, just return that thing. + _spack_compress_aliases } # Helper functions for subcommands @@ -328,6 +331,49 @@ _spacktivate() { _spack_env_activate } +# Simple function to get the spack alias for a command +_spack_get_alias() { + local possible_alias="${1-}" + local IFS=";" + + # spack aliases are a ;-separated list of :-separated pairs + for item in $SPACK_ALIASES; do + # maps a possible alias to its command + eval "local real_command=\"\${item#*${possible_alias}:}\"" + if [ "$real_command" != "$item" ]; then + SPACK_ALIAS="$real_command" + return + fi + done + + # no alias found -- just return $1 + SPACK_ALIAS="$possible_alias" +} + +# If all commands in COMPREPLY alias to the same thing, set COMPREPLY to +# just the real command, not the aliases. +_spack_compress_aliases() { + # if there's only one thing, don't bother compressing aliases; complete the alias + if [ "${#COMPREPLY[@]}" == "1" ]; then + return + fi + + # get the alias of the first thing in the list of completions + _spack_get_alias "${COMPREPLY[0]}" + local first_alias="$SPACK_ALIAS" + + # if anything in the list would alias to something different, stop + for comp in "${COMPREPLY[@]:1}"; do + _spack_get_alias "$comp" + if [ "$SPACK_ALIAS" != "$first_alias" ]; then + return + fi + done + + # all commands alias to first alias; just return that + COMPREPLY=("$first_alias") +} + # Spack commands # # Everything below here is auto-generated. diff --git a/share/spack/qa/completion-test.sh b/share/spack/qa/completion-test.sh index 9559c56d0a..494a1b1235 100755 --- a/share/spack/qa/completion-test.sh +++ b/share/spack/qa/completion-test.sh @@ -61,6 +61,12 @@ contains 'python' _spack_completions spack extensions '' contains 'hdf5' _spack_completions spack -d install --jobs 8 '' contains 'hdf5' _spack_completions spack install -v '' +title 'Testing alias handling' +contains 'concretize' _spack_completions spack c +contains 'concretise' _spack_completions spack c +contains 'concretize' _spack_completions spack conc +does_not_contain 'concretise' _spack_completions spack conc + # XFAIL: Fails for Python 2.6 because pkg_resources not found? #contains 'compilers.py' _spack_completions spack unit-test '' diff --git a/share/spack/spack-completion.bash b/share/spack/spack-completion.bash index 22365df54a..91e34045b4 100755 --- a/share/spack/spack-completion.bash +++ b/share/spack/spack-completion.bash @@ -139,6 +139,9 @@ _bash_completion_spack() { $subfunction COMPREPLY=($(compgen -W "$SPACK_COMPREPLY" -- "$cur")) fi + + # if every completion is an alias for the same thing, just return that thing. + _spack_compress_aliases } # Helper functions for subcommands @@ -328,9 +331,54 @@ _spacktivate() { _spack_env_activate } +# Simple function to get the spack alias for a command +_spack_get_alias() { + local possible_alias="${1-}" + local IFS=";" + + # spack aliases are a ;-separated list of :-separated pairs + for item in $SPACK_ALIASES; do + # maps a possible alias to its command + eval "local real_command=\"\${item#*${possible_alias}:}\"" + if [ "$real_command" != "$item" ]; then + SPACK_ALIAS="$real_command" + return + fi + done + + # no alias found -- just return $1 + SPACK_ALIAS="$possible_alias" +} + +# If all commands in COMPREPLY alias to the same thing, set COMPREPLY to +# just the real command, not the aliases. +_spack_compress_aliases() { + # if there's only one thing, don't bother compressing aliases; complete the alias + if [ "${#COMPREPLY[@]}" == "1" ]; then + return + fi + + # get the alias of the first thing in the list of completions + _spack_get_alias "${COMPREPLY[0]}" + local first_alias="$SPACK_ALIAS" + + # if anything in the list would alias to something different, stop + for comp in "${COMPREPLY[@]:1}"; do + _spack_get_alias "$comp" + if [ "$SPACK_ALIAS" != "$first_alias" ]; then + return + fi + done + + # all commands alias to first alias; just return that + COMPREPLY=("$first_alias") +} + # Spack commands # # Everything below here is auto-generated. +SPACK_ALIASES="concretise:concretize;containerise:containerize;rm:remove" + _spack() { if $list_options -- cgit v1.2.3-60-g2f50