@@ -11,7 +11,7 @@ export ScreenEmulator, LineEmulator, Emulator, parse!, parse_cell!, Cell,
11
11
parseall!
12
12
import Base: convert, write
13
13
import REPL
14
- import REPL. Terminals: cmove_right
14
+ import REPL. Terminals: cmove_right, CSI
15
15
import Base: iterate, setindex!, getindex, lastindex
16
16
17
17
module Attributes
@@ -58,25 +58,42 @@ struct Cell
58
58
end
59
59
60
60
const colorlist = Dict (
61
- :black => 0 ,
62
- :red => 1 ,
63
- :green => 2 ,
64
- :yellow => 3 ,
65
- :blue => 4 ,
66
- :magenta => 5 ,
67
- :cyan => 6 ,
68
- :white => 7 ,
69
- :default => 9
61
+ :black => 0 ,
62
+ :red => 1 ,
63
+ :green => 2 ,
64
+ :yellow => 3 ,
65
+ :blue => 4 ,
66
+ :magenta => 5 ,
67
+ :cyan => 6 ,
68
+ :light_grey => 7 ,
69
+ :light_gray => 7 ,
70
+ :default => 9 ,
71
+ :dark_grey => 60 ,
72
+ :dark_gray => 60 ,
73
+ :light_red => 61 ,
74
+ :light_green => 62 ,
75
+ :light_yellow => 63 ,
76
+ :light_blue => 64 ,
77
+ :light_magenta => 65 ,
78
+ :light_cyan => 66 ,
79
+ :white => 67 ,
70
80
)
71
81
72
82
function Cell (c:: Cell ;
73
83
content = c. content, flags = c. flags, fg = c. fg, bg = c. bg,
74
84
attrs = c. attrs, fg_rgb = c. fg_rgb, bg_rgb = c. bg_rgb)
75
- isa (fg, Symbol) && (fg = colorlist[fg]; flags & ~ (FG_IS_256 | FG_IS_RGB))
76
- isa (bg, Symbol) && (bg = colorlist[bg]; flags & ~ (BG_IS_256 | BG_IS_RGB))
85
+ isa (fg, Symbol) && (fg = colorlist[fg]+ 30 ; flags & ~ (FG_IS_256 | FG_IS_RGB))
86
+ isa (bg, Symbol) && (bg = colorlist[bg]+ 40 ; flags & ~ (BG_IS_256 | BG_IS_RGB))
77
87
Cell (content,flags,fg,bg,attrs,fg_rgb,bg_rgb)
78
88
end
79
89
Cell (c:: Char ) = Cell (c,0 ,0 ,0 ,0 ,RGB8 (0 ,0 ,0 ),RGB8 (0 ,0 ,0 ))
90
+ Cell (;kwargs... ) = Cell (Cell (' ' ); kwargs... )
91
+ (c:: Cell )(ch:: Char ; kwargs... ) = Cell (c, content = ch; kwargs... )
92
+ Base. convert (:: Type{Cell} , c:: Char ) = Cell (c)
93
+ Base. size (c:: Cell ) = ()
94
+ Base. length (c:: Cell ) = 1
95
+ Base. iterate (c:: Cell ) = c, nothing
96
+ Base. iterate (c:: Cell , _) = nothing
80
97
81
98
# Encode x information if foreground color, y information in background color
82
99
# r encodes the lowest 8 bits, g the next, b the hight bits
@@ -108,6 +125,8 @@ mutable struct Line
108
125
Line () = new (Vector {Cell} (0 ),false )
109
126
Line (data:: Vector{Cell} ) = new (data,false )
110
127
end
128
+ Base. length (l:: Line ) = length (l. data)
129
+ Base. resize! (l:: Line , n:: Int ) = resize! (l. data, n)
111
130
iterate (l:: Line , args... ) = iterate (l. data, args... )
112
131
setindex! (l:: Line , c, i) = setindex! (l. data, c, i)
113
132
getindex (l:: Line ,i) = getindex (l. data,i)
@@ -125,7 +144,7 @@ struct Size
125
144
height:: Int
126
145
end
127
146
128
- abstract type Emulator end
147
+ abstract type Emulator <: AbstractArray{Cell, 2} end
129
148
130
149
mutable struct ScreenEmulator <: Emulator
131
150
ViewPortSize:: Size
@@ -145,9 +164,10 @@ mutable struct ScreenEmulator <: Emulator
145
164
this
146
165
end
147
166
end
167
+ Base. size (s:: ScreenEmulator ) = (s. ViewPortSize. height, s. ViewPortSize. width)
148
168
create_cell (em:: ScreenEmulator ,c:: Char ) = Cell (em. cur_cell, content = c)
149
169
cur_cell (em:: ScreenEmulator ) = em. cur_cell
150
- set_cur_cell (em:: ScreenEmulator ,c:: Cell ) = em. cur_cell = c
170
+ set_cur_cell! (em:: ScreenEmulator ,c:: Cell ) = em. cur_cell = c
151
171
function cmove (em:: ScreenEmulator , line, col)
152
172
em. debug && println (" Moving to $line :$col " )
153
173
targetline = em. firstline- 1 + line
@@ -178,6 +198,34 @@ function cmove_up(em::ScreenEmulator, n)
178
198
em. cursor = Cursor (em. cursor. line - n, em. cursor. column)
179
199
end
180
200
201
+ function Base. getindex (em:: ScreenEmulator , row:: Int , col:: Int )
202
+ if col > em. ViewPortSize. width
203
+ throw (BoundsError (em, row, col))
204
+ end
205
+ thisrow = em. lines[row]
206
+ l = length (thisrow)
207
+ if l < col
208
+ fill_space! (thisrow, l+ 1 , col)
209
+ end
210
+ return thisrow[col]
211
+ end
212
+
213
+ function Base. setindex! (em:: ScreenEmulator , c:: Union{Cell, Char} , line:: Int , col:: Int )
214
+ if col > em. ViewPortSize. width
215
+ throw (BoundsError (em, line, col))
216
+ end
217
+ while line > length (em. lines)
218
+ add_line! (em)
219
+ end
220
+ thisrow = em. lines[line]
221
+ l = length (thisrow)
222
+ if l < col
223
+ fill_space! (thisrow, l+ 1 , col)
224
+ end
225
+ thisrow[col] = c
226
+ return thisrow[col]
227
+ end
228
+
181
229
# An emulator that works a line at a time and does not support screen movement
182
230
# commands
183
231
mutable struct LineEmulator <: Emulator
@@ -255,15 +303,61 @@ const ExtendedContents = String[]
255
303
256
304
# Render the contents of this emulator into another terminal.
257
305
function render (term:: IO , em:: Emulator )
258
- dump (term,devnull ,em)
306
+ buf = IOBuffer ()
307
+ dump (buf,devnull ,em, render_content_decorators= true )
308
+ write (term, take! (buf))
309
+ end
310
+
311
+ function change_color (buf, is_fg, flags, color, rgb, is_256, is_rgb)
312
+ write (buf,CSI)
313
+ if (flags & is_256) != 0
314
+ write (buf, is_fg ? ' 3' : ' 4' , " 8;5;" ,string (color))
315
+ elseif (flags & is_rgb) != 0
316
+ write (buf, is_fg ? ' 3' : ' 4' , " 8;2;" ,string (rgb. r. i),' ;' ,
317
+ string (rgb. g. i),' ;' ,
318
+ string (rgb. b. i))
319
+ else
320
+ write (buf,string (color))
321
+ end
322
+ write (buf,' m' )
323
+ end
324
+
325
+ function change_fg_color (buf, cell)
326
+ change_color (buf, true , cell. flags, cell. fg, cell. fg_rgb, FG_IS_256, FG_IS_RGB)
327
+ end
328
+
329
+ function change_bg_color (buf, cell)
330
+ change_color (buf, false , cell. flags, cell. bg, cell. bg_rgb, BG_IS_256, BG_IS_RGB)
331
+ end
332
+
333
+ function change_attrs (buf, want, have)
334
+ # If we are clearing any bits
335
+ if (want & IsACS) != (have & IsACS)
336
+ write (buf,(want & IsACS) == 0 ? " \e (B" : " \e (0" )
337
+ end
338
+ if (have & ~ want) != 0
339
+ write (buf,CSI," 0m" )
340
+ have = 0
341
+ end
342
+ if (want & Bright) != 0
343
+ write (buf,CSI," 1m" )
344
+ end
345
+ end
346
+
347
+ function switch_cell_attrs (buf,wantc,attrs)
348
+ (wantc. bg != attrs. bg || wantc. bg_rgb != attrs. bg_rgb) && change_bg_color (buf,wantc)
349
+ (wantc. fg != attrs. fg || wantc. fg_rgb != attrs. fg_rgb) && change_fg_color (buf,wantc)
350
+ (wantc. attrs != attrs. attrs) && change_attrs (buf,wantc. attrs,attrs. attrs)
351
+ wantc
259
352
end
260
353
261
354
# Dump the emulator contents as a plain-contents text file and a decorator file
262
355
# Intended mostly for regression testing.
263
356
const default_decorators = [' A' :' z' ;' a' :' z' ;' 0' :' 9' ]
264
357
function dump (contents:: IO , decorator:: IO , em:: Emulator , lines = nothing , decorator_map = Dict {Cell,Char} (),
265
- available_decorators = copy (default_decorators))
358
+ available_decorators = copy (default_decorators); render_content_decorators = false )
266
359
first = true
360
+ attrs = Cell ()
267
361
for line in (lines === nothing ? em. lines : em. lines[lines])
268
362
if first
269
363
first = false
@@ -273,6 +367,9 @@ function dump(contents::IO, decorator::IO, em::Emulator, lines = nothing, decora
273
367
end
274
368
for cell in line
275
369
c = cell. content
370
+ if render_content_decorators
371
+ attrs = switch_cell_attrs (contents, cell, attrs)
372
+ end
276
373
if c < ' \U f0000'
277
374
write (contents,c)
278
375
else
@@ -287,6 +384,9 @@ function dump(contents::IO, decorator::IO, em::Emulator, lines = nothing, decora
287
384
write (decorator, decorator_map[template])
288
385
end
289
386
end
387
+ if render_content_decorators
388
+ switch_cell_attrs (contents, Cell (), attrs)
389
+ end
290
390
end
291
391
292
392
function fill_space! (line, from, to)
@@ -306,7 +406,7 @@ function insert_cell!(em, pos, c::Cell)
306
406
if pos > em. ViewPortSize. width
307
407
# Fill the remainder of this line with spaces
308
408
fill_space! (line, l+ 1 , em. ViewPortSize. width)
309
- # Remember that this line was wrapper
409
+ # Remember that this line was wrapped
310
410
line. wrapped = true
311
411
insert_line! (em)
312
412
cmove_down (em, 1 ); cmove_col (em, 1 )
@@ -433,9 +533,9 @@ function parseSGR!(em::Emulator, params)
433
533
error (" Incorrect SGR sequence" )
434
534
end
435
535
elseif 90 <= f1 <= 97
436
- set_cur_cell (em,Cell (cell,fg = f1- 90 , attrs= cell. attrs | Bright ))
536
+ set_cur_cell (em,Cell (cell,fg = f1, attrs= cell. attrs))
437
537
elseif 100 <= f1 <= 107
438
- set_cur_cell (em,Cell (cell,fg = f1- 100 , attrs= cell. attrs | Bright ))
538
+ set_cur_cell (em,Cell (cell,bg = f1, attrs= cell. attrs))
439
539
else
440
540
error (" Unimplemented CSIm $f1 " )
441
541
end
0 commit comments