From d82e13bb5119fadbeeb7a90d6ece2384abd23db1 Mon Sep 17 00:00:00 2001 From: Vladimir Zhelezov Date: Mon, 14 Dec 2020 07:37:48 +0100 Subject: [PATCH] Add an automatic check for required option argument Get rid of manually listing unhandled long options: Instead of listing options requiring an argument one by one in the case statement in _hledger_compreply_optarg(), the option completion lists are searched and if the option does require an argument an empty COMPREPLY is send. Short options are uncounted for and still need a manual entry. This necessitated setting $subcommandOptions beforehand, so it is moved back where it was -- in the sub-command loop in main(). --- shell-completion/hledger-completion.bash | 49 ++++++++++++++------- shell-completion/hledger-completion.bash.m4 | 49 ++++++++++++++------- 2 files changed, 64 insertions(+), 34 deletions(-) diff --git a/shell-completion/hledger-completion.bash b/shell-completion/hledger-completion.bash index 3310c4f52..00aa0222e 100644 --- a/shell-completion/hledger-completion.bash +++ b/shell-completion/hledger-completion.bash @@ -23,6 +23,7 @@ _hledger_completion_function() { esac local subcommand + local subcommandOptions local i for ((i=1; i<${#words[@]}; i++)); do subcommand=${words[i]} @@ -40,6 +41,16 @@ _hledger_completion_function() { )" return 0 fi + if [[ $cur == -* ]]; then + # Replace dashes with underscores and use indirect expansion + subcommandOptions=_hledger_complist_options_${subcommand//-/_} + _hledger_compreply "$(_hledger_compgen "${!subcommandOptions}")" + + # Suspend space on completion of long options requiring an argument + [[ ${COMPREPLY[0]} == --*= ]] && compopt -o nospace + + return 0 + fi break done @@ -62,18 +73,6 @@ _hledger_completion_function() { return 0 fi - if [[ $cur == -* ]]; then - local subcommandOptions - # Replace dashes with underscores and use indirect expansion - subcommandOptions=_hledger_complist_options_${subcommand//-/_} - _hledger_compreply "$(_hledger_compgen "${!subcommandOptions}")" - - # Suspend space on completion of long options requiring an argument - [[ ${COMPREPLY[0]} == --*= ]] && compopt -o nospace - - return 0 - fi - # Set this from here on because queries tend to have lots of special chars # TODO: better handling of special characters compopt -o filenames @@ -208,7 +207,7 @@ _hledger_compgen() { # Try required option argument completion. Set COMPREPLY and return 0 on # success, 1 if option doesn't require an argument or out of context _hledger_compreply_optarg() { - local optionIndex=$((cword - 1)) + local option=${words[cword - 1]} local match=$cur local wordlist @@ -217,12 +216,12 @@ _hledger_compreply_optarg() { match="" # Once input is present, cword is incremented so we compensate elif [[ $prev == = ]]; then - optionIndex=$((cword - 2)) + option=${words[cword - 2]} fi - [[ ${words[optionIndex]} == -* ]] || return + [[ $option == -* ]] || return - case ${words[optionIndex]} in + case $option in --alias) compopt -o nospace -o filenames _hledger_compreply "$( @@ -270,10 +269,26 @@ _hledger_compreply_optarg() { _hledger_compreply "$(compgen -W "$wordlist" -- "$match")" ;; # Argument required, but no handler (yet) - -b|--begin|-e|--end|-p|--period|--depth|--drop) + -b|-e|-p) _hledger_compreply "" ;; + # Check if an unhandled long option requires an argument *) + local optionList argRequired + + if [[ -n $subcommandOptions ]]; then + optionList=${!subcommandOptions} + else + optionList=$_hledger_complist_generic_options + fi + + while IFS= read -r argRequired; do + if [[ $argRequired == "$option=" ]]; then + _hledger_compreply "" + return 0 + fi + done <<< "$optionList" + return 1 ;; esac diff --git a/shell-completion/hledger-completion.bash.m4 b/shell-completion/hledger-completion.bash.m4 index b63ba91a0..cf6749c6d 100644 --- a/shell-completion/hledger-completion.bash.m4 +++ b/shell-completion/hledger-completion.bash.m4 @@ -23,6 +23,7 @@ _hledger_completion_function() { esac local subcommand + local subcommandOptions local i for ((i=1; i<${#words[@]}; i++)); do subcommand=${words[i]} @@ -40,6 +41,16 @@ _hledger_completion_function() { )" return 0 fi + if [[ $cur == -* ]]; then + # Replace dashes with underscores and use indirect expansion + subcommandOptions=_hledger_complist_options_${subcommand//-/_} + _hledger_compreply "$(_hledger_compgen "${!subcommandOptions}")" + + # Suspend space on completion of long options requiring an argument + [[ ${COMPREPLY[0]} == --*= ]] && compopt -o nospace + + return 0 + fi break done @@ -62,18 +73,6 @@ _hledger_completion_function() { return 0 fi - if [[ $cur == -* ]]; then - local subcommandOptions - # Replace dashes with underscores and use indirect expansion - subcommandOptions=_hledger_complist_options_${subcommand//-/_} - _hledger_compreply "$(_hledger_compgen "${!subcommandOptions}")" - - # Suspend space on completion of long options requiring an argument - [[ ${COMPREPLY[0]} == --*= ]] && compopt -o nospace - - return 0 - fi - # Set this from here on because queries tend to have lots of special chars # TODO: better handling of special characters compopt -o filenames @@ -208,7 +207,7 @@ _hledger_compgen() { # Try required option argument completion. Set COMPREPLY and return 0 on # success, 1 if option doesn't require an argument or out of context _hledger_compreply_optarg() { - local optionIndex=$((cword - 1)) + local option=${words[cword - 1]} local match=$cur local wordlist @@ -217,12 +216,12 @@ _hledger_compreply_optarg() { match="" # Once input is present, cword is incremented so we compensate elif [[ $prev == = ]]; then - optionIndex=$((cword - 2)) + option=${words[cword - 2]} fi - [[ ${words[optionIndex]} == -* ]] || return + [[ $option == -* ]] || return - case ${words[optionIndex]} in + case $option in --alias) compopt -o nospace -o filenames _hledger_compreply "$( @@ -270,10 +269,26 @@ _hledger_compreply_optarg() { _hledger_compreply "$(compgen -W "$wordlist" -- "$match")" ;; # Argument required, but no handler (yet) - -b|--begin|-e|--end|-p|--period|--depth|--drop) + -b|-e|-p) _hledger_compreply "" ;; + # Check if an unhandled long option requires an argument *) + local optionList argRequired + + if [[ -n $subcommandOptions ]]; then + optionList=${!subcommandOptions} + else + optionList=$_hledger_complist_generic_options + fi + + while IFS= read -r argRequired; do + if [[ $argRequired == "$option=" ]]; then + _hledger_compreply "" + return 0 + fi + done <<< "$optionList" + return 1 ;; esac