-
Notifications
You must be signed in to change notification settings - Fork 12
/
ansi-seq.red
238 lines (215 loc) · 4.79 KB
/
ansi-seq.red
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
Red [
Title: "Ansi sequence dialect"
Author: "Boleslav Březovský"
Usage: {
# Function
ANSI/DO block! - print dialect
ANSI/TRANS block! - convert dialect to string!
# Dialect
CLS - clear screen
CLEAR - clear screen
CLEAR LINE - clear whole line
CLEAR LINE LEFT - clear line from cursor to line start
CLEAR LINE RIGHT - clear line from cursor to line end
CLEAR SCREEN - clear screen
CLEAR SCREEN UP - clear screen from cursor to top of screen
CLEAR SCREEN DOWN - clear screen from cursor to bottom of screen
AT pair! - put curspor at position
FG word! - set foregroud to color
BG word! - set background to color
BOLD - set bold style
ITALIC - set italic style
UNDERLINE - set underline style
UP - move cursor up
DOWN - move cursor down
LEFT - move cursor left
RIGHT - move cursor right
RESET - reset all styles
}
]
ansi: context [
win?: system/platform = 'Windows
esc-main: "^[["
clear-screen: append copy esc-main "2J"
set-position: func [position][
rejoin [esc-main form position/y #";" form position/x #"H"]
]
demo: does [
do [cls at 1x1 fg red "Welcome to " fg black bg white "A" bg yellow "N" bg red "S" bg magenta "I" reset bold space underline fg bright green "con" reset fg green italic "sole" reset]
]
colors: [black red green yellow blue magenta cyan white none default]
as-rule: func [block][
block: collect [
foreach value block [keep reduce [to lit-word! value '|]]
]
also block take/last block
]
colors-list: as-rule colors
color-rule: [
set type ['fg | 'bg]
(bright?: false)
opt ['bright (bright?: true)]
set value colors-list
keep (
type: pick [3 4] equal? 'fg type
if bright? [type: type + 6]
value: -1 + index? find colors value
either win? [""][
rejoin [esc-main form type value #"m"]
]
)
]
move-rule: [
(value: 1)
set type ['up | 'down | 'left | 'right]
opt [set value integer!]
keep (rejoin [esc-main form value #"@" + index? find [up down left right] type])
]
style-rule: [
set type ['bold | 'italic | 'underline | 'inverse]
keep (
either win? [""][
rejoin [esc-main form select [bold 1 italic 3 underline 4 inverse 7] type #"m"]
]
)
]
clear-rule: [
(type: value: none)
'clear
opt [
set type [
'line opt [set value ['left | 'right]]
| 'screen opt [set value ['up | 'down]]
]
]
keep (
case [
not type (rejoin [esc-main "2J"])
type = 'line [
rejoin [
esc-main
switch/default value [left "1" right "0"]["2"]
#"K"
]
]
type = 'screen [
rejoin [
esc-main
switch/default value [up "1" down "0"]["2"]
#"J"
]
]
]
)
]
type: value: bright?: none
trans: func [
data
][
parse data [
collect [
some [
'reset keep (either win? [""][rejoin [esc-main "0m"]])
| 'cls keep (clear-screen)
| clear-rule
| style-rule
| move-rule
| color-rule
| 'at set value pair! keep (set-position value)
| keep [word! | string! | char!]
]
]
]
]
do: func [data][
if block? data [data: trans data]
print rejoin data
]
vline: func [
pos
height
][
collect [
repeat i height [
keep reduce ['at pos + (i * 0x1) "│"]
]
]
]
tui: func [
data
/local cmd value stack
box-rule
][
stack: []
dialect: clear []
box-rule: [
(clear stack)
'box
set value pair! (append stack value)
set value pair! (append stack value)
(
width: stack/2/x - stack/1/x - 1
height: stack/2/y - stack/1/y - 1
repend dialect ['at stack/1 + 1x0 append/dup copy "" #"─" width] ; top line
repend dialect ['at stack/1 + (height + 1 * 0x1) + 1x0 append/dup copy "" #"─" width] ; bottom line
append dialect vline stack/1 height
append dialect vline stack/1 + 1x0 + (width * 1x0) height
repend dialect ['at stack/1 "┌"] ; top-left copner
repend dialect ['at stack/1 + (width + 1 * 1x0) "┐"] ; top-right corner
repend dialect ['at stack/1 + (height + 1 * 0x1) "└"] ; bottom-left copner
repend dialect ['at stack/2 "┘"] ; bottom-right copner
)
]
pass-rule: [
set value skip (append dialect value)
]
parse data [
some [
box-rule
| pass-rule
]
]
dialect
]
; --- DECODER
octet: charset "01234567"
m: #"m"
set-color: func [color][
if char? color [color: to integer! color - 48]
pick colors color + 1
]
ansi-seqs: [
"2J" ; clear screen
| #"3" set value octet m (cmd: reduce ['fg set-color value] emit) ; foreground
| #"4" set value octet m (cmd: reduce ['bg set-color value] emit) ; background
| "0m" (cmd: 'reset emit)
| "1m" (cmd: 'bold emit)
| "3m" (cmd: 'italic emit)
| "4m" (cmd: 'underline emit)
]
decode-rules: [
some [
esc-main ansi-seqs
| set value skip (append str value)
]
]
emit: does [
append result copy str
if cmd [append result cmd]
clear str
cmd: none
]
result: []
str: ""
cmd: none
decode: func [
string
][
clear str
clear result
parse string decode-rules
emit
result
]
; -- end of context
]