# Gentoo Linux Bash Shell Command Completion
#
# Copyright 1999-2013 Gentoo Authors
# Distributed under the terms of the GNU General Public License, v2 or later

source "/usr/share/bash-completion/helpers/gentoo-common.sh"

#
# emerge completion command
#
_emerge()
{
    local c cur prev cond prepend
    local words stophere i x
    local action actionpos sysactions pkgpos
    local portdir=$(_portdir -o)
    COMPREPLY=()
    local cur=${COMP_WORDS[COMP_CWORD]}
    local prev=${COMP_WORDS[COMP_CWORD-1]}
    local numwords=${#COMP_WORDS[*]}
    local curword=${COMP_CWORD}
    local opts=()

    if [[ ${prev} == '>' || ${prev} == '<' ]] ; then
        COMPREPLY=($(compgen -f -- ${cur}))
        return 0
    fi

    if [[ ${cur} =~ ^@ ]] ; then
        local SET_LIST=($(emerge --list-sets))
        COMPREPLY=($(compgen -W '${SET_LIST[@]/#/@}' ${cur}))
        return 0
    fi

    # find action
    for x in ${COMP_LINE} ; do
        if [[ ${x} =~ ^(system|world)$ ]] || [[ ${x} =~ -[CPcs] ]] || \
            [[ ${x} =~ --(clean|config|depclean|deselect|info|metadata|prune|rage-clean|regen|resume|search|sync|unmerge) ]]
        then
            action=${x}
            break
        fi
    done

    if [[ -n ${action} ]]; then
        for ((i = 0; i < ${numwords}; i++ )); do
            if [[ ${COMP_WORDS[${i}]} == "${action}" ]]; then
                actionpos=${i}
                pkgpos=$((actionpos + 1))
                break
            fi
        done

        if [[ ${action} == -* && ${action} != --* ]] ; then
            case "${action}" in
            -*C*) action='--unmerge' ;;
            -*P*) action='--prune' ;;
            -*c*) action='--clean' ;;
            -*s*) action='--search' ;;
            esac
        fi
    else
        for ((i = 1; i < ${numwords}; i++ )); do
            if [[ ! ${COMP_WORDS[$i]} == -* ]]; then
                pkgpos=${i}
                break
            fi
        done
        [[ -z ${pkgpos} ]] && pkgpos=${numwords}
    fi

    # Handle special cases.
    if [[ ${action} == "--search" ]] || [[ ${COMP_LINE} == *" "-@(S|-searchdesc)* ]] || \
        [[ ${COMP_LINE} == *" "-@(V|-version)* ]] || [[ ${action} == "--metadata" ]]
    then
        unset COMPREPLY
        return 0
    elif [[ ${COMP_LINE} == *" "-@(h|-help)* ]] ; then
        unset COMPREPLY
        [[ ${curword} -eq 2 ]] && COMPREPLY=($(compgen -W 'system world --sync' -- ${cur}))
        return 0
    fi

    # Complete on options.
    if [[ ${cur} == -* ]]; then
        # If a resume option was specified, it needs special handling.
        if [[ ${COMP_LINE} =~ --(resume|skipfirst) ]] ; then
            if [[ ${cur} == --* ]]; then
                opts=( --ask --pretend --resume --skipfirst )
            elif [[ ${cur} == -* ]]; then
                [[ ${COMP_LINE} =~ --(ask|pretend) ]] && opts=( -a -p )
            fi
        elif [[ ${cur} == --* ]]; then
            # Complete on long options.
            opts=(
                --alphabetical
                --ask
                --autounmask-write --autounmask-keep-keywords --autounmask-continue={y,n}
                --autounmask-backtrack --autounmask-only --autounmask-unrestricted-atoms
                --autounmask-keep-masks --autounmask-license={y,n} --autounmask-use={y,n}
                --accept-properties --accept-restrict --alert --alert={y,n}
                --ask-enter-invalid
                --binpkg-changed-deps --binpkg-respect-use
                --buildpkg-exclude
                --buildpkg --buildpkgonly
                --backtrack=
                --changelog --clean --color={y,n} --columns --complete-graph --config --check-news
                --complete-graph-if-new-use={y,n} --complete-graph-if-new-ver={y,n}
                --config-root
                --changed-deps --changed-deps-report --changed-slot --changed-use
                --debug --deep --depclean --deselect
                --depclean-lib-check
                --dynamic-deps={y,n}
                --emptytree
                --exclude
                --fail-clean --fetch-all-uri --fetchonly --fuzzy-search
                --getbinpkg --getbinpkgonly
                --ignore-default-opts --ignore-built-slot-operator-deps={y,n} --ignore-soname-deps={y,n}
                --ignore-world --implicit-system-deps={y,n} --info
                --jobs= --load-average=
                --keep-going
                --misspell-suggestions={y,n} --metadata
                --newrepo --newuse --noconfmem --nodeps --noreplace --nospinner
                --oneshot --onlydeps --onlydeps-with-ideps --onlydeps-with-rdeps
                --pretend --prune --package-moves --pkg-format
                --quiet --quiet-build --quiet-fail --quiet-repo-display --quiet-unmerge-warn
                --rage-clean --regex-search-auto={y,n} --read-news
                --reinstall=changed-use --reinstall-atoms --regen --rebuild-exclude --rebuild-ignore --rebuild-if-new-slot
                --rebuild-if-new-rev --rebuild-if-new-ver --rebuild-if-unbuilt --rebuilt-binaries
                --search --search-index --search-similarity
                --sync --select --selective
                --sync-submodule={glsa,news,profiles}
                --tree
                --unordered-display --use-ebuild-visibility --useoldpkg-atoms --usepkg-exclude-live
                --unmerge --update --update-if-installed --upgradeonly --usepkg --usepkgonly --usepkg-exclude
                --verbose --verbose-conflicts --verbose-slot-rebuilds
                --with-bdeps={y,n} --with-bdeps-auto={y,n} --with-test-deps
            )
            if [[ ${curword} -eq 1 ]] && [[ ${numwords} -eq 2 ]] ; then
                opts+=( --help --resume --searchdesc --version )
            fi
        elif [[ ${cur} == -* ]]; then
            # Complete on short options.
            opts+=( -B -D -G -K -N -O -a -b -d -e -f -g -k -l -n -o -p -q -t -u -v )
            if [[ ${curword} -eq 1 ]] && [[ ${numwords} -eq 2 ]] ; then
                opts+=( -h -S -V )
            fi
            if [[ -z ${action} ]] && [[ ${curword} -eq $((pkgpos - 1)) ]] ; then
                opts+=( -C -P -c -s )
            fi
        fi

        COMPREPLY=($(compgen -W '${opts[*]}' -- ${cur}))

        # NOTE: This slows things down!
        # (Adapted from bash_completion by Ian Macdonald <ian@caliban.org>)
        # This removes any options from the list of completions that have
        # already been specified on the command line.
        COMPREPLY=($(echo "${COMP_WORDS[@]}" | \
            (while read -d ' ' i; do
                [[ -z ${i} ]] && continue
                # flatten array with spaces on either side,
                # otherwise we cannot grep on word boundaries of
                # first and last word
                COMPREPLY=" ${COMPREPLY[@]} "
                # remove word from list of completions
                COMPREPLY=(${COMPREPLY/ ${i%% *} / })
            done
            echo ${COMPREPLY[@]})))

        return 0
    fi # options

    # Stop completion if a special case is encountered.
    if [[ ${action} =~ (system|world) ]] || \
        [[ ${COMP_LINE} =~ --(depclean|metadata|regen|resume|skipfirst|sync) ]]
    then
        unset COMPREPLY
        return 0
    fi

    # Complete on installed packages when unmerging.
    if [[ "${action}" =~ --(rage-clean|unmerge) ]]; then
        if [[ -n "${cur}" ]] ; then
            if [[ "${cur}" == */* ]]; then
                words=$(builtin cd /var/db/pkg; compgen -G "${cur}*")
            else
                words=$(builtin cd /var/db/pkg; compgen -S '/' -G "${cur}*")

                local n=0
                for i in ${words} ; do
                    [[ ${i} == ${cur}* ]] && n=$((n+1))
                done

                if [[ ${n} -eq 1 ]] ; then
                    words="$(builtin cd /var/db/pkg ; compgen -G "*-*/*")"
                fi
            fi
                COMPREPLY=($(for i in ${words} ; do \
                                [[ ${i} == ${cur}* ]] && echo ${i} ; \
                            done))
        else
            COMPREPLY=($(builtin cd /var/db/pkg ; compgen -S '/' -G "*-*"))
        fi

        [[ -z "${COMPREPLY}" ]] && _pkgname_only ${cur} /var/db/pkg
        return 0
    fi

    # Check for conditional.
    cond="${cur%%[A-Za-z0-9]*}"
    cur="${cur:${#cond}}"
    if [[ ${cond:0:1} == "'" || ${cond:0:1} == '"' ]] ; then
        prepend="-P ${cond:1}"
        c="${cond:1}"
    else
        c="${cond}"
    fi

    # Handle cases where a conditional is specified.
    if [[ -n "${cond}" ]]; then
        if [[ -n "${cur}" ]]; then
            if [[ ${cur} == */* ]]; then
                if [[ ${cur} == *-[0-9]* ]] ; then
                    words="$(\
                        for pd in ${portdir} ; do \
                            builtin cd ${pd} ; \
                            local cat="${cur%/*}" ; \
                            local pkg="$(echo ${cur%-[0-9]*})" ; \
                            pkg="${pkg##*/}" ; \
                            for x in ${cat}/${pkg}/*.ebuild ; do \
                                [[ -f ${x} ]] || continue ; \
                                x="${x/${pkg}\/}" ; \
                                echo "${x%*.ebuild}" ; \
                            done ; \
                        done)"
                else
                    words="$(\
                    for pd in ${portdir} ; do \
                        builtin cd ${pd}; \
                        compgen -X "*metadata.xml" -G "${cur}*" -- ${cur} ; \
                    done)"
                fi

                local w
                for x in $words ; do
                    w="${x}\n${w}"
                done

                words=$(echo -ne ${w} | sort | uniq)
                COMPREPLY=( ${words} )

                # Complete on the specific versions (if appropriate).
                # TODO - see if we can use _pkgname
                if [[ ${#COMPREPLY[@]} -le 1 ]]; then
                    COMPREPLY=($(
                        for pd in ${portdir}; do
                            if [[ -d ${pd}/metadata/md5-cache ]]; then
                                builtin cd ${pd}/metadata/md5-cache
                                compgen ${prepend} -G "${cur}*" -- "${cur}"
                            elif [[ -d ${pd}/metadata/cache ]]; then
                                builtin cd ${pd}/metadata/cache
                                compgen ${prepend} -G "${cur}*" -- "${cur}"
                            else
                                builtin cd ${pd}
                                local cat="${cur%/*}"
                                local pkg="$(echo ${cur%-[0-9]*}*)"
                                pkg="${pkg##*/}"
                                for x in ${cat}/${pkg}/*.ebuild; do
                                    [[ -f "${x}" ]] || continue
                                    x="${x/${pkg}\/}"
                                    if [[ ${cond:0:1} == "'" ]] || [[ ${cond:0:1} == '"' ]]; then
                                        echo "${c}${x%*.ebuild}"
                                    else
                                        echo "${x%*.ebuild}"
                                    fi
                                done
                            fi
                        done
                    ))
                else
                    COMPREPLY=($(compgen ${prepend} -W "${words}" -- $cur))
                fi
            else
                words="$(\
                    for pd in ${portdir} ; do \
                        builtin cd ${pd} ; \
                        compgen ${prepend} -S '/' -G "${cur}*" -- "${cur}" ; \
                    done)"

                local w
                for x in words ; do
                    w="${x}\n${w}"
                done

                COMPREPLY=($(echo -e ${w} | uniq))
                [[ ${#COMPREPLY[@]} = 1 ]] && \
                    COMPREPLY=($(\
                        for pd in ${portdir} ; do \
                            builtin cd ${pd} ; \
                            compgen ${prepend} -G "${cur}*/*" -- "${cur}" ; \
                        done))
            fi
        else
        words="$(\
                for pd in ${portdir} ; do \
                    builtin cd ${pd}; \
                    compgen -G "*-*"; \
                done)"
        COMPREPLY=($(compgen -W "${words}" -- "${cur}"))
    fi

    # If all else fails, try to complete on package names without the
    # category being specified.
    if [[ -z "${COMPREPLY}" ]]; then
        words="$(\
                for pd in ${portdir} ; do \
                    builtin cd ${pd}; \
                    for i in *-*/${cur}*; do \
                        [[ -d $i ]] && echo ${i##*/}; \
                    done ; \
                done)"

        COMPREPLY=($(compgen ${prepend} -W "${words}" -- ${cur}))

        if [[ ${#COMPREPLY[@]} -le 1 ]]; then
            # Now complete on the specific versions.
            words="$(
                for pd in ${portdir}; do
                    if [[ -d ${pd}/metadata/md5-cache ]]; then
                        builtin cd ${pd}/metadata/md5-cache
                        for i in */${cur}*; do
                            [[ -f $i ]] && echo ${i##*/}
                        done
                    elif [[ -d ${pd}/metadata/cache ]]; then
                        builtin cd ${pd}/metadata/cache
                        for i in */${cur}*; do
                            [[ -f $i ]] && echo ${i##*/}
                        done
                    fi
                done
            )"
            COMPREPLY=($(compgen ${prepend} -W "${words}" -- "${cur}"))
        fi
    fi
    return 0
    fi

    # Complete on packages.
    #
    # Only allow these actions if no packages have been specified.
    #
    # TODO: This doesn't block these actions if no categories are
    #       specified. Please fix me.
    #
    #       e.g. emerge -a gentoo-dev-sources
    #
    #            will still allow system and world actions to be specified,
    #            as opposed to
    #
    #            emerge -a sys-kernel/gentoo-dev-sources
    #
    if [[ ${COMP_CWORD} -eq 1 ]] || [[ ! " ${COMP_LINE} " == *" "*[/]*" "* ]] ; then
        sysactions=$'\n'"system"$'\n'"world"
    else
        sysactions=''
    fi

    if [[ -n "${cur}" ]] ; then
        if [[ ${cur} == */* ]] ; then
            words=$(\
                for pd in ${portdir} ; do \
                    builtin cd ${pd}; \
                    compgen -X "*metadata.xml" -G "${cur}*" ; \
                done)"${sysactions}"
        else
            local ww=$(\
                for pd in ${portdir} ; do \
                    builtin cd ${pd} ; \
                    compgen -X "!@(*-*|virtual)" -S '/' -G "${cur}*"; \
                done)"${sysactions}"
            # complete on virtuals
            ww="${ww} $(\
                for pd in ${portdir} ; do \
                    if [[ -d ${pd}/profiles ]] ; then
                        find ${pd}/profiles -name virtuals -exec \
                            sed -n -e 's|^\(virtual/[[:alnum:]]\+\).*$|\1|p' {} \; | \
                            sort -u
                    fi ; \
                done)"

            local w
            for x in ${ww} ; do w="${x}\n${w}" ; done

            words=$(echo -e ${w} | sort -u)

            local n=0
            for i in ${words} ; do
                [[ ${i} == ${cur}* ]] && n=$((n+1))
            done

            if [[ ${n} -eq 1 ]] ; then
                words=$(for pd in ${portdir} ; do \
                            builtin cd ${pd} ; \
                            compgen -G "*-*/*" ; \
                        done)"${sysactions}"
            fi
        fi
        COMPREPLY=($(for i in ${words} ; do \
                        [[ ${i} == ${cur}* ]] && echo ${i} ; \
                    done))
    else
        words="$(\
            for pd in ${portdir} ; do \
                builtin cd ${pd} ; \
                compgen -S '/' -G "*-*" ; \
            done)""${sysactions}"
        COMPREPLY=($(compgen -W "${words}" -- ${cur}))
    fi

    # If all else fails, try to complete on package names without the
    # category being specified.
    if [[ -z "${COMPREPLY}" ]]; then
        words="$(\
            for pd in ${portdir} ; do \
                builtin cd ${pd}; \
                for i in [a-z]*-[a-z0-9]*/${cur}*; do \
                    [[ -d $i ]] && echo ${i##*/}; \
                done ; \
            done)"
        COMPREPLY=($(compgen -W "${words}" -- ${cur}))
    fi

    return 0
} &&
complete -o filenames -F _emerge emerge

# vim: ft=sh:et:ts=4:sw=4:tw=80
