#!/usr/bin/env dash

# shellcheck source=/dev/null
SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH

# needed for help() and version
# shellcheck disable=2034
AUTHORS="Soispha"
# shellcheck disable=2034
YEARS="2024"
# shellcheck disable=2034
VERSION="1.0.0"

# NAME is from the wrapper
# shellcheck disable=SC2269
NAME="$NAME"

help() {
    cat <<EOF
Edit a file from the index. This script does not touch the unstaged variant of the file.

USAGE:
    $NAME [OPTIONS] [--] FILES..

OPTIONS:
    --
                            Stop parsing options and interpret everything as an file.

    --help | -h
                            Display this help and exit.

    --version | -v
                            Display version and copyright information and exit.
ARGUMENTS:
    FILES := [[ git diff --name-only --cached --diff-filter=AM ]]
                            The files to edit.

EOF
}

GIT_DIR="$(git rev-parse --show-toplevel)"
materialize_file() {
    git diff --cached "$1" >"$GIT_DIR/.git/EDIT_INDEX_PATCH"

    git add "$1"
    git restore --staged "$1"
    cat "$1" >"$GIT_DIR/.git/EDIT_INDEX_FILE"
    git restore "$1"

    git apply "$GIT_DIR/.git/EDIT_INDEX_PATCH"
    "$EDITOR" "$1"

    git add "$1"
    mv "$GIT_DIR/.git/EDIT_INDEX_FILE" "$1"
}

edit() {
    files_to_add="$(mktmp)"
    realpath --relative-to=. "$@" >"$files_to_add"

    index_files="$(mktmp)"
    git diff --name-only --cached --diff-filter=AM >"$index_files"

    while read -r file; do
        if grep -q "$file" "$files_to_add"; then
            sed -i "s|$file||" "$files_to_add"
            materialize_file "$file"
        fi
    done <"$index_files"

    files_to_check="$(mktmp)"
    clean "$files_to_add" >"$files_to_check"
    if [ "$(wc -l <"$files_to_check")" -gt 0 ]; then
        warn "Could not edit every file:"
        cat "$files_to_add"
    fi
}

for arg in "$@"; do
    case "$arg" in
    "--help" | "-h")
        help
        exit 0
        ;;
    "--version" | "-v")
        version
        exit 0
        ;;
    "--")
        end_of_cli_options=true
        ;;
    esac
    [ "$end_of_cli_options" = "true" ] && break
done

edit "$@"

# vim: ft=sh