n-list-draw 4.07 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
# 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"
101
[[ "$active_text" = "underline" || "$active_text" = "reverse" ]] || local active_text="reverse"
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
# 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: