Any plugin or script using bashcompinit & complete to define completion won't work after sourcing antigen
Description
The google-cloud-sdk adds the following snippet to the end of your .zshrc:
# The next line updates PATH for the Google Cloud SDK.
if [ -f '/Users/segevfiner/google-cloud-sdk/path.zsh.inc' ]; then . '/Users/segevfiner/google-cloud-sdk/path.zsh.inc'; fi
# The next line enables shell command completion for gcloud.
if [ -f '/Users/segevfiner/google-cloud-sdk/completion.zsh.inc' ]; then . '/Users/segevfiner/google-cloud-sdk/completion.zsh.inc'; fi
Their completion script is using bashcompinit and complete to define completions. This translates to a bunch of compdef calls like this:
compdef '_bash_complete -o nospace -o default -F _python_argcomplete' gcloud
If this happens after antigen apply, the compdef is ignored: https://github.com/zsh-users/antigen/blob/64de2dcd95d6a8e879cd2244c763d99f0144e78e/bin/antigen.zsh#L1843
Which is weird...? Why?
Moving it between sourcing antigen and antigen apply causes antigen to defer the compdef call using: https://github.com/zsh-users/antigen/blob/64de2dcd95d6a8e879cd2244c763d99f0144e78e/bin/antigen.zsh#L64
Which causes it to save it as a single string inside the array, losing the quoting and the fact that it has multiple arguments, and then the subsequent compdef call here doesn't work:
https://github.com/zsh-users/antigen/blob/64de2dcd95d6a8e879cd2244c763d99f0144e78e/bin/antigen.zsh#L802
As it needs to call compdef with two arguments but calls it with one.
# Wrong (Caused by the code deferring compdef)
compdef '_bash_complete -o nospace -o default -F _python_argcomplete gcloud'
# Correct
compdef '_bash_complete -o nospace -o default -F _python_argcomplete' gcloud
In general, I think this might happen with any compdef call at all, as they all use more than one argument.
Also note that nvm generates the following:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
And its completion script calls compinit, which antigen isn't trying to defer/skip, which will then undo the effect of deferring compdef (nvm-sh/nvm/bash_completion:89-95) getting the completion to be defined correctly but hurting shell startup performance due to multiple compinit invocations. Making it not call compinit by commenting that out, causes the same kind of issue with its own defined completions not loading as happens with the google-cloud-sdk, although nvm has completion available in the Zsh default completion and an oh-my-zsh plugin with completions that will end up getting used instead.
You can load such completions before sourcing antigen, which will make it call compdef before antigen tries to defer it, which seems to work, but there might be a reason for this attempted deferral of compdef calls.
I'm not really sure how to resolve this as Zsh doesn't support nested arrays or something obvious to store an array of such multiple argument commands...
P.S. As antigen doesn't appear to be maintained, this is unlikely to be resolved, any recommendations for an alternative to antigen (With good oh-my-zsh plugins support, good performance, and being actually maintained), workaround, fix to apply locally, or anything else?
Steps to reproduce
Minimal steps to reproduce this behavior. Example:
1 - Use any `.zshrc` that calls `compdef` between sourcing antigen and `antigen apply`. (`antigen reset` if needed, not sure when antigen invalidates its cache)
2 - Check `$_comps[command]` (e.g. `$_comps[gcloud]`) to see if the completion is defined properly.
Expected behavior:
- Deferred `compdef` completion to be defined correctly.
Software version
antigen versionAntigen v2.2.3 (ff391b5) Revision date: 2018-01-02 13:19:57 +0100zsh --versionzsh 5.8 (x86_64-apple-darwin21.0)uname -aDarwin Segevs-MacBook-Pro.local 21.4.0 Darwin Kernel Version 21.4.0: Fri Mar 18 00:46:32 PDT 2022; root:xnu-8020.101.4~15/RELEASE_ARM64_T6000 arm64
Configuration
.zshrc
source /opt/homebrew/share/antigen/antigen.zsh
FPATH="$(brew --prefix)/share/zsh/site-functions:${FPATH}"
LESS=-FR
antigen use oh-my-zsh
antigen bundle git
antigen bundle fzf
antigen bundle zsh-users/zsh-completions
antigen bundle zsh-users/zsh-autosuggestions
antigen bundle zsh-users/zsh-syntax-highlighting
eval "$(starship init zsh)"
export ZSH_HIGHLIGHT_HIGHLIGHTERS=(main brackets)
# The next line updates PATH for the Google Cloud SDK.
if [ -f '/Users/segevfiner/google-cloud-sdk/path.zsh.inc' ]; then . '/Users/segevfiner/google-cloud-sdk/path.zsh.inc'; fi
# The next line enables shell command completion for gcloud.
if [ -f '/Users/segevfiner/google-cloud-sdk/completion.zsh.inc' ]; then . '/Users/segevfiner/google-cloud-sdk/completion.zsh.inc'; fi
antigen apply
More information
😢
So maybe using some Zsh specific magic:
$ A=("Foo Bar" Qux)
$ B=${(@qq)A}
$ printf "%s\n" ${(Q)${(z)B}}
Foo Bar
Qux
+1
Terraform completion is another one impacted by this bug.
~/.zshrc
[...]
autoload -U +X bashcompinit && bashcompinit
complete -o nospace -C "$(which terraform)" terraform
complete above internally runs:
compdef '_bash_complete -o nospace -C /path/to/terraform' terraform
When running the complete command manually on my shell, completions get loaded, but not when they are loaded from ~/.zshrc
+1
I'm a shell noob, but here's how I would describe it:
Antigen causes complete command to not work in .zshrc file.
complete works when run in zsh, but not when I put it in my .zshrc file. There, it runs, gives a 0 exit status, but then autocompletion doesn't work. Examples: AWS CLI v2 autocomplete, Terraform autocomplete.
The interwebs suggested various problems with autoload, bashcompinit, etc, but none of those resolved my problem. In the end, it was simple: the AWS complete command works when I put it in my .bashrc. So then I went back to my .zshrc and kept removing things until AWS complete worked. It only worked after removing Antigen itself.