n-list-draw 4.06 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# Copy this file into /usr/share/zsh/site-functions/
# and add 'autoload n-list-draw` to .zshrc
#
# This is an internal function not for direct use

emulate -L zsh

zmodload zsh/curses

setopt typesetsilent extendedglob

_nlist_print_with_ansi() {
    local win="$1" text="$2" out col chunk Xout
    integer text_offset="$3" max_text_len="$4" text_len=0 no_match=0 nochunk_text_len to_skip_from_chunk to_chop_off_from_chunk before_len

    # 1 - non-escaped text, 2 - first number in the escaped text, with ;
    # 3 - second number, 4 - text after whole escape text

    typeset -a c
    c=( black red green yellow blue magenta cyan white )

    while [[ -n "$text" && "$no_match" -eq 0 ]]; do
        if [[ "$text" = (#b)([^$'\x1b']#)$'\x1b'\[([0-9](#c0,2))(#B)(\;|)(#b)([0-9](#c0,2))m(*) ]]; then
            # Text for further processing
            text="$match[4]"
            # Text chunk to output now
            out="$match[1]"
            # Save color
            col="$match[2]"
            (( match[3] >= 30 && match[3] <= 37 )) && col="$match[3]"
        else
            out="$text"
            no_match=1
        fi

        if [ -n "$out" ]; then
################ Expand tabs ################
            chunk="$out"
            before_len="$text_len"
            Xout=""

            while [ -n "$chunk" ]; do
                [[ "$chunk" = (#b)([^$'\t']#)$'\t'(*) ]] && {
                    (( all_text_len=((before_len+${#match[1]})/8+1)*8 ))

                    Xout+="${(r:all_text_len-before_len:: :)match[1]}"

                    before_len+=all_text_len-before_len
                    chunk="$match[2]"
                } || {
                    Xout+="$chunk"
                    break
                }
            done
#############################################

            # Input text length without the current chunk
            nochunk_text_len=text_len
            # Input text length up to current chunk
            text_len+="$#Xout"

            # Should start displaying with this chunk?
            # I.e. stop skipping left part of the input text?
            if (( text_len > text_offset )); then
                to_skip_from_chunk=text_offset-nochunk_text_len

                # LEFT - is chunk off the left skip boundary? +1 for 1-based index in string
                (( to_skip_from_chunk > 0 )) && Xout="${Xout[to_skip_from_chunk+1,-1]}"

                # RIGHT - is text off the screen?
                if (( text_len-text_offset > max_text_len )); then
                    to_chop_off_from_chunk=0+(text_len-text_offset)-max_text_len
                    Xout="${Xout[1,-to_chop_off_from_chunk-1]}"
                fi
                
                [ -n "$Xout" ] && zcurses string "$win" "$Xout"
            fi
        fi

        if (( no_match == 0 )); then
            if (( col >= 30 && col <= 37 )); then
                zcurses attr "$win" $c[col-29]/black
            elif [[ "$col" -eq 0 ]]; then
                zcurses attr "$win" white/black
            fi
        fi
    done
}

integer highlight="$1"
integer page_height="$2"
integer page_width="$3"
local y_offset="$4"
local x_offset="$5"
local text_offset="$6"
local win="$7"
shift 7
integer max_text_len=page_width-x_offset

[ "$bold" = "0" ] && bold="" || bold="+bold"
[[ "$active_text" = "underline" || "$active_text" = "reverse" ]] || active_text="reverse"
# With Linux terminal underline won't work properly
[ "$TERM" = "linux" ] && active_text="reverse"

integer max_idx=page_height
integer end_idx=max_idx
[ "$end_idx" -gt "$#" ] && end_idx="$#"
integer y=y_offset

zcurses attr "$win" $bold white/black

integer i text_len
local text
for (( i=1; i<=end_idx; i++ )); do
    zcurses move "$win" $y "$x_offset"

    [ "$i" = "$highlight" ] && zcurses attr "$win" +"$active_text"
    _nlist_print_with_ansi "$win" "$@[i]" "$text_offset" "$max_text_len"
    zcurses clear "$win" eol
    [ "$i" = "$highlight" ] && zcurses attr "$win" -"$active_text"

    y+=1
done

if [ "$end_idx" -lt "$max_idx" ]; then
    zcurses move "$win" $y "$x_offset"
    zcurses clear "$win" eol
fi

zcurses attr "$win" white/black
# vim: set filetype=zsh: