#compdef aura

# Zsh completion file for Aura, based on pacman's.
# Copy this file to /usr/share/zsh/site-functions/_aura

typeset -A opt_args
setopt extendedglob

# options for passing to _arguments: main aura commands
_aura_opts_commands=(
    {-A,--aursync}'[Install and manage AUR packages]'
    {-B,--save}'[Manage the global package state]'
    {-C,--downgrade}'[Manage the package cache]'
    {-D,--database}'[Operate on the package database]'
    {-F,--files}'[Query the files database]'
    {-L,--viewlog}'[Analyse the pacman log file]'
    {-O,--orphans}'[Manage orphan packages]'
    {-Q,--query}'[Query the package database]'
    {-R,--remove}'[Remove a package]'
    {-S,--sync}'[Synchronize repo packages]'
    {-T,--deptest}'[Check if given dependencies are satisfied]'
    {-U,--upgrade}'[Upgrade packages]'
    {-V,--version}'[Display version information]'
    # {check}'[Validate your system]'
    # {conf}'[View various configuration settings and files]'
    # {deps}'[Output a dependency graph]'
    # {free}'[The state of Free Software installed on the system]'
    # {stats}'[View statistics about your machine or about Aura itself]'
    # {thanks}'[The people behind Aura]'
    '(-h --help)'{-h,--help}'[Help message]'
)

# options for passing to _arguments: options common to all commands
_aura_opts_common=(
    {-h,--help}'[Display syntax for the given operation]'
    '--log-level[Minimum level of Aura log messages to display]'
)

# options for passing to _arguments: options for --upgrade commands
_aura_opts_pkgfile=(
    '*-d[Skip dependency checks]'
    '*--nodeps[Skip dependency checks]'
    '*--assume-installed[Add virtual package to satisfy dependencies]'
    '--dbonly[Only remove database entry, do not remove files]'
    '--needed[Do not reinstall up to date packages]'
    '--asdeps[mark packages as non-explicitly installed]'
    '--asexplicit[mark packages as explicitly installed]'
    {-p,--print}'[Only print the targets instead of performing the operation]'
    '*--ignore[Ignore a package upgrade]:package: _pacman_completions_all_packages'
    '*--ignoregroup[Ignore a group upgrade]:package group:_pacman_completions_all_groups'
    '--print-format[Specify how the targets should be printed]'
    '*:package file:_files -g "*.pkg.tar*~*.sig(.,@)"'
)

# options for passing to _arguments: subactions for --query command
_aura_opts_query_actions=(
    '(-Q --query)'{-Q,--query}
    {-g,--groups}'[View all members of a package group]:*:package groups:->query_group'
    {-o,--owns}'[Query the package that owns a file]:file:_files'
    {-p,--file}'[Package file to query]:*:package file:->query_file'
    {-s,--search}'[Search package names and descriptions]:*:search text:->query_search'
)

# options for passing to _arguments: options for --query and subcommands
_aura_opts_query_modifiers=(
    {-c,--changelog}'[List package changelog]'
    {-d,--deps}'[List packages installed as dependencies]'
    {-e,--explicit}'[List packages explicitly installed]'
    {\*-i,\*--info}'[View package information]'
    {\*-k,\*--check}'[Check package files]'
    {-l,--list}'[List package contents]'
    {-m,--foreign}'[List installed packages not found in sync db(s)]'
    {-n,--native}'[List installed packages found in sync db(s)]'
    {-q,--quiet}'[Show less information for query and search]'
    {-t,--unrequired}'[List packages not required by any package]'
    {-u,--upgrades}'[List packages that can be upgraded]'
)

# options for passing to _arguments: options for --remove command
_aura_opts_remove=(
    {-c,--cascade}'[Remove all dependent packages]'
    {-d,--nodeps}'[Skip dependency checks]'
    '*--assume-installed[Add virtual package to satisfy dependencies]'
    {-n,--nosave}'[Remove protected configuration files]'
    {-p,--print}'[Only print the targets instead of performing the operation]'
    {\*-s,\*--recursive}'[Remove dependencies not required by other packages]'
    {-u,--unneeded}'[Remove unneeded packages]'
    '--dbonly[Only remove database entry, do not remove files]'
    '--print-format[Specify how the targets should be printed]'
    '*:installed package:_aura_completions_installed_packages'
)

