#! /bin/bash
#
# Copyright © 2007,2008 Neil Moore <neil@s-z.org>
# 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

