# Debian apt(8) completion                             -*- shell-script -*-
# shellcheck shell=bash

_apt_patterns() {
    if [[ $cur == ?(\\)\?* ]]; then
        compopt -o filenames  # escape to avoid ? filename matches
        COMPREPLY=( $( compgen -P '?' -W '
            automatic
            broken
            config-files
            essential
            garbage
            installed
            obsolete
            phasing
            security
            upgradable
            virtual
        ' -- "${cur#?(\\)\?}" ) )
        return 0
    fi
    return 1
}

_apt()
{
    local sourcesdir="/etc/apt/sources.list.d"
    local cur prev words cword
    _init_completion || return

    local -a COMMANDS
    mapfile -t COMMANDS < <(apt __complete 2>/dev/null)

    # See if the user selected a command already.
    local command i
    for (( i=1; i < ${#words[@]}; i++ )); do
        if [[ " ${COMMANDS[*]} " == *" ${words[i]} "* ]]; then
            command=${words[i]}
            break
        fi
    done

    # Complete a -t<SPACE><TAB>
    case $prev in
        -t|--target-release)
            COMPREPLY=( $( compgen -W "$(apt-cache policy | grep -Eo 'a=[^,]*|n=[^,]*' | cut -f2- -d= | sort -u)" -- "$cur" ) )
            return 0
            ;;
    esac

    # Options come directly from the declarative parser.
    if [[ $cur == -* || ( -v command && $cword -le $i ) ]]; then
        COMPREPLY=( $( compgen -W "$(apt __complete "${command-}" 2>/dev/null)" -- "$cur" ) )
        return 0
    fi

    # Specific command arguments.
    if [[ -v command ]]; then
        case $command in
            remove|purge|autoremove|autopurge|why)
                _apt_patterns && return 0
                if [[ -f /etc/debian_version ]]; then
                    # Debian system
                    COMPREPLY=( $( \
                        _xfunc dpkg _comp_dpkg_installed_packages $cur ) )
                else
                    # assume RPM based
                    _xfunc rpm _rpm_installed_packages
                fi
                return 0
                ;;
            show|list|download|changelog|depends|rdepends|why-not)
                _apt_patterns || \
                COMPREPLY=( $( apt-cache --no-generate pkgnames "$cur" \
                    2> /dev/null ) )
                return 0
                ;;
            install|reinstall)
                if [[ "$cur" == .* || "$cur" == /* || "$cur" == ~* ]]; then
                    _filedir "deb"
                else
                    _apt_patterns || \
                    COMPREPLY=( $( apt-cache --no-generate pkgnames "$cur" \
                        2> /dev/null ) )
                fi
                return 0
                ;;
            source|build-dep|showsrc|policy)
                if [[ "$command" == build-dep && ( "$cur" == .* || "$cur" == /* || "$cur" == ~* ) ]]; then
                    _filedir "dsc"
                else
                    _apt_patterns || \
                    COMPREPLY=( $( apt-cache --no-generate pkgnames "$cur" \
                        2> /dev/null ) $( apt-cache dumpavail | \
                        command grep "^Source: $cur" | sort -u | cut -f2 -d" " ) )
                fi
                return 0
                ;;
            edit-sources)
                COMPREPLY=( $( compgen -W '$( command ls $sourcesdir )' \
                    -- "$cur" ) )
                return 0
                ;;
            history-info|history-rollback|history-redo|history-undo)
                local _historyids=$( apt history-list |
                    awk '/^(ID|$)/{next};{print$1}' |tac 2> /dev/null )
                COMPREPLY=( $( compgen -W "${_historyids[@]}" -- "$cur" ) )
                return 0
                ;;
            moo)
                COMPREPLY=( $( compgen -W 'moo' \
                    -- "$cur" ) )
                return 0
                ;;
        esac
    else
        # No command yet: derive commands from the parser.
        COMPREPLY=( $( compgen -W "${COMMANDS[*]}" -- "$cur" ) )
    fi

    return 0
} &&
complete -o nosort -F _apt apt

# ex: ts=4 sw=4 et filetype=sh