# options for passing to _arguments: options for commands dealing with the database
_aura_opts_database=(
    '--asdeps[mark packages as non-explicitly installed]'
    '--asexplicit[mark packages as explicitly installed]'
    '*:installed package:_aura_completions_installed_packages'
)

_aura_opts_files=(
    {-l,--list}'[List the files owned by the queried package]:package:_pacman_completions_all_packages'
    {-x,--regex}'[Enable searching using regular expressions]:regex:'
    {-y,--refresh}'[Download fresh files databases from the server]'
    '--machinereadable[Produce machine-readable output]'
    {-q,--quiet}'[Show less information for query and search]'
)

# options for passing to _arguments: options for --sync command
_aura_opts_sync_actions=(
    '(-S --sync)'{-S,--sync}
    {\*-c,\*--clean}'[Remove old packages from cache]:\*:clean:->sync_clean'
    {-g,--groups}'[View all members of a package group]:*:package groups:->sync_group'
    {-s,--search}'[Search package names and descriptions]:*:search text:->sync_search'
    '--dbonly[Only remove database entry, do not remove files]'
    '--needed[Do not reinstall up to date packages]'
    '--recursive[Reinstall all dependencies of target packages]'
)

# options for passing to _arguments: options for --sync command
_aura_opts_sync_modifiers=(
    {\*-d,\*--nodeps}'[Skip dependency checks]'
    '*--assume-installed[Add virtual package to satisfy dependencies]'
    {\*-i,\*--info}'[View package information]'
    {-l,--list}'[List all packages in a repository]'
    {-p,--print}'[Print download URIs for each package to be installed]'
    {-q,--quiet}'[Show less information for query and search]'
    {\*-u,\*--sysupgrade}'[Upgrade all out-of-date packages]'
    {-w,--downloadonly}'[Download packages only]'
    {\*-y,\*--refresh}'[Download fresh package databases]'
    '*--ignore[Ignore a package upgrade]:package: _aura_completions_all_packages'
    '*--ignoregroup[Ignore a group upgrade]:package group:_aura_completions_all_groups'
    '--asdeps[Install packages as non-explicitly installed]'
    '--asexplicit[Install packages as explicitly installed]'
    '--print-format[Specify how the targets should be printed]'
)

# options for passing to _arguments: options for --aursync command
_aura_opts_aursync_actions=(
    '(-A --aursync)'{-A,--aursync}
    {-i,--info}'[Display AUR package information]'
    {-o,--open}'[Open the AUR page of a given package]'
    {-p,--pkgbuild}'[Display an AUR package''s PKGBUILD]'
    {-s,--search}'[Search AUR package names and descriptions]'
    {-u,--sysupgrade}'[Upgrade all installed AUR packages]'
    {-v,--provides}'[Search for packages that provide some package identity]'
    {-w,--clone}'[Download an AUR package''s source tarball]'
    {-y,--refresh}'[Pull the latest changes for every local copy of AUR pkgs]'
)

# options for passing to _arguments: options for --aursync command
_aura_opts_aursync_modifiers=(
    {-a,--delmakedeps}'[Uninstall unneeded build deps after installation]'
    {-d,--dryrun}'[Show available upgrades, but do not perform them]'
    {-k,--diff}'[Show PKGBUILD diffs when upgrading]'
    '--git[Rebuild all git/svn/hg/etc. packages as well]'
    '--ignore[Ignore a package upgrade]'
    '--hotedit[Prompt user to edit PKGBUILD before dep checks]'
    '--build[The path in which to build packages]'
    '--builduser[The user to build as]'
    '--shellcheck[Run shellcheck on PKGBUILDs before building]'
    '--nocheck[Do not consider checkdeps when building]'
    '--skipdepcheck[Perform no dependency resolution]'
    '--abc[Sort search results alphabetically]'
    '--limit[Limit search results to N results]'
    {-q,--quiet}'[Only print matching package names]'
    {-r,--reverse}'[Reverse the search results]'
    '--noconfirm[Do not ask for any confirmation]'
)

