#!/usr/bin/env bash
# SPDX-License-Identifier: GPL-2.0-only

_detect_kver() {
    local kver_validator='^[[:digit:]]+(\.[[:digit:]]+)+' offset
    offset="$(od -An -j0x20E -dN2 "$1")" || return
    read -r kver _ < \
        <(dd if="$1" bs=1 count=127 skip=$(( offset + 0x200 )) 2>/dev/null)
    [[ "$kver" =~ $kver_validator ]] && printf '%s' "$kver"
}

_lsinitcpio() {
    local cur opts
    opts=(-a --analyze -c --config -h --help -l --list
          -n --nocolor -V --version -v --verbose -x --extract)

    _get_comp_words_by_ref cur

    case $cur in
        -*)
            mapfile -t COMPREPLY< <(compgen -W "${opts[*]}" -- "$cur") ;;
        *)
            _filedir ;;
    esac
}

_find_kernel_versions() {
    local -a matches
    local f kver

    for f in /boot/*; do
        # only match regular files which pass validation
        if [[ ! -L $f && -f $f ]] && kver=$(_detect_kver "$f"); then
            matches+=("$f" "$kver")
        fi
    done

    mapfile -t COMPREPLY < <(compgen -W "${matches[*]}" -- "$cur")
}

_files_from_dirs() {
    local files stripsuf d f

    if [[ $1 = -s ]]; then
        stripsuf=$2
        shift 2
    fi

    for d in "$@"; do
        for f in "$d"/*; do
            [[ -f $f ]] && files+=("${f##*/}")
        done
    done

    printf '%s\n' "${files[@]%$stripsuf}"
}

_mkinitcpio() {
    local cur prev opts
    opts=(-A --addhooks -c --config -D --hookdir -d --generatedir -g --generate -H --hookhelp -h --help -k --kernel
          -L --listhooks -M --automods -n --nocolor -P --allpresets -p --preset -R --remove -r --moduleroot
          -S --skiphooks -s --save -t --builddir -V --version -v --verbose -z --compress
          -U --cmdline --kernelimage --microcode --osrelease --splash --uki --uefistub)

    _get_comp_words_by_ref cur prev

    case $prev in
        -[cgU]|--cmdline|--config|--generate|--kernelimage|--microcode|--osrelease|--splash|--uki|--uefistub)
            _filedir ;;
        -D|--hookdir|-d|--generatedir|-r|--moduleroot|-t|--builddir)
            _filedir -d ;;
        -k|--kernel)
            _find_kernel_versions ;;
        -p|--preset)
            mapfile -t COMPREPLY < <(compgen -W "$(_files_from_dirs -s .preset /etc/mkinitcpio.d)" -- "$cur") ;;
        -[AHS]|--add|--hookhelp|--skiphooks)
            mapfile -t COMPREPLY < <(compgen -W "$(_files_from_dirs {/usr,}/lib/initcpio/install)" -- "$cur") ;;
        *)
            mapfile -t COMPREPLY < <(compgen -W "${opts[*]}" -- "$cur") ;;
    esac
}

complete -F _mkinitcpio mkinitcpio
complete -F _lsinitcpio lsinitcpio

# vim: set et ts=4 sw=4 ft=sh:
