Search code examples
bashtab-completion

Why does just adding strings to COMPREPLY result into tab completion not matching correctly?


I am currently working on a path shortcut manager CLI, which enables users to abbreviate paths with short labels. To make those labels easy to use, I wanted my custom bash commands to autocomplete the labels by pressing tab. This is the broad structure of my solution:

function _custom_command(){
    # load labels into COMPREPLY
}
complete -F _custom_command custom_command

Currently, my completion function loads every single existing label into COMPREPLY, which means that those should get matched for tab completion. Given this situation, the tab completion does not work properly. Even though I am typing a prefix of a label as the first argument of my custom command, it never does get matched / replaced by the label.

This behaviour can be reproduced by the following simple code:

function hello(){
    echo "hello"
}

function _hello(){
    COMPREPLY=("hey")
    COMPREPLY+=("cool")
}

complete -F _hello hello

This seems to be the root of the problem, as adding two strings to COMPREPLY leads to the same behaviour specified above.

E.g.:

$hello c[Tab]
cool hey

Am I missing any options / specification of complete or is my usage of this command faulty? Also feel free to leave any feedback on this question, as is it my first. Thank you :)


Solution

  • From the documentation of progammable completion:

    After these matches have been generated, any shell function or command specified with the -F and -C options is invoked. When the command or function is invoked, the COMP_LINE, COMP_POINT, COMP_KEY, and COMP_TYPE variables are assigned values as described above (see Bash Variables). If a shell function is being invoked, the COMP_WORDS and COMP_CWORD variables are also set. When the function or command is invoked, the first argument ($1) is the name of the command whose arguments are being completed, the second argument ($2) is the word being completed, and the third argument ($3) is the word preceding the word being completed on the current command line. No filtering of the generated completions against the word being completed is performed; the function or command has complete freedom in generating the matches.

    So anything you put in COMPREPLY will be used as a possible completion. If you only want words that begin with what the user has typed, the function is supposed to do that filtering itself. The word being completed will be in $2, you can use that.