# options for passing to _arguments: options for --save commands
_aura_opts_save=(
    {-c,--clean}'[Given n, save n recent package states and remove the rest]'
    {-l,--list}'[Show all saved package snapshot filenames]'
    {-r,--restore}'[Restore a previously saved package state]'
)

# options for passing to _arguments: options for --downgrade commands
_aura_opts_downgrade=(
    {-b,--backup}'[Backup the cache to a given directory]'
    {-c,--clean}'[Given n, save n versions of each package file]'
    {-i,--info}'[Look up specific packages for their cache info]'
    {-l,--list}'[Print the contents of the package cache]'
    {-m,--missing}'[Display packages that have no tarball in the cache]'
    '--notsaved[Delete only those tarballs not present in a snapshot]'
    {-s,--search}'[Search the cache via a regex]'
    {-t,--invalid}'[Delete invalid tarballs from the cache]'
    {-y,--refresh}'[Download tarballs of installed packages that are missing from the cache]'
    '*:installed package:_aura_completions_installed_packages'
)

# options for passing to _arguments: options for --viewlog commands
_aura_opts_viewlog=(
    '-i[View package installation history.]'
    '-s[Search log file via a regex.]'
)

_aura_opts_viewlog_modifiers=(
    {-b,--before}'[Only display entries from before the given date.]'
    {-a,--after}'[Only display entries from after the given date.]'
    '--logfile[Set an alternate log file]'
)

# options for passing to _arguments: options for --orphans commands
_aura_opts_orphans=(
    {-a,--adopt}'[Mark a package as explicitly installed]'
    {-j,--adandon}'[Uninstall all orphan packages]'
    {-e,--elderly}'[Display all explicitly installed, top-level packages]'
)

_aura_opts_conf=(
    {-a,--aura}'[View the contents of your Aura config file]'
    {-g,--gen}'[Output your current, full Aura config as legal TOML]'
    {-m,--makepkg}'[View the Makepkg conf]'
    {-p,--pacman}'[View the Pacman conf]'
)

_aura_opts_conf_modifiers=(
    '--config[Set an alternate Pacman configuration file]'
)

_aura_ops_deps=(
    {-l,--limit}'[The number of layers up or down to allow]'
    {-o,--optional}'[Include optional dependencies]'
    {-r,--reverse}'[Display packages that depend on the given args]'
    '--open[Open the output image automatically]'
    '--raw[Print the raw DOT output]'
)

_aura_ops_free=(
    '--copyleft[Consider only Copyleft licenses]'
    '--lenient[Allow FOSS-derived custom licenses]'
)

_aura_ops_stats=(
    {-g,--groups}'[View all installed package groups]'
    '--heavy[View the Top 10 heaviest package installations]'
    {-l,--lang}'[View Aura''s localisation statistics]'
)

# handles --help subcommand
_aura_action_help() {
    _arguments -s : \
        "$_aura_opts_commands[@]"
}

# handles cases where no subcommand has yet been given
_aura_action_none() {
    _arguments -s : \
        "$_aura_opts_commands[@]"
}

# handles --query subcommand
_aura_action_query() {
    local context state line
    typeset -A opt_args

    case $state in
        query_file)
            _arguments -s : \
                "$_aura_opts_common[@]" \
                "$_aura_opts_query_modifiers[@]" \
                '*:package file:_files -g "*.pkg.tar*~*.sig(.,@)"'
            ;;
        query_group)
            _arguments -s : \
                "$_aura_opts_common[@]" \
                "$_aura_opts_query_modifiers[@]" \
                '*:groups:_aura_completions_installed_groups'
            ;;
        query_owner)
            _arguments -s : \
                "$_aura_opts_common[@]" \
                "$_aura_opts_query_modifiers[@]" \
                '*:file:_files'
            ;;
        query_search)
            _arguments -s : \
                "$_aura_opts_common[@]" \
                "$_aura_opts_query_modifiers[@]" \
                '*:search text: '
            ;;
        *)
            _arguments -s : \
                "$_aura_opts_common[@]" \
                "$_aura_opts_query_actions[@]" \
                "$_aura_opts_query_modifiers[@]" \
                '*:package:_aura_completions_installed_packages'
            ;;
    esac
}

# handles --remove subcommand
_aura_action_remove() {
    _arguments -s : \
        '(--remove -R)'{-R,--remove} \
        "$_aura_opts_common[@]" \
        "$_aura_opts_remove[@]"
}

# handles --database subcommand
_aura_actions_database() {
    _arguments -s : \
        '(--database -D)'{-D,--database} \
        "$_aura_opts_common[@]" \
        "$_aura_opts_database[@]"
}

# handles --files subcommand
_aura_action_files() {
    _arguments -s : \
        '(--files -F)'{-F,--files} \
        "$_aura_opts_common[@]" \
        "$_aura_opts_files[@]"
}

# handles --deptest subcommand
_aura_action_deptest() {
    _arguments -s : \
        '(--deptest)-T' \
        "$_aura_opts_aura_common[@]" \
        ":packages:_aura_all_packages"
}

# handles --sync subcommand
_aura_action_sync() {
    local context state line
    typeset -A opt_args
    if (( $+words[(r)--clean] )); then
        state=sync_clean
    elif (( $+words[(r)--groups] )); then
        state=sync_group
    elif (( $+words[(r)--search] )); then
        state=sync_search
    fi

    case $state in
        sync_clean)
            _arguments -s : \
                {\*-c,\*--clean}'[Remove old packages from cache]' \
                "$_aura_opts_common[@]" \
                "$_aura_opts_sync_modifiers[@]"
                ;;
        sync_group)
            _arguments -s : \
                "$_aura_opts_common[@]" \
                "$_aura_opts_sync_modifiers[@]" \
                '(-g --group)'{-g,--groups} \
                '*:package group:_aura_completions_all_groups'
            ;;
        sync_search)
            _arguments -s : \
                "$_aura_opts_common[@]" \
                "$_aura_opts_sync_modifiers[@]" \
                '*:search text: '
            ;;
        *)
            _arguments -s : \
                "$_aura_opts_common[@]" \
                "$_aura_opts_sync_actions[@]" \
                "$_aura_opts_sync_modifiers[@]" \
                '*:package:_aura_completions_repo_packages'
            ;;
    esac
}

# handles --upgrade subcommand
_aura_action_upgrade() {
    _arguments -s : \
        '(-U --upgrade)'{-U,--upgrade} \
        "$_aura_opts_common[@]" \
        "$_aura_opts_pkgfile[@]"
}

# handles --version subcommand
_aura_action_version() {
    # no further arguments
    return 0
}

# provides completions for package groups
_aura_completions_all_groups() {
    local -a cmd groups
    _aura_get_command
    groups=( $(_call_program groups $cmd[@] -Sg) )
    typeset -U groups

    if [[ ${words[CURRENT-1]} == '--ignoregroup' ]]; then
        _sequence compadd -S ',' "$@" -a groups
    else
        compadd "$@" -a groups
    fi
}

