Bash completions with equals sign and enumerable flag values
Asked Answered
G

2

2

I'm trying to construct a bash completion routine that will suggest command lines flags and suitable flag values. For example in the below fstcompose command I would like the competition routine to first suggest the compose_filter= flag, and then suggest possible values from [alt_sequence, auto, match, sequence].

fstcompose --compose_filter=

For any flags that do not have a set of associated of values I want the competition to fall back to the default mode of suggesting paths or files.

The one issue I'm facing is the = equal sign treated as an individual token and is set as the prev COMP_WORD. Is there a technique for detecting the whole flag before and including the previous = character ? Or is there a better way of implementing this type completion of flag with enumerable values? Below is a sample of the completion routine I'm working with.

_fstcompose()
{
  local cur prev opts filters pprev
  COMPREPLY=()
  cur="${COMP_WORDS[COMP_CWORD]}"
  prev="${COMP_WORDS[COMP_CWORD-1]}"
  opts="--compose_filter= --connect"
  filters="alt_sequence auto match sequence"

  if [[ ${cur} == -* ]] ; then
  COMPREPLY=($(compgen -W "${opts}" -- ${cur}))
  return 0
  fi

  if [[ ${prev} == "--compose_filter=" ]] ; then
  COMPREPLY=($(compgen -W "${filters}" -- ${cur}))
  return 0
  fi
  _filedir
}
complete -o nospace -F _fstcompose fstcompose
Giorgia answered 18/2, 2011 at 11:44 Comment(2)
I made a similar question and an answer for it here. I could not mark this one as a duplicate.Slung
Minimal answer hereInglorious
R
3

Your first return 0 prevents the second if from being evaluated. Try using a case statement ordered from most-specific to least-specific or at least order your if statements that way.

Since "=" is included in $COMP_WORDBREAKS, ${prev} is "--compose_filter" without the "=".

If you remove "=" from $COMP_WORDBREAKS then --compose_filter is still ${cur} rather than ${prev}. Doing so without preserving and restoring its value will break other completions.

I'm not sure what other problems there may be.

You can pepper your function with echo statements that are redirected to another terminal to aid in debugging. For example:

echo "cur: $cur, prev: $prev" > /dev/pts/2
Rauwolfia answered 18/2, 2011 at 14:44 Comment(0)
B
0

this will help some people i think. The below code should work (wrote on the fly)

have fstcompose &&{
    function elementExists(){
        local i isRunning result
        i=0
        isRunning=1
        result=0
        #~ for i in ${opts_with_equal[@]}; do
        while [ "$isRunning" -eq 1 ]; do
            if [ "$i" -ge "${#opts_with_equal[@]}" ]; then
                isRunning=0
            elif [ "${opts_with_equal[$i]}" == "$1" ]; then
                result=1
                isRunning=0
            fi
            ((i++))
        done
        echo $result
    }
    function _fstcompose(){
        local prev cur opts opts_with_equal isEqualOptions
        COMPREPLY=()
        _get_comp_words_by_ref -n : cur prev
        opts="--compose_filter --connect"
        opts_with_equal=(--compose_filter)

        case ${cur} in
            '--compose_filter'*)
                prev="${cur%%=*}="
                cur=${cur#*=}
                COMPREPLY=( ${prev}$(compgen -W "alt_sequence auto match sequence" -- "${cur}") )
                return 0
                ;;
        esac

        if [[ "${cur}" != -* ]]; then
            _filedir
        else
            isEqualOptions=$(elementExists "${cur}")
            if [ "${isEqualOptions:-0}" -eq 1 ]; then
                COMPREPLY=( $(compgen -W "${opts}" -S '=' -- "${cur}") )
            else
                COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
            fi
        fi

    }
    complete -o nospace -F _fstcompose fstcompose
}
# Local variables:
# mode: shell-script
# sh-basic-offset: 4
# sh-indent-comment: t
# indent-tabs-mode: nil
# End:
# ex: ts=4 sw=4 et filetype=sh

Note: opts_with_equal it is an array in this example it contain only one parameter. Put into each parameter who use '='

Barnebas answered 20/1, 2012 at 22:54 Comment(1)
What is that have in the beginning? I do not have such a command or function in my system.Slung

© 2022 - 2024 — McMap. All rights reserved.