Enable composer bash completion on Ubuntu
The composer bash completion from iArren is fantastic, but is doesn’t work out of the box on Ubuntu (14.04). I found out this is due to an old version of bash-completion
on Ubuntu and with a simple fix I got it working.
The cool thing about iArren’s bash completion is not only the ablity to
autocomplete the composer methods (install
, update
and so on) but it can
query packages too. It uses composer show -a
to get a list of all known
packages. Thereafter, it lists all available versions of that package.
The bash-completion project ships with some functions the completion
files can use. A recent version comes with a function called
_init_completion()
, but is not included in /etc/bash_completion
for some
kind of reason.
The problem here is the composer autocomplete uses the _init_completion()
and it’s not available on my machine! Other Ubuntu users have a similar issue
and apparently this is due to an old version of bash or bash-completion
shipped with 14.04. I am not sure if this is still the case for 14.10.
The simple fix is to load the function yourself and source it from your
.bashrc
. Create a file ~/.bash_completion
with this content:
## Added because old bash-completion versions doesn't have the
## _init_completion() function
# Initialize completion and deal with various general things: do file
# and variable completion where appropriate, and adjust prev, words,
# and cword as if no redirections exist so that completions do not
# need to deal with them. Before calling this function, make sure
# cur, prev, words, and cword are local, ditto split if you use -s.
#
# Options:
# -n EXCLUDE Passed to _get_comp_words_by_ref -n with redirection chars
# -e XSPEC Passed to _filedir as first arg for stderr redirections
# -o XSPEC Passed to _filedir as first arg for other output redirections
# -i XSPEC Passed to _filedir as first arg for stdin redirections
# -s Split long options with _split_longopt, implies -n =
# @return True (0) if completion needs further processing,
# False (> 0) no further processing is necessary.
#
_init_completion()
{
local exclude flag outx errx inx OPTIND=1
while getopts "n:e:o:i:s" flag "$@"; do
case $flag in
n) exclude+=$OPTARG ;;
e) errx=$OPTARG ;;
o) outx=$OPTARG ;;
i) inx=$OPTARG ;;
s) split=false ; exclude+== ;;
esac
done
# For some reason completion functions are not invoked at all by
# bash (at least as of 4.1.7) after the command line contains an
# ampersand so we don't get a chance to deal with redirections
# containing them, but if we did, hopefully the below would also
# do the right thing with them...
COMPREPLY=()
local redir="@(?([0-9])<|?([0-9&])>?(>)|>&)"
_get_comp_words_by_ref -n "$exclude<>&" cur prev words cword
# Complete variable names.
if [[ $cur =~ ^(\$\{?)([A-Za-z0-9_]*)$ ]]; then
[[ $cur == *{* ]] && local suffix=} || local suffix=
COMPREPLY=( $( compgen -P ${BASH_REMATCH[1]} -S "$suffix" -v -- \
"${BASH_REMATCH[2]}" ) )
return 1
fi
# Complete on files if current is a redirect possibly followed by a
# filename, e.g. ">foo", or previous is a "bare" redirect, e.g. ">".
if [[ $cur == $redir* || $prev == $redir ]]; then
local xspec
case $cur in
2'>'*) xspec=$errx ;;
*'>'*) xspec=$outx ;;
*'<'*) xspec=$inx ;;
*)
case $prev in
2'>'*) xspec=$errx ;;
*'>'*) xspec=$outx ;;
*'<'*) xspec=$inx ;;
esac
;;
esac
cur="${cur##$redir}"
_filedir $xspec
return 1
fi
# Remove all redirections so completions don't have to deal with them.
local i skip
for (( i=1; i < ${#words[@]}; )); do
if [[ ${words[i]} == $redir* ]]; then
# If "bare" redirect, remove also the next word (skip=2).
[[ ${words[i]} == $redir ]] && skip=2 || skip=1
words=( "${words[@]:0:i}" "${words[@]:i+skip}" )
[[ $i -le $cword ]] && cword=$(( cword - skip ))
else
i=$(( ++i ))
fi
done
[[ $cword -eq 0 ]] && return 1
prev=${words[cword-1]}
[[ $split ]] && _split_longopt && split=true
return 0
}
This is extracted from the source file hosted on Github. Now, load this
file from the ~/.bashrc
and include ~/.bash_completion
only when the
_init_completion()
is unknown:
# make sure we have the _init_completion() function
if type -t _init_completion | grep -q '^function$'; then
. ~/.bash_completion
fi
The last step is to download the composer autocompletion file and save it
as /etc/bash_completion.d/composer
. Now reload bash (with source ~/.bashrc
) and you’re good to go!