0

I've tried (and failed miserably) to write a bash completion script that can take arbitrarily deep autocompletion. I didn't make it past two :-\ despite reading multiple SO posts and some blogs and docs. For example, I can get to:

$ seuss tweedle beetle

but can't get to seuss tweedle beetle puddle

I don't even really need functions at the end of each complete, just the options themselves. I tried modifying scripts from the following posts but everything I did would break.

Nested bash autocompletion script

How do I autocomplete nested, multi-level subcommands?

Here's what I've tried:

_seuss()
{
    local one two three four

    one=${COMP_WORDS[COMP_CWORD]}
    two=${COMP_WORDS[COMP_CWORD-1]}
    three=${COMP_WORDS[COMP_CWORD-2]}
    four=${COMP_WORDS[COMP_CWORD-3]}

    case ${COMP_CWORD} in
        1)
            COMPREPLY=($(compgen -W "fox tweedle" -- ${one}))
            ;;
        2)
            case ${two} in
                fox)
                    COMPREPLY=($(compgen -W "socks" -- ${one}))
                    case ${three} in
                        socks)
                            COMPREPLY=($(compgen -W "box clocks" -- ${one}))
                            ;;
                        box)
                            COMPREPLY=($(compgen -W "knox" -- ${one}))
                            ;;
                    esac
                    ;;
                tweedle)
                    COMPREPLY=($(compgen -W "beetle poodle" -- ${one}))
                    case ${three} in
                        beetle)
                            COMPREPLY=($(compgen -W "puddle battle" -- ${one}))
                            ;;
                        poddle)
                            COMPREPLY=($(compgen -W "noodle" -- ${one}))
                            ;;
                    esac
                    ;;
            esac
            ;;
        *)
            COMPREPLY=()
            ;;
    esac
}

complete -F _seuss seuss

But this only results in:

$ seuss fox sox

I can't seem to get box clocks.

Spanky
  • 5,608
  • 10
  • 39
  • 45
  • i know nothing about `seuss` so could you elaborate a bit more what's the expected behavior? – pynexj Jan 08 '21 at 02:45
  • Seuss is just an arbitrary example that doesn't exist. The expected behavior is: `seuss fox sox box|clocks` – Spanky Jan 08 '21 at 17:33
  • are the autocomplete candidates determined by the position? or by the previous argument? or by all the previous arguments? – pynexj Jan 09 '21 at 01:58

1 Answers1

1

There's a problem with the logic. I suggest you use a printf function for debugging purpose and wrap your head around what is actually happening. I just added the following code as the last line of your _seuss function:

printf "\n*** DEBUG ***\nCOMP_CWORD: $COMP_CWORD\nOne: $one\nTwo: $two\nThree: $three\nFour: $four\nCOMP_LINE: $COMP_LINE"

Now, as you call $ seuss fox socks <TAB> you can see how all variables are filling up:

*** DEBUG ***
COMP_CWORD: 3
One: 
Two: socks
Three: fox
Four: seuss
COMP_LINE: seuss fox socks

So, as you can see, there is no rule set for when COMP_CWORD is 3. Just a plain old COMPREPLY=() which means no suggestions will be printed. Check the logic again using this printf as a helper. Happy coding!

EDIT: Since there are no special complexities in the case tree you asked, I guess this one should do the work:

_seuss()
{
    case $3 in
        seuss)      COMPREPLY=($(compgen -W "fox tweedle" -- "$2"))     ;;
        fox)        COMPREPLY=($(compgen -W "socks" -- "$2"))           ;;
        socks)      COMPREPLY=($(compgen -W "box clocks" -- "$2"))      ;;
        box)        COMPREPLY=($(compgen -W "knox" -- "$2"))            ;;
        tweedle)    COMPREPLY=($(compgen -W "beetle poodle" -- "$2"))   ;;
        beetle)     COMPREPLY=($(compgen -W "puddle battle" -- "$2"))   ;;
        poddle)     COMPREPLY=($(compgen -W "noodle" -- "$2"))          ;;
        *)          COMPREPLY=()                                        ;;
    esac
}

complete -F _seuss seuss

Here $2 means the current word being completed and $3 is the previous word.

Pedram
  • 921
  • 1
  • 10
  • 17