I have a command line tool which takes arguments in an three-part form:
$ t first_second_third
I have a set of valid values for first
, a set of valid values for second
, and a set of valid values for third
. I want to use Bash complete functionality to complete each part of the option value, as in this example:
$ t [tab][tab] # shows options for first part
walk run skip bike
$ t w[tab] # completes first part and appends delimiter
$ t walk_[tab][tab] # shows options for second part
home work park
$ t walk_h[tab] # completes second part and appends delimiter
$ t walk_home_[tab][tab] # shows options for second part
morning afternoon evening
$ t walk_home_a[tab] # completes second part and appends space
$ t walk_home_afternoon
I have this code:
_tool () {
local cur="${COMP_WORDS[COMP_CWORD]}"
local first="walk run skip bike"
local second="home work park"
local third="morning afternoon evening"
case "${cur}" in
*_*_*)
COMPREPLY=( $(compgen -W "${third}" -- "") ); return 0;;
*_*)
COMPREPLY=( $(compgen -W "${second}" -S "_" -- ${cur}) ); compopt -o nospace; return 0;;
*)
COMPREPLY=( $(compgen -W "${first}" -S "_" -- ${cur}) ); compopt -o nospace; return 0;;
esac
}
complete -F _tool t
The first clause works great; nothing special there. But the second clause gives me no options or completions.
$ t [tab][tab]
bike_ run_ skip_ walk_
$ t b[tab]
$ t bike_[tab][tab] # nothing but bells
I replaced the second clause with the following (i.e. I replaced ${cur}
with an empty string in the COMPREPLY
call):
COMPREPLY=( $(compgen -W "${second}" -S "_" -- "") ); compopt -o nospace; return 0;;
I get a list of all options on the command line, but no completions.
$ t bike_[tab][tab]
home_ park_ work_
$ t bike_h[tab][tab]
home_ park_ work_
$ t bike_ho[tab][tab]
home_ park_ work_
I thought there might be some bad interaction with ${cur}
and the COMPREPLY
word list, so I changed the second clause again, adding a prefix which matches the first part of the current word:
local prefix=( $(expr "${cur}" : '\(.*_\)') )
COMPREPLY=( $(compgen -W "${second}" -P "${prefix}" -S "_" -- "") ); compopt -o nospace; return 0;;
This did not help much. With ${cur}
still in the COMPREPLY
command, I got no options or completions again. With an empty string instead, I got the full option (not just the curent part). But, pressing tab would erase what is typed.
$ t bike_[tab][tab]
bike_home_ bike_park_ bike_work_
$ t bike_ho[tab]
$ t bike_ # "ho" was erased
Of course, I have the same problem with the third part, too.
This is similar to another Bash complete question, but I do not want to list every possible permutation of the values and they are not formatted as filenames (not sure if the filename pattern makes a difference).
Thanks for the help!
--ap
Bash completion is a bash function that allows you to auto complete commands or arguments by typing partially commands or arguments, then pressing the [Tab] key. This will help you when writing the bash command in terminal.
The programmable completion feature in Bash permits typing a partial command, then pressing the [Tab] key to auto-complete the command sequence. [1] If multiple completions are possible, then [Tab] lists them all.
Linux commands are executed on Terminal by pressing Enter at the end of the line. You can run commands to perform various tasks, from package installation to user management and file manipulation.
I was able to create what you want. See my code below:
_tool () {
local cur="${COMP_WORDS[COMP_CWORD]}"
local first="walk run skip bike"
case "${cur}" in
*_*_*)
local firstsecond=`echo ${cur} | awk -F '_' '{print $1"_"$2}'`
local third="${firstsecond}_morning ${firstsecond}_afternoon ${firstsecond}_evening"
COMPREPLY=( $(compgen -W "${third}" -- ${cur}) ); return 0;;
*_*)
local firstcomp=`echo ${cur} | awk -F '_' '{print $1}'`
local second="${firstcomp}_home ${firstcomp}_work ${firstcomp}_park"
COMPREPLY=( $(compgen -W "${second}" -S "_" -- ${cur}) ); compopt -o nospace; return 0;;
*)
COMPREPLY=( $(compgen -W "${first}" -S "_" -- ${cur}) ); compopt -o nospace; return 0;;
esac
}
complete -F _tool t
I am not much familiar with autocomplete, and it was the first time I used compgen
or complete
, so I'm not sure I can answer your questions about the theory of the thing. I can tell you what I did, in case it helps you understand how this badly-documented functions work.
First I tried to understand what you had. I reproduced your problems successfully. Then I had this idea that, even though you didn't want to list every permutation yourself in the code, I could use the local variables to mimic as if it had. The first thing I did was to get the "first" element after we had the first underscore, and add the second element to it, and feed that to compgen. To my surprise, it worked fine. Then I tried to do the same to the 3rd level... and then problems started. I found out that the second part was not working as fine as I had imagined. after completing the first word, I would get the suggestions for the second; after chosing one word to be the second and hit [TAB], the first underscore would disappear.
$ t [tab][tab] # shows options for first part
bike_ run_ skip_ walk_
$ t w[tab] # completes first part and appends delimiter
$ t walk_[tab][tab] # shows options for second part
walk_home_ walk_park_ walk_work_
$ t walk_h[tab] # completes second part and appends delimiter
$ t walk_home_[tab][tab] # screws up with it
$ t walkhome_
I tried moving the underscore into awk, to no success:
local first=`echo ${cur} | awk -F '_' '{print $1"_"}'`
local second="${first}home ${first}work ${first}park"
For some reason I had to change the variable name to something different from "first", and it started working. Then, on the 3rd element I had the same problem that you described last, where whatever I typed in the 3rd element would disappear, but [tab][tab] would give me the options:
$ t walk_home_[tab][tab] # shows options for second part
morning afternoon evening
$ t walk_home_aft[tab] # erases what I typed
$ t walk_home_
To which I added ${cur}
to compgen in the 3rd word and it worked. This is just a summary of what I did... but I got a working version, so I'm happy with it. :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With