#!/bin/sh -e

term_setup() {
    stty -icanon -echo

    printf '\033[?1049h\033[?7l\033[?25l\033[2J\033[1;%sr' \
        "$((LINES - 2))"
}

term_reset() {
    stty icanon echo

    printf '\033[?7h\033[?25h\e[2J\033[;r\033[?1049l'
}

term_resize() {
    set -f
    set +f -- $(stty size)

    LINES=$1 COLUMNS=$2

    # leave gap above statusline
    line_max=$((LINES - 2))
}

list_print() {
    printf '\033[2J\033[H\033[31;7m'
    printf '%s\033[m\n' "$@"
    printf '\033[%sH' "$y"
}

list_reset() {
    y=1
}

redraw() {
    list_print "$@"
    status_line
}

status_line() {
    printf '\0337\033[%sH\033[31;7m%-*s\033[m\0338' \
        "$LINES" "$COLUMNS" "${1:-$PWD ($y)}"
}

print_line() {
    offset=$1

    [ "$offset" != "$y" ] ||
        printf '\033[31;7m'

    shift "$1"
    printf '\033[K%s\033[m\r' "$1"

    [ "$offset" != "$y" ] ||
        cur=$1
}

main() {
    esc_char=$(printf '\033')

    # change directory to the first argument
    cd "${1:-"$PWD"}"

    set -- *

    term_resize
    term_setup
    list_reset
    redraw "$@"

    trap 'term_reset'  EXIT INT
    trap 'term_resize' WINCH

    while key=$(dd ibs=1 count=1 2>/dev/null); do
        case $key${esc:=0} in
            k?|A2) # ARROW UP
                y=$((y = y - 1 == 0 ? 1 : y - 1))

                print_line "$((y + 1))" "$@"
                printf '\033[A'
                print_line "$y" "$@"

                status_line
            ;;

            j?|B2) # ARROW DOWN
                end=$(($# < line_max ? $# : line_max))

                case $y in
                    "$end")
                        y=$end
                    ;;

                    *)
                        y=$((y + 1))

                        print_line "$((y - 1))" "$@"
                        printf '\n'
                        print_line "$y" "$@"

                        status_line "HELLO $y / $end"
                    ;;
                esac
            ;;

            l?|C2) # ARROW RIGHT
                if cd "$cur"; then
                    set -- *
                    list_reset
                    redraw "$@"
                else
                    "${EDITOR:=vi}" "$1"
                fi
            ;;

            h?|D2) # ARROW LEFT
                cd .. || continue
                set -- *
                list_reset
                redraw "$@"
            ;;

            q?)
                exit 0
            ;;

            # handle keys which emit escape sequences
            "$esc_char"*) esc=1 ;;
                    '[1') esc=2 ;;
                       *) esc=0 ;;
        esac
    done
}

main "$@"