# provides completions for packages available from repositories
# these can be specified as either 'package' or 'repository/package'
_aura_completions_repo_packages() {
    local -a seq sep cmd packages repositories packages_long
    _aura_get_command

    if [[ ${words[CURRENT-1]} == '--ignore' ]]; then
        seq='_sequence'
        sep=(-S ',')
    else
        seq=
        sep=()
    fi

    if compset -P1 '*/*'; then
        packages=( $(pacman -Sql ${words[CURRENT]%/*}) )
        typeset -U packages
        ${seq} _wanted repo_packages expl "repository/package" compadd ${sep[@]} ${(@)packages}
    else
        packages=( $(pacman -Sql) )
        typeset -U packages
        ${seq} _wanted packages expl "packages" compadd ${sep[@]} - "${(@)packages}"

        repositories=($(pacman-conf --repo-list))
        typeset -U repositories
        _wanted repo_packages expl "repository/package" compadd -S "/" $repositories
    fi
}

# provides completions for packages in the AUR
_aura_completions_aur_packages() {
    local -a cmd packages repositories packages_long
    _aura_get_command

    packages=()
    if [[ -d ~/.cache/aura/packages/ ]]; then
        packages=( $(ls ~/.cache/aura/packages/) )
    fi
    typeset -U packages
    _wanted aur_packages expl "packages" compadd - "${(@)packages}"
}

# provides completions for packages available from repositories and the AUR
# these can be specied as either 'package' or 'repository/package'
_aura_completions_all_packages() {
    _alternative : \
        'aurpkgs:aur packages:_aura_completions_aur_packages' \
        'repopkgs:repository packages:_aura_completions_repo_packages'
}

_aura_all_packages() {
    _alternative : \
        'localpkgs:local packages:_aura_completions_installed_packages' \
        'aurpkgs:aur packages:_aura_completions_aur_packages' \
        'repopkgs:repository packages:_aura_completions_repo_packages'
}

# provides completions for package groups
_aura_completions_installed_groups() {
    local -a cmd groups
    _aura_get_command
    groups=(${(o)${(f)"$(_call_program groups $cmd[@] -Qg)"}% *})
    typeset -U groups
    compadd "$@" -a groups
}

# provides completions for installed packages
_aura_completions_installed_packages() {
    local -a cmd packages packages_long
    packages_long=(/var/lib/pacman/local/*(/))
    packages=( ${${packages_long#/var/lib/pacman/local/}%-*-*} )
    compadd "$@" -a packages
}

# provides completions for repository names
_aura_completions_repositories() {
    local -a cmd repositories
    repositories=($(pacman-conf --repo-list))
    # Uniq the array
    typeset -U repositories
    compadd "$@" -a repositories
}

# builds command for invoking aura in a _call_program command - extracts
# relevant options already specified (config file, etc)
# $cmd must be declared by calling function
_aura_get_command() {
    # this is mostly nicked from _perforce
    cmd=( "aura" "2>/dev/null" )
    integer i
    for (( i = 2; i < CURRENT - 1; i++ )); do
        # FIXME 2024-07-26 Probably not relevant for Aura.
        if [[ ${words[i]} = "--config" || ${words[i]} = "--root" ]]; then
            cmd+=( ${words[i,i+1]} )
        fi
    done
}

_aura_comp() {
    local -a args cmds
    local tmp
    args=( ${${${(M)words:#-*}#-}:#-*} )
    _message 'now what'
    for tmp in $words; do
        cmds+=("${${_aura_opts_commands[(r)*$tmp\[*]%%\[*}#*\)}")
    done
    case $args in #$words[2] in
        h*)
            if (( ${(c)#args} <= 1 && ${(w)#cmds} <= 1 )); then
                _aura_action_help
            else
                _message "no more arguments"
            fi
            ;;
        *h*)
            _message "no more arguments"
            ;;
        D*)
            _aura_action_database
            ;;
        F*)
            _aura_action_files
            ;;
        Q*g*) # ipkg groups
            _arguments -s : \
                "$_aura_opts_common[@]" \
                "$_aura_opts_query_modifiers[@]" \
                '*:groups:_aura_completions_installed_groups'
            ;;
        Q*o*) # file
            _arguments -s : \
                "$_aura_opts_common[@]" \
                "$_aura_opts_query_modifiers[@]" \
                '*:package file:_files'
            ;;
        Q*p*) # file *.pkg.tar.*
            _arguments -s : \
                "$_aura_opts_common[@]" \
                "$_aura_opts_query_modifiers[@]" \
                '*:package file:_files -g "*.pkg.tar*~*.sig(.,@)"'
            ;;
        T*)
            _aura_action_deptest
            ;;
        Q*)
            _aura_action_query
            ;;
        R*)
            _aura_action_remove
            ;;
        S*c*)
            _arguments -s : \
                '(-S --sync)'{-S,--sync} \
                '(-c --clean)'{\*-c,\*--clean}'[Remove all files from the cache]' \
                "$_aura_opts_common[@]"
            ;;
        S*l*) # repos
            _arguments -s : \
                "$_aura_opts_common[@]" \
                "$_aura_opts_sync_modifiers[@]" \
                '*:package repo:_aura_completions_repositories' \
                ;;
        S*g*) # pkg groups
            _arguments -s : \
                "$_aura_opts_common[@]" \
                "$_aura_opts_sync_modifiers[@]" \
                '*:package group:_aura_completions_all_groups'
            ;;
        S*s)
            _arguments -s : \
                "$_aura_opts_common[@]" \
                "$_aura_opts_sync_modifiers[@]" \
                '*:search text: '
                ;;
        S*)
            _aura_action_sync
            ;;
        U*)
            _aura_action_upgrade
            ;;
        V*)
            _aura_action_version
            ;;
        A*)
            _arguments -s : \
                "$_aura_opts_common[@]" \
                "$_aura_opts_aursync_modifiers[@]" \
                "$_aura_opts_aursync_actions[@]" \
                '*:package:_aura_completions_aur_packages'
                ;;
        B*)
            _arguments -s : \
                '(-B --save)'{-B,--save} \
                "$_aura_opts_common[@]" \
                "$_aura_opts_save[@]"
                ;;
        C*)
            _arguments -s : \
                '(-C --downgrade)'{-C,--downgrade} \
                "$_aura_opts_common[@]" \
                "$_aura_opts_downgrade[@]"
            ;;
        L*)
            _arguments -s : \
                '(-L --viewlog)'{-L,--viewlog} \
                "$_aura_opts_common[@]" \
                "$_aura_opts_viewlog[@]"
            ;;
        O*)
            _arguments -s : \
                '(-O --orphans)'{-O,--orphans} \
                "$_aura_opts_common[@]" \
                "$_aura_opts_orphans[@]"
            ;;
        conf)
            _arguments -s : \
                '(conf)'{conf} \
                "$_aura_opts_common[@]" \
                "$_aura_opts_conf"
            ;;
        deps*)
            _arguments -s : \
                '(deps)'{deps} \
                "$_aura_opts_common[@]" \
                "$_aura_opts_deps"
            ;;
        free)
            _arguments -s : \
                '(free)'{free} \
                "$_aura_opts_common[@]" \
                "$_aura_opts_free"
            ;;
        stats)
            _arguments -s : \
                '(stats)'{stats} \
                "$_aura_opts_common[@]" \
                "$_aura_opts_stats"
            ;;
        *)
            case ${(M)words:#--*} in
                *--help*)
                    if (( ${(W)#cmds} == 1 )); then
                        _aura_action_help
                    else
                        return 0
                    fi
                    ;;
                *--sync*)
                    _aura_action_sync
                    ;;
                *--query*)
                    _aura_action_query
                    ;;
                *--remove*)
                    _aura_action_remove
                    ;;
                *--deptest*)
                    _aura_action_deptest
                    ;;
                *--database*)
                    _aura_action_database
                    ;;
                *--version*)
                    _aura_action_version
                    ;;
                *--upgrade*)
                    _aura_action_upgrade
                    ;;

                *--aursync*)
                    _arguments -s : \
                        "$_aura_opts_common[@]" \
                        "$_aura_opts_aursync_modifiers[@]" \
                        "$_aura_opts_aursync_actions[@]" \
                        '*:package:_aura_completions_aur_packages'
                    ;;
                *--save*)
                    _arguments -s : \
                        '(-B --save)'{-B,--save} \
                        "$_aura_opts_common[@]" \
                        "$_aura_opts_save[@]"
                    ;;
                *--downgrade*)
                    _arguments -s : \
                        '(-C --downgrade)'{-C,--downgrade} \
                        "$_aura_opts_common[@]" \
                        "$_aura_opts_downgrade[@]"
                    ;;
                *--viewlog*)
                    _arguments -s : \
                        '(-L --viewlog)'{-L,--viewlog} \
                        "$_aura_opts_common[@]" \
                        "$_aura_opts_viewlog[@]"
                    ;;
                *--orphans*)
                    _arguments -s : \
                        '(-O --orphans)'{-O,--orphans} \
                        "$_aura_opts_common[@]" \
                        "$_aura_opts_orphans[@]"
                    ;;
                *)
                    _aura_action_none
                    ;;
            esac
            ;;
    esac
}

# run the main dispatcher
_aura_comp "$@"
