# Copy this file into /usr/share/zsh/site-functions/
# and add 'autoload n-preview` to .zshrc
#
# This is partially a test if n-list-draw and n-list-input can be
# used multiple times to create multiple lists. It might become
# more usable if someone adds more features like previewing of
# archive contents.

emulate -L zsh

zmodload zsh/curses

setopt typesetsilent extendedglob
trap "return" TERM INT QUIT
trap "_vpreview_exit" EXIT

local IFS="
"

[ -f ~/.config/znt/n-list.conf ] && . ~/.config/znt/n-list.conf

[[ "$colorpair" = "" ]] && colorpair="white/black"
local background="${colorpair#*/}"

# Drawing and input
autoload n-list-draw n-list-input

# Cleanup before any exit
_vpreview_exit() {
    zcurses 2>/dev/null delwin files
    zcurses 2>/dev/null delwin body 
    zcurses 2>/dev/null delwin status
    zcurses 2>/dev/null refresh
    zcurses end
}

# Outputs a message in the bottom of the screen
_vpreview_status_msg() {
    zcurses move status 1 2
    zcurses clear status eol
    zcurses string status "$1"
}

# Prefer tput, then module terminfo
_nlist_cursor_visibility() {
    if type tput 2>/dev/null 1>&2; then
        [ "$1" = "1" ] && tput cvvis
        [ "$1" = "0" ] && tput civis
    elif [ "$has_termcap" = "1" ]; then
        [ "$1" = "1" ] && [ -n $terminfo[cvvis] ] && echo -n $terminfo[cvvis]
        [ "$1" = "0" ] && [ -n $terminfo[civis] ] && echo -n $terminfo[civis]
    fi 
}

#
# Main code
#

integer term_height="$LINES"
integer term_width="$COLUMNS"
if [[ "$term_height" -lt 1 || "$term_width" -lt 1 ]]; then
    local stty_out=$( stty size )
    term_height="${stty_out% *}"
    term_width="${stty_out#* }"
fi

integer status_height=3
integer status_width=term_width
integer status_page_height=1
integer status_page_width=term_width-2

integer files_height=term_height-status_height
integer files_width=term_width/5
integer files_page_height=files_height-2
integer files_page_width=files_width-2

integer body_height=term_height-status_height
integer body_width=term_width-files_width
integer body_page_height=body_height-2
integer body_page_width=body_width

integer _from_what_idx_list_is_shown_1=1
integer current_1=1

integer _from_what_idx_list_is_shown_2=1
integer current_2=1
integer hscroll_2=0

integer active_window=0

local ansi_mode="ansi"
[ -f ~/.config/znt/n-preview.conf ] && . ~/.config/znt/n-preview.conf
typeset -a hcmd
#if type pygmentize 2>/dev/null 1>&2; then
#    hcmd=( pygmentize -g )
if type highlight 2>/dev/null 1>&2; then
    hcmd=( highlight -q --force -O ansi )
elif type source-highlight 2>/dev/null 1>&2; then
    # Warning: source-highlight can have problems
    hcmd=( source-highlight --failsafe -fesc -o STDOUT -i )
else
    ansi_mode="noansi"
fi

zcurses init
zcurses addwin status "$status_height" "$status_width" $(( term_height - status_height )) 0
zcurses addwin files "$files_height" "$files_width" 0 0
zcurses addwin body "$body_height" "$body_width" 0 "$files_width"
zcurses bg status white/black
zcurses bg files white/black
zcurses bg body white/black

#
# Listening for input
#

local key keypad

# Clear input buffer
zcurses timeout status 0
zcurses input status key keypad
zcurses timeout status -1
key=""
keypad=""

typeset -a filenames
integer last_element_1

typeset -a body
integer last_element_2

filenames=( *(N) )
filenames=( "${(@M)filenames:#(#i)*$1*}" )

local NLIST_GREP_STRING="$1"

integer last_element_1="$#filenames"
integer last_element_2=0

local selection action final_key

while (( 1 )); do
    # Output the lists
    integer end_idx=$(( _from_what_idx_list_is_shown_1 + files_page_height - 1 ))
    [ "$end_idx" -gt "$last_element_1" ] && end_idx=last_element_1

    n-list-draw "$(( (current_1 -1) % files_page_height + 1 ))" \
                    "$files_page_height" "$files_page_width" 1 2 0 files \
                    "${(@)filenames[_from_what_idx_list_is_shown_1, end_idx]}"

    if [ "$#body" -ge 1 ]; then
        end_idx=$(( _from_what_idx_list_is_shown_2 + body_page_height - 1 ))
        [ "$end_idx" -gt "$last_element_2" ] && end_idx=last_element_2

        n-list-draw "$(( (current_2 -1) % body_page_height + 1 ))" \
                        "$body_page_height" "$body_page_width" 1 0 "$hscroll_2" body \
                        "${(@)body[_from_what_idx_list_is_shown_2, end_idx]}"
    fi

    [[ "$active_window" -eq 0 ]] && zcurses border files
    zcurses border status
    zcurses refresh files body status 

    # Wait for input
    zcurses input status key keypad

    # Get the special (i.e. "keypad") key or regular key
    if [ -n "$key" ]; then
        final_key="$key" 
    elif [ -n "$keypad" ]; then
        final_key="$keypad"
    else
        _vpreview_status_msg "Inproper input detected"
        zcurses refresh status 
    fi

    if [ "$active_window" -eq 0 ]; then
        zcurses clear files
        n-list-input "$current_1" "$_from_what_idx_list_is_shown_1" "$files_page_height" \
            "$files_page_width" "$last_element_1" 0 "$final_key"

        selection="$reply[1]"
        action="$reply[2]"
        current_1="$reply[3]"
        _from_what_idx_list_is_shown_1="$reply[4]"

        if [ "$action" = "SELECT" ]; then
            # Load new file and refresh the displaying window
            local filename="$filenames[$selection]"
            if [ "$ansi_mode" = "ansi" ]; then
                body=( "${(@f)"$( "$hcmd[@]" "$filename" )"}" )
            else
                body=( "${(@f)"$(<$filename)"}" )
            fi
            last_element_2="$#body"
            current_2=1
            _from_what_idx_list_is_shown_2=1
            zcurses clear body
        fi
    elif [ "$active_window" -eq 1 ]; then
        zcurses clear body
        n-list-input "$current_2" "$_from_what_idx_list_is_shown_2" "$body_page_height" \
            "$body_page_width" "$last_element_2" "$hscroll_2" "$final_key"

        selection="$reply[1]"
        action="$reply[2]"
        current_2="$reply[3]"
        _from_what_idx_list_is_shown_2="$reply[4]"
        hscroll_2="$reply[5]"

    fi

    if [ "$action" = "LEAVE" ]; then
        active_window=1-active_window
    elif [ "$action" = "QUIT" ]; then
            break
    elif [ "$action" = "REDRAW" ]; then
        zcurses clear files redraw
        zcurses clear body redraw
        zcurses clear status redraw
    fi
done

# vim: set filetype=zsh: