Search code examples
fishtab-completion

How to add tab-completion to command with two arguments (and tab complete both)?


Let's have a command command. This command has an option -o that takes 2 arguments. I'd like to add tab-completion to both of those arguments.

I've tried

complete -c command -x -s o -a "complete first arg"

I but cannot add tab-completion to the second argument.


I would like to autocomplete the command when no option is specified. this work fine:

complete -c command -a "no option completion"

but when it I hit tab after the first argument in -o option, those ^ completions are shown.

like this:

command -o "fist" <tab>
no
option
completion

if I cannot add completion for the second argument I'd like to at least remove those completions.


Solution

  • This command has an option -o that takes 2 arguments.

    That's quite unusual. Are you sure about that?

    Usually, you'll either have options that take one argument, or options that act as "flags" and change all other arguments. So you would just check their presence.

    "-o" "-old-style" options also aren't as common as "--gnu-style" long options or "-s" short options, so I suggest double-checking.

    complete -c command -a "no option completion"

    This means to offer "no", "option" and "completion" if the command is "command".

    There is no condition specified, so these are always offered.

    What you want is to use the "--condition" (or "-n") option to complete. This takes script (as a string) that is executed. If it returns 0 (i.e. true), the corresponding completion (the rest of that complete invocation - the option and arguments) is offered.

    Something like

    # The first condition is just to see that `commandline -opc`, 
    # which tokenizes (-o) all tokens of the current process (-p) 
    # up to (but not including) the cursor (-c)
    # returns just one token - which must be the command.
    #
    # Alternatively this condition could also be 
    # the inverse of the other conditions
    # (offer this if nothing else would be)
    complete -c command -n 'test (count (commandline -opc)) -lt 2' -a 'stuff for no argument'
    
    # The first argument to the option we handle via "-a" to the option
    complete -c command -o the-option -a 'the first argument'
    
    # The second argument needs to be offered
    # if the second-to-last token is the option.
    #
    # This is incomplete, because theoretically a token that
    # _looks_ like the option could be offered as an argument to _another_ option.
    complete -c command -n 'set -l option (commandline -opc)[-2]; test "$option" = "-o"' -a 'the second argument'