I'm writing a bash command line tool for which I want to enable bash completion using completely.
I have the following bash completion. After I eval "$(./cli completion)"
(which outputs the below), completions work fine in bash:
#!/usr/bin/env bash
# This bash completions script was generated by
# completely (https://github.com/dannyben/completely)
# Modifying it manually is not recommended
_cli_completions() {
local cur=${COMP_WORDS[COMP_CWORD]}
local comp_line="${COMP_WORDS[*]:1}"
case "$comp_line" in
'completions'*) COMPREPLY=($(compgen -W "--help -h" -- "$cur")) ;;
'download'*) COMPREPLY=($(compgen -W "--force --help -f -h" -- "$cur")) ;;
''*) COMPREPLY=($(compgen -W "--help --version -h -v completions download" -- "$cur")) ;;
esac
}
complete -F _cli_completions cli
However, they do not work right in ZSH. I have identified the problem to be that COMP_WORDS
is not an array when I'm inside ZSH, but it is inside bash. This then breaks the line local comp_line="${COMP_WORDS[*]:1}"
.
E.g. in the situation ./cli download <tab>
, comp_line
should be download
, but in ZSH it's /cli download
(only the .
is removed), so I always end up in the last case ''*
.
I'm using ZSH 5.8 with Oh-My-ZSH. Bash completions generally seem to work in ZSH. Oh-My-ZSH sets up completions using
fpath=($ZSH/functions $ZSH/completions $fpath)
autoload -U compaudit compinit
I have tried setting setopt shwordsplit
, hoping that that would cause COMP_WORDS
to be treated as an array, but it had no effect.
Is there a ZSH configuration that I can change to make this completion script work? Or is there a bash compatible change to the completion script that would make it work in both shells?
This issue is discussed in this Github ticket.
ZSH should be totally capable of handling bash completions when it is configured to do so by adding these two lines in ~/.zshrc
:
# Load bash completion functions
autoload -Uz +X compinit && compinit
autoload -Uz +X bashcompinit && bashcompinit
In addition, the script in question, generated by the completely gem, seems to have a problem.
Replacing *
with @
in the below line seems to make it work on both bash and zsh.
local comp_line="${COMP_WORDS[*]:1}" # broken
local comp_line="${COMP_WORDS[@]:1}" # works
This change is now a part of both bashly and completely gems.