The whole issue is discussed here and here. Since no one involved in those discussions was 100% sure about the issue, I'm asking for help here. (For the sake of completeness, I'll start from the beginning.)
Let's say we have two scripts (sourced in ~/.zshrc
) that set up some completion logic for ZSH. Now based on what I learned, at some point in the script you need to call compinit
and bashcompinit
like this (copied from NVM completion script)
if [[ -n ${ZSH_VERSION-} ]]; then
autoload -U +X compinit && if [[ ${ZSH_DISABLE_COMPFIX-} = true ]]; then
compinit -u
else
compinit
fi
autoload -U +X bashcompinit && bashcompinit
fi
Apparently, according to ZSH manual, bashcompinit
must be called after compinit
, (not sure if it's relevant). Now the problem is, the moment the second script calls compinit
, the logic coming from the first script is gone (i.e. no completion from the first script is available). A simple snippet to reproduce this is (copied from here):
complete -W "hello world" one
one <tab> # to see autocomplete working
compinit
one <tab> # to see autocomplete NOT working
Someone proposed (here) something like below to solve the issue (by checking if compinit
is already called before calling it):
if [[ -n ${ZSH_VERSION-} ]]; then
if ! command -v compinit > /dev/null; then
autoload -U +X compinit && if [[ ${ZSH_DISABLE_COMPFIX-} = true ]]; then
compinit -u
else
compinit
fi
fi
autoload -U +X bashcompinit && bashcompinit
fi
Another idea could be to call compinit
and bashcompinit
not in the custom completion script, but in ~/.zshrc
(which hurts the automated installation process for tools like NVM).
I'd like to know what is the correct way to set up completion in general (or specifically with respect to calling compinit
).
Thanks.
Let's say we have two scripts (sourced in
~/.zshrc
) that set up some completion logic for ZSH. Now based on what I learned, at some point in the script you need to callcompinit
andbashcompinit
Nope, that's not what your script should be doing. Not your script, but the user should call compinit
(in their .zshrc
file) to enable Zsh's more advanced completion system.
Additionally, it should be called only once for each shell instance.
A more basic, Bash-like completion system is enabled by default in Zsh, but it's pretty much deprecated. Don’t bother with it; the vast majority of your users have compinit
in their dotfiles, which provides a much better user exerience, even though it's not enabled by default. Yes, Zsh ships with poor, archaic defaults in the name of backwards compatibility. Nearly all its newer features are opt-in, unfortunately.
This is the proper way to add native completion functions to Zsh:
/usr/local/share/zsh/site-functions
, as this is in every Zsh user's $fpath
by default.
.zshrc
file:
fpath=(
/path/to/dir/containing/your/completion/functions
$fpath
)
.zshrc
file (or scripts that they source
from there), after setting the $fpath
, in the order given:
autoload -Uz compinit
compinit
Many Zsh frameworks & plugin managers include a call to compinit
on startup. Calling compinit
more than once increases startup time significantly and erases completion functions added programmatically. You might want to make your users aware of this, to save yourself needless bug reports.compinit
will then automatically pick up your completion functions from the user’s $fpath
.
Apparently, according to ZSH manual,
bashcompinit
must be called aftercompinit
, (not sure if it's relevant).
Yes, it's relevant, but no, not in the way you think it is. Among other things, bashcompinit
defines the function complete
, which emulates Bash’s complete
builtin and can be used to add Bash completions to Zsh. Like compinit
, bashcompinit
is meant to be called only once per shell.
If your package supplies Bash completions only, then you can do the following to install them in Zsh:
autoload -Uz compinit bashcompinit
compinit
bashcompinit
However, Zsh's completion is much richer and more powerful than Bash’s. Whenever possible, I would recommend supplying a native Zsh completion function. Here's a good guide on how to write Zsh completion functions.