#! /bin/bash # # Copyright © 2007,2008 Neil Moore # All rights reserved. # # Redistribution and use, with or without modification, are permitted # provided that the following conditions are met: # # 1. Redistributions must retain the above copyright notice, this list # of conditions and the following disclaimer. # # 2. The name of the author may not be used to endorse or promote # products derived from this script without specific prior written # permission. # # THIS SCRIPT IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # Expand a bash completion from the command line. Call with the full # command line as a single argument. Prints the list of completions for # the last word, one per line. # BUGS: # # Assumes the first word in the argument is the relevant command to use for # completion; this might not be the case when builtins or command substitution # is involved. # # Ignores complete options (-o) for function/command completions (-F/-C). # # Tries to complete the last word even if there was trailing space. The # script should instead complete from a new, empty word. if [ -r /etc/bash_completion ]; then . /etc/bash_completion fi # Set up completion variables: needed if we are going to call a -F or -C # completion. COMP_LINE="$1" COMP_POINT=${#COMP_LINE} COMP_WORDS=($COMP_LINE) COMP_CWORD=$((${#COMP_WORDS[*]} - 1)) cmd=${COMP_WORDS[0]} if [[ ${#COMP_WORDS[*]} > 1 ]]; then # Current and previous words curr=${COMP_WORDS[COMP_CWORD]} if [[ $COMP_CWORD == 0 ]]; then prev="" else prev=${COMP_WORDS[COMP_CWORD - 1]} fi # Completion command ccmd=$(complete -p "$cmd" 2>/dev/null) if [[ $? -eq 0 ]]; then # Call completion functions and commands manually. We can't # use compgen -F/-C because it resets COMP_CWORD to -1. Fregex=' -F ([^ ]+)' Cregex=' -C ([^ ]+)' Oregex='^complete (.*) [^ ]+$' if [[ $ccmd =~ $Fregex ]]; then "${BASH_REMATCH[1]}" "$cmd" "$curr" "$prev" elif [[ $ccmd =~ $Cregex ]]; then scr="${BASH_REMATCH[1]}" # Store the output in COMPREPLY, one element per line. IFS=$'\n' COMPREPLY=($( "$scr" "$cmd" "$curr" "$prev" )) else [[ $ccmd =~ $Oregex ]] || exit 1 ARGS="${BASH_REMATCH[1]}" # Store the output of compgen in COMPREPLY, one element # per line. However, we must set IFS back to its # original value so that the complete arguments are # split properly. O="$IFS" IFS=$'\n' COMPREPLY=($( IFS="$O"; compgen $ARGS "$curr" )) fi else IFS=$'\n' COMPREPLY=($( compgen -o bashdefault -f "$curr" )) fi else IFS=$'\n' COMPREPLY=($( compgen -o bashdefault -c "$cmd" )) fi for x in "${COMPREPLY[@]}"; do echo "$x" done