# bash completion for java, javac and javadoc

# available path elements completion
have java && {
_java_path()
{
    cur=${cur##*:}
    _filedir '@(jar|zip)'
}

# exact classpath determination
_java_find_classpath()
{
    local i

    # search first in current options
    for (( i=1; i < COMP_CWORD; i++ )); do
        if [[ "${COMP_WORDS[i]}" == -@(cp|classpath) ]]; then
            classpath=${COMP_WORDS[i+1]}
            break
        fi
    done

    # default to environment
    [ -z "$classpath" ] && classpath=$CLASSPATH

    # default to current directory
    [ -z "$classpath" ] && classpath=.
}

# exact sourcepath determination
_java_find_sourcepath()
{
    local i

    # search first in current options
    for (( i=1; i < COMP_CWORD; i++ )); do
        if [[ "${COMP_WORDS[i]}" == -sourcepath ]]; then
            sourcepath=${COMP_WORDS[i+1]}
            break
        fi
    done

    # default to classpath
    if [ -z "$sourcepath" ]; then
        _java_find_classpath
        sourcepath=$classpath
    fi
}

# available classes completion
_java_classes()
{
    local classpath i

    # find which classpath to use
    _java_find_classpath

    # convert package syntax to path syntax
    cur=${cur//.//}
    # parse each classpath element for classes
    for i in ${classpath//:/ }; do
        if [ -r $i ] && [[ "$i" == *.@(jar|zip) ]]; then
            if type zipinfo &>/dev/null; then
                COMPREPLY=( "${COMPREPLY[@]}" $( zipinfo -1 \
                    "$i" "$cur*" 2>/dev/null | \
                    grep '^[^$]*\.class$' ) )
            else
                COMPREPLY=( "${COMPREPLY[@]}" $( jar tf "$i" \
                    "$cur" | grep '^[^$]*\.class$' ) )
            fi

        elif [ -d $i ]; then
            i=${i%/}

            # See Debian bug #496828
            COMPREPLY=( "${COMPREPLY[@]}" $( find "$i" -type f \
                -maxdepth 1 -path "$i/$cur*.class" 2>/dev/null | \
                grep -v "\\$" | sed -e "s|^$i/||" ) )

            # FIXME: if we have foo.class and foo/, the completion
            # returns "foo/"... how to give precedence to files
            # over directories?
        fi
    done

    # remove class extension
    COMPREPLY=( ${COMPREPLY[@]%.class} )
    # convert path syntax to package syntax
    COMPREPLY=( ${COMPREPLY[@]//\//.} )
}

# available packages completion
_java_packages()
{
    local sourcepath i

    # find which sourcepath to use
    _java_find_sourcepath

    # convert package syntax to path syntax
    cur=${cur//.//}
    # parse each sourcepath element for packages
    for i in ${sourcepath//:/ }; do
        if [ -d $i ]; then
            COMPREPLY=( "${COMPREPLY[@]}" $( command ls -F -d \
                $i/$cur* 2>/dev/null | sed -e 's|^'$i'/||' ) )
        fi
    done
    # keep only packages
    COMPREPLY=( $( echo "${COMPREPLY[@]}" | tr " " "\n" | grep "/$" ) )
    # remove packages extension
    COMPREPLY=( ${COMPREPLY[@]%/} )
    # convert path syntax to package syntax
    cur=${COMPREPLY[@]//\//.}
}

# java completion
#
_java()
{
    local cur prev i

    COMPREPLY=()
    cur=`_get_cword`
    prev=${COMP_WORDS[COMP_CWORD-1]}

    for ((i=1; i < $COMP_CWORD; i++)); do
        case ${COMP_WORDS[$i]} in
            -cp|-classpath)
            ((i++)) # skip the classpath string.
            ;;
            -*)
            # this is an option, not a class/jarfile name.
            ;;
            *)
            # once we've seen a class, just do filename completion
            _filedir
            return 0
            ;;
        esac
    done

    case $prev in
        -@(cp|classpath))
            _java_path
            return 0
            ;;
    esac

    if [[ "$cur" == -* ]]; then
        # relevant options completion
        COMPREPLY=( $( compgen -W '-client -hotspot -server -classic \
            -cp -classpath -D -verbose -verbose:class \
            -verbose:gc -version:jni -version \
            -showversion -? -help -X -jar \
            -ea -enableassertions -da -disableassertions \
            -esa -enablesystemassertions \
            -dsa -disablesystemassertions ' -- "$cur" ) )
    else
        if [[ "$prev" == -jar ]]; then
            # jar file completion
            _filedir jar
        else
            # classes completion
            _java_classes
        fi
    fi
}
complete -F _java $filenames java
}

have javadoc &&
_javadoc()
{
    COMPREPLY=()
    local cur prev

    cur=`_get_cword`
    prev=${COMP_WORDS[COMP_CWORD-1]}

    case $prev in
        -@(overview|helpfile|stylesheetfile))
            _filedir
            return 0
            ;;
        -d)
            _filedir -d
            return 0
            ;;
        -@(classpath|bootclasspath|docletpath|sourcepath|extdirs))
            _java_path
            return 0
            ;;
    esac

    if [[ "$cur" == -* ]]; then
        # relevant options completion
        COMPREPLY=( $( compgen -W '-overview -public -protected \
            -package -private -help -doclet -docletpath \
            -sourcepath -classpath -exclude -subpackages \
            -breakiterator -bootclasspath -source -extdirs \
            -verbose -locale -encoding -J -d -use -version \
            -author -docfilessubdirs -splitindex \
            -windowtitle -doctitle -header -footer -bottom \
            -link -linkoffline -excludedocfilessubdir \
            -group -nocomment -nodeprecated -noqualifier \
            -nosince -nodeprecatedlist -notree -noindex \
            -nohelp -nonavbar -quiet -serialwarn -tag \
            -taglet -tagletpath -charset -helpfile \
            -linksource -stylesheetfile -docencoding' -- "$cur" ) )
    else
        # source files completion
        _filedir java
        # packages completion
        _java_packages
    fi
} &&
complete -F _javadoc $filenames javadoc

have javac &&
_javac()
{
    COMPREPLY=()
    local cur prev

    cur=`_get_cword`
    prev=${COMP_WORDS[COMP_CWORD-1]}

    case $prev in
        -d)
            _filedir -d
            return 0
            ;;
        -@(classpath|bootclasspath|sourcepath|extdirs))
            _java_path
            return 0
            ;;
    esac

    if [[ "$cur" == -* ]]; then
        # relevant options completion
        COMPREPLY=( $( compgen -W '-g -g:none -g:lines -g:vars\
            -g:source -O -nowarn -verbose -deprecation -classpath\
            -sourcepath -bootclasspath -extdirs -d -encoding -source\
            -target -help' -- "$cur" ) )
    else
        # source files completion
        _filedir java
    fi
} &&
complete -F _javac $filenames javac

# Local variables:
# mode: shell-script
# sh-basic-offset: 4
# sh-indent-comment: t
# indent-tabs-mode: nil
# End:
# ex: ts=4 sw=4 et filetype=sh
