Can a Bash tab-completion script be used in zsh?

BashZshTab Completion

Bash Problem Overview


I have a Bash tab-completion script for Apache's Hadoop. Normally, I use zsh as my day-to-day shell. It tends to be pretty bash-like when I need it to be, but it looks like the tab-completion systems are radically different between them. Is there a simple way to "convert" the existing bash-tab-completion definitions to work in zsh? I don't want to invest a ton of time in this, but if it's easy I'd save a moderate amount of effort.

Bash Solutions


Solution 1 - Bash

autoload bashcompinit
bashcompinit
source /path/to/your/bash_completion_file

Solution 2 - Bash

autoload -U +X compinit && compinit
autoload -U +X bashcompinit && bashcompinit
source /path/to/your/bash_completion_script

I am running zsh zsh 5.0.2 (x86_64-apple-darwin13.0) without any ~/.zshrc and the above sequence worked in a freshly spawned zsh shell.

Thanks to git-completion.bash script for the hint :D


Read-on for more details on above 3 lines:

Bash has awesome in built auto completion support but the bash autocomplete scripts don't work directly zsh as zsh environment doesn't have the essential bash autocomplete helper functions like compgen, complete. It does so in an effort to keep zsh session fast.

These days zsh is shipped with appropriate completion scripts like compinit and bashcompinit which have the required functions to support bash autocomplete scripts.

autoload <func_name>: Note that autoload is defined in zsh and not bash. autoload looks for a file named in the directory paths returned by fpath command and marks a function to load the same when it is first invoked.

  • -U: Ignore any aliases when loading a function like compinit or bashcompinit
  • +X: Just load the named function fow now and don't execute it

For example on my system echo $fpath returns /usr/share/zsh/site-functions and /usr/share/zsh/5.0.5/functions and both compinit and bashcompinit are available at /usr/share/zsh/5.0.5/functions.

Also for most people may be only autoload -U +X bashcompinit && bashcompinit is required because some other script like git autocomplete or their own ~/.zshrc may be doing autoload -U +X compinit && compinit, but it's safe to just run both of them.

Solution 3 - Bash

From this page (dated 2010/01/05):

>Zsh can handle bash completions functions. The latest development version of zsh has a function bashcompinit, that when run will allow zsh to read bash completion specifications and functions. This is documented in the zshcompsys man page. To use it all you need to do is run bashcompinit at any time after compinit. It will define complete and compgen functions corresponding to the bash builtins.

Solution 4 - Bash

For zsh use:

  • compdef
  • compadd

My example:

# bash completion for bxrun (/home/ecuomo/projects/bashx/bxrun)
_bxrun_methods() {
	grep "^\s*\(function\s\+\)\?__.\+()\s*{.*$" "${1}" | while read line ; do
		echo "$line" | sed "s/()\s*{.*//g" | sed "s/\s*\(function\s\+\)\?__//g"
	done
}
_bxrun_lst() {
	if [ -d "/home/ecuomo/projects/bashx/src/actions" ]; then
		for f in /home/ecuomo/projects/bashx/src/actions/* ; do
			if [ -f "${f}" ]; then
				basename "${f}" | sed 's/\..*$//g'
			fi
		done
	fi
	_bxrun_methods "/home/ecuomo/projects/bashx/bxrun"
	_bxrun_methods "/home/ecuomo/projects/bashx/src/bashx.sh"
}
_bxrun() {
	local cur
	COMPREPLY=()
	cur=${COMP_WORDS[COMP_CWORD]}
	COMPREPLY=( $( compgen -W '$( _bxrun_lst )' -- $cur  ) )
}
_bxrun_zsh() {
	compadd `_bxrun_lst`
}
if type complete >/dev/null 2>/dev/null; then
	# bash
	complete -F _bxrun bxrun
else if type compdef >/dev/null 2>/dev/null; then
	# zsh
	compdef _bxrun_zsh bxrun
fi; fi

Source: My code https://github.com/reduardo7/bashx

Solution 5 - Bash

I am running Antigen as a Oh-My-Zsh plugin manager. I had a few bash completion scripts written by coworkers that I wanted to load into Zsh with a simple source /path/to/completion.

I had some trouble, because it seems like either Antigen or OMZ (hard to tell) concern themselves with only loading completion scripts from their plugins. I finally got around this by autoloading bashcompinit and compinit after antigen apply. Simply autoloading bashcompinit wasn't enough.

source ~/.antigen/antigen.zsh
antigen use oh-my-zsh
antigen apply

autoload -U +X compinit && compinit
autoload -U +X bashcompinit && bashcompinit

source /path/to/bash_completion

Antigen creates its .zcompdump file at $ANTIGEN_COMPDUMP which for me was ~/.antigen/.zcompdump

The re-invoke of compinit and bashcompinit create a second .zcompdump at $HOME/.zcompdump

That seems to all work out, because I am able to use the completions set up by /path/to/bash_completion. I've deleted both .zcompdump files a few times to make sure they're regenerated and seems to work.

I've had to rm the .zcompdump files a few times after a machine reboot because of errors thrown when trying to tab complete, but I'm unsure if that's due to this set up or something else. rm ~/.zcompdump && rm $ANTIGEN_COMPDUMP and a new shell fixes that for me.

Versions used at time of writing:

Antigen = v2.2.3 = d3d4ee0
Oh-my-zsh = c3b072e
Zsh = 5.3

Solution 6 - Bash

@JatinKumar's answer got me on the right track, but I had to use complete instead of source. So all together:

autoload -Uz compinit && compinit
autoload -U +X bashcompinit && bashcompinit

complete -C /usr/local/bin/terraform terraform
complete -C /usr/local/aws/bin/aws_completer aws
complete -C /usr/local/bin/az az

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCodererView Question on Stackoverflow
Solution 1 - BashfreestylerView Answer on Stackoverflow
Solution 2 - BashJatin KumarView Answer on Stackoverflow
Solution 3 - BashDennis WilliamsonView Answer on Stackoverflow
Solution 4 - BashEduardo CuomoView Answer on Stackoverflow
Solution 5 - BashWalter WilfingerView Answer on Stackoverflow
Solution 6 - BashjschmitterView Answer on Stackoverflow