Make zsh complete arguments from a file

2019-03-13 12:50发布

问题:

zsh is great but its completion system is very diverse. And the documentation lacks good examples. Is there a template for completing for a specific application. The completion would get its match data from a file, separated by newlines?

I tried modifying an older example of mine that takes match data "live":

~ % cat .zsh/completers/_jazzup 
#compdef jazz_up
_arguments "2: :(`mpc lsplaylists|sed -e 's# #\\\\ #g'`)"

I could supply cat my_file there instead of mpc invocation and so on but would there be a more elegant way to do this simple task? And that completion there is placement-specific: can you provide an example where zsh would attempt to complete at any point after the program name is recognized?

The match data will have whitespaces and so on, the completion should escape the WS. Example of that:

Foo bar
Barbaric
Get it (42)

Now if that completion would be configured for a command Say, we should get this kind of behaviour out of zsh:

$ Say Fo<TAB>
$ Say Foo\ bar
$ Say Ge<TAB>
$ Say Get\ it\ \(42\)

回答1:

Simple completion needs are better addressed with _describe, it pairs an array holding completion options and a description for them (you can use multiple array/description pairs, check the manual).

(_arguments is great but too complex.)

[...]

First create a file

echo "foo\nbar\nbaz\nwith spac e s\noh:noes\noh\:yes" >! ~/simple-complete

Then create a file _simple somewhere in your $fpath:

#compdef simple

# you may wish to modify the expansion options here
# PS: 'f' is the flag making one entry per line
cmds=( ${(uf)"$(< ~/simple-complete)"} ) 

# main advantage here is that it is easy to understand, see alternative below
_describe 'a description of the completion options' cmds

# this is the equivalent _arguments command... too complex for what it does
## _arguments '*:foo:(${cmds})'

then

function simple() { echo $* }
autoload _simple # do not forget BEFORE the next cmd! 
compdef _simple simple # binds the completion function to a command

simple [TAB]

it works. Just make sure the completion file _simple is placed somewhere in your fpath.

Notice that : in the option list is supposed to be used for separating an option from their (individual) description (oh:noes). So that won't work with _describe unless you quote it (oh\:yes). The commented out _arguments example will not use the : as a separator.



回答2:

Without changing anything further in .zshrc (I already have autoload -Uz compinit compinit) I added the following as /usr/local/share/zsh/site-functions/_drush

#compdef drush
_arguments "1: :($(/usr/local/bin/aliases-drush.php))"

Where /usr/local/bin/aliases-drush.php just prints a list of strings, each string being a potential first argument for the command drush. You could use ($(< filename)) to complete from filename.

I based this on https://unix.stackexchange.com/a/458850/9452 -- it's surprising how simple this is at the end of the day.