Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash Autocompletion with multiple argument values per argument

I'm trying to implement tab completion for the first time - it has to work in GIT Bash and its for a python script that i wrote (done with argparser)

The script basically has two arguments --option_a and --option_b and they accept both single and multiple argument values, e.g. script --option_a steak or script --option_a steak burger pizza are both valid. There's still a set of choices to choose from though, so you cannot enter whatever you like.

I already got most of it done:

What's already done

OPTION_A_VALUES="bread pizza steak burger"
OPTION_B_VALUES="apple banana"

_autocomplete () {                
  COMPREPLY=()   
  local cur=${COMP_WORDS[COMP_CWORD]}
  local prev=${COMP_WORDS[COMP_CWORD-1]}

  case "$prev" in
   "--option_a")
       COMPREPLY=( $( compgen -W "$OPTION_A_VALUES" -- $cur ) )  
       return 0 
       ;;
  "--option_b")
        COMPREPLY=( $( compgen -W "$OPTION_B_VALUES" -- $cur ) )
        return 0 
       ;;
 esac

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

complete -o nospace -F _autocomplete script

script is the alias for the python script.

  • $ script --option_a bur<TAB>
    
    This evaluates to script --option_a burger. Excellent!

The problem

Basically what i still need to do is supporting autocompletion for all the possible argument values - currently it stops after completing one:

  • $ script --option_a burger pi<TAB>
    
    This does not evaluate to script --option_a burger pizza yet :( Bad!

Of course, after completing to pizza and typing --<TAB><TAB> the script should again suggest --option_a --option_b

Any help on how to modify my autocomplete script to make this work would be greatly appreciated! Thanks in advance.

like image 757
Manu Avatar asked Sep 11 '25 15:09

Manu


1 Answers

You can try this

_autocomplete () {
  COMPREPLY=()
  local cur=${COMP_WORDS[COMP_CWORD]}
  local prev=${COMP_WORDS[COMP_CWORD-1]}

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

  case "$prev" in
   --option_a|bread|pizza|steak|burger)
       COMPREPLY=( $( compgen -W "$OPTION_A_VALUES" -- $cur ) )
       return 0
       ;;
   --option_b|apple|banana)
       COMPREPLY=( $( compgen -W "$OPTION_B_VALUES" -- $cur ) )
       return 0
       ;;
 esac

}

The idea is

If the cur starts with -, the compgen gets option_a option_b immediately

If the prev is one of --option_a bread pizza steak burger, it gets the values again

like image 125
nhatnq Avatar answered Sep 13 '25 07:09

nhatnq