stevenkhan commited on
Commit
05879f6
·
verified ·
1 Parent(s): 86c91c8

Upload spectral-core/src/term.rs

Browse files
Files changed (1) hide show
  1. spectral-core/src/term.rs +572 -0
spectral-core/src/term.rs ADDED
@@ -0,0 +1,572 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ use crate::ansi::Perform;
2
+ use crate::cell::CellFlags;
3
+ use crate::color::ANSI_COLORS;
4
+ use crate::config::{Config, CursorStyle};
5
+ use crate::damage::Damage;
6
+ use crate::grid::Grid;
7
+
8
+ pub struct Terminal {
9
+ pub grid: Grid,
10
+ pub config: Config,
11
+
12
+ pub cursor_style: CursorStyle,
13
+ pub cursor_visible: bool,
14
+ pub auto_wrap: bool,
15
+ pub insert_mode: bool,
16
+ pub reverse_video: bool,
17
+ pub origin_mode: bool,
18
+ pub bracketed_paste: bool,
19
+ pub focus_tracking: bool,
20
+ pub mouse_tracking: bool,
21
+
22
+ pub fg_color: u32,
23
+ pub bg_color: u32,
24
+ pub sgr_flags: CellFlags,
25
+
26
+ pub damage: Damage,
27
+ pub cursor_blink_phase: bool,
28
+ pub dirty_cursor: bool,
29
+ }
30
+
31
+ impl Terminal {
32
+ pub fn new(config: Config) -> Self {
33
+ let mut grid = Grid::new(config.cols, config.rows, config.scrollback_limit);
34
+ grid.clear_screen();
35
+ let cfg = config.clone();
36
+ Self {
37
+ grid,
38
+ config,
39
+ cursor_style: cfg.cursor_style,
40
+ cursor_visible: true,
41
+ auto_wrap: true,
42
+ insert_mode: false,
43
+ reverse_video: false,
44
+ origin_mode: false,
45
+ bracketed_paste: false,
46
+ focus_tracking: false,
47
+ mouse_tracking: false,
48
+ fg_color: cfg.foreground_color,
49
+ bg_color: cfg.background_color,
50
+ sgr_flags: CellFlags::empty(),
51
+ damage: Damage::Full,
52
+ cursor_blink_phase: true,
53
+ dirty_cursor: true,
54
+ }
55
+ }
56
+
57
+ pub fn feed(&mut self, bytes: &[u8]) {
58
+ let mut parser = crate::ansi::Parser::new();
59
+ parser.advance(self, bytes);
60
+ }
61
+
62
+ pub fn resize(&mut self, cols: usize, rows: usize) {
63
+ self.grid.resize(cols, rows);
64
+ self.damage = Damage::Full;
65
+ }
66
+
67
+ pub fn tick_blink(&mut self) {
68
+ if self.config.cursor_blink {
69
+ self.cursor_blink_phase = !self.cursor_blink_phase;
70
+ self.dirty_cursor = true;
71
+ }
72
+ }
73
+
74
+ fn write_char(&mut self, ch: char) {
75
+ let row = self.grid.cursor_row;
76
+ let col = self.grid.cursor_col;
77
+
78
+ if let Some(line) = self.grid.line_mut(row) {
79
+ if let Some(cell) = line.cells.get_mut(col) {
80
+ cell.ch = ch;
81
+ cell.fg = self.fg_color;
82
+ cell.bg = self.bg_color;
83
+ cell.flags = self.sgr_flags;
84
+ line.dirty = true;
85
+ self.damage.add_line(row, col, col + 1);
86
+ }
87
+ }
88
+
89
+ if self.grid.cursor_col + 1 < self.grid.cols {
90
+ self.grid.cursor_col += 1;
91
+ } else if self.auto_wrap {
92
+ self.grid.cursor_col = 0;
93
+ if self.grid.cursor_row + 1 >= self.grid.bottom_margin + 1 {
94
+ self.grid.scroll_up(1);
95
+ } else {
96
+ self.grid.cursor_row += 1;
97
+ }
98
+ }
99
+ }
100
+ }
101
+
102
+ impl Perform for Terminal {
103
+ fn print(&mut self, ch: char) {
104
+ self.write_char(ch);
105
+ }
106
+
107
+ fn execute(&mut self, byte: u8) {
108
+ match byte {
109
+ 0x07 => { }
110
+ 0x08 => {
111
+ if self.grid.cursor_col > 0 {
112
+ self.grid.cursor_col -= 1;
113
+ }
114
+ }
115
+ 0x09 => {
116
+ let next_tab = ((self.grid.cursor_col / 8) + 1) * 8;
117
+ self.grid.cursor_col = next_tab.min(self.grid.cols - 1);
118
+ }
119
+ 0x0A | 0x0B | 0x0C => {
120
+ if self.grid.cursor_row + 1 >= self.grid.bottom_margin + 1 {
121
+ self.grid.scroll_up(1);
122
+ } else {
123
+ self.grid.cursor_row += 1;
124
+ }
125
+ }
126
+ 0x0D => {
127
+ self.grid.cursor_col = 0;
128
+ }
129
+ 0x0E => { }
130
+ 0x0F => { }
131
+ _ => {}
132
+ }
133
+ }
134
+
135
+ fn csi_dispatch(&mut self, params: &[u16], _intermediates: &[u8], _ignore: bool, action: char) {
136
+ match action {
137
+ 'm' => self.handle_sgr(params),
138
+ 'H' | 'f' => self.handle_cup(params),
139
+ 'J' => self.handle_ed(params),
140
+ 'K' => self.handle_el(params),
141
+ 'A' => self.handle_cuu(params),
142
+ 'B' => self.handle_cud(params),
143
+ 'C' => self.handle_cuf(params),
144
+ 'D' => self.handle_cub(params),
145
+ 'E' => self.handle_cnl(params),
146
+ 'F' => self.handle_cpl(params),
147
+ 'G' => self.handle_cha(params),
148
+ 'd' => self.handle_vpa(params),
149
+ 'n' => self.handle_dsr(params),
150
+ 'h' => self.handle_sm(params),
151
+ 'l' => self.handle_rm(params),
152
+ 'r' => self.handle_decstbm(params),
153
+ 'L' => self.handle_il(params),
154
+ 'M' => self.handle_dl(params),
155
+ 'P' => self.handle_dch(params),
156
+ '@' => self.handle_ich(params),
157
+ 'X' => self.handle_ech(params),
158
+ 'c' => self.handle_da(params),
159
+ 'g' => self.handle_tbc(params),
160
+ _ => {}
161
+ }
162
+ }
163
+
164
+ fn esc_dispatch(&mut self, _intermediates: &[u8], _ignore: bool, byte: u8) {
165
+ match byte {
166
+ b'c' => {
167
+ *self = Terminal::new(self.config.clone());
168
+ }
169
+ b'7' => {
170
+ self.grid.saved_cursor_row = self.grid.cursor_row;
171
+ self.grid.saved_cursor_col = self.grid.cursor_col;
172
+ }
173
+ b'8' => {
174
+ self.grid.cursor_row = self.grid.saved_cursor_row;
175
+ self.grid.cursor_col = self.grid.saved_cursor_col;
176
+ }
177
+ b'M' => {
178
+ if self.grid.cursor_row == self.grid.top_margin {
179
+ self.grid.scroll_down(1);
180
+ } else if self.grid.cursor_row > 0 {
181
+ self.grid.cursor_row -= 1;
182
+ }
183
+ }
184
+ _ => {}
185
+ }
186
+ }
187
+
188
+ fn osc_dispatch(&mut self, params: &[&[u8]]) {
189
+ if params.is_empty() {
190
+ return;
191
+ }
192
+ let param0 = std::str::from_utf8(params[0]).unwrap_or("");
193
+ match param0.parse::<u32>() {
194
+ Ok(0) | Ok(2) => { }
195
+ Ok(7) => { }
196
+ Ok(8) => { }
197
+ Ok(52) => { }
198
+ _ => { }
199
+ }
200
+ }
201
+
202
+ fn dcs_hook(&mut self, _params: &[u16], _intermediates: &[u8], _ignore: bool, _action: char) {}
203
+ fn dcs_put(&mut self, _byte: u8) {}
204
+ fn dcs_unhook(&mut self) {}
205
+ }
206
+
207
+ macro_rules! param_or {
208
+ ($params:expr, $idx:expr, $default:expr) => {
209
+ $params.get($idx).copied().filter(|&v| v != 0).unwrap_or($default)
210
+ };
211
+ }
212
+
213
+ impl Terminal {
214
+ fn handle_sgr(&mut self, params: &[u16]) {
215
+ if params.is_empty() {
216
+ self.fg_color = self.config.foreground_color;
217
+ self.bg_color = self.config.background_color;
218
+ self.sgr_flags = CellFlags::empty();
219
+ return;
220
+ }
221
+
222
+ let mut i = 0;
223
+ while i < params.len() {
224
+ match params[i] {
225
+ 0 => {
226
+ self.fg_color = self.config.foreground_color;
227
+ self.bg_color = self.config.background_color;
228
+ self.sgr_flags = CellFlags::empty();
229
+ }
230
+ 1 => self.sgr_flags.insert(CellFlags::BOLD),
231
+ 3 => self.sgr_flags.insert(CellFlags::ITALIC),
232
+ 4 => self.sgr_flags.insert(CellFlags::UNDERLINE),
233
+ 5 | 6 => self.sgr_flags.insert(CellFlags::BLINK),
234
+ 7 => self.sgr_flags.insert(CellFlags::REVERSE),
235
+ 8 => self.sgr_flags.insert(CellFlags::HIDDEN),
236
+ 9 => self.sgr_flags.insert(CellFlags::STRIKETHROUGH),
237
+ 21 => self.sgr_flags.remove(CellFlags::BOLD),
238
+ 22 => self.sgr_flags.remove(CellFlags::BOLD),
239
+ 23 => self.sgr_flags.remove(CellFlags::ITALIC),
240
+ 24 => self.sgr_flags.remove(CellFlags::UNDERLINE),
241
+ 25 => self.sgr_flags.remove(CellFlags::BLINK),
242
+ 27 => self.sgr_flags.remove(CellFlags::REVERSE),
243
+ 28 => self.sgr_flags.remove(CellFlags::HIDDEN),
244
+ 29 => self.sgr_flags.remove(CellFlags::STRIKETHROUGH),
245
+ 30..=37 => {
246
+ let idx = (params[i] - 30) as usize;
247
+ self.fg_color = ANSI_COLORS[idx];
248
+ }
249
+ 38 => {
250
+ if let Some(color) = self.parse_extended_color(params, &mut i) {
251
+ self.fg_color = color;
252
+ }
253
+ }
254
+ 39 => self.fg_color = self.config.foreground_color,
255
+ 40..=47 => {
256
+ let idx = (params[i] - 40) as usize;
257
+ self.bg_color = ANSI_COLORS[idx];
258
+ }
259
+ 48 => {
260
+ if let Some(color) = self.parse_extended_color(params, &mut i) {
261
+ self.bg_color = color;
262
+ }
263
+ }
264
+ 49 => self.bg_color = self.config.background_color,
265
+ 90..=97 => {
266
+ let idx = (params[i] - 90 + 8) as usize;
267
+ self.fg_color = ANSI_COLORS[idx];
268
+ }
269
+ 100..=107 => {
270
+ let idx = (params[i] - 100 + 8) as usize;
271
+ self.bg_color = ANSI_COLORS[idx];
272
+ }
273
+ _ => {}
274
+ }
275
+ i += 1;
276
+ }
277
+ }
278
+
279
+ fn parse_extended_color(&self, params: &[u16], i: &mut usize) -> Option<u32> {
280
+ *i += 1;
281
+ match params.get(*i)? {
282
+ 2 => {
283
+ *i += 1;
284
+ let r = params.get(*i).copied().unwrap_or(0) as u32;
285
+ *i += 1;
286
+ let g = params.get(*i).copied().unwrap_or(0) as u32;
287
+ *i += 1;
288
+ let b = params.get(*i).copied().unwrap_or(0) as u32;
289
+ Some(0xFF_000000 | (r << 16) | (g << 8) | b)
290
+ }
291
+ 5 => {
292
+ *i += 1;
293
+ let idx = params.get(*i).copied().unwrap_or(0) as usize;
294
+ Some(extended_256_color(idx))
295
+ }
296
+ _ => None,
297
+ }
298
+ }
299
+
300
+ fn handle_cup(&mut self, params: &[u16]) {
301
+ let row = param_or!(params, 0, 1).saturating_sub(1) as usize;
302
+ let col = param_or!(params, 1, 1).saturating_sub(1) as usize;
303
+ let base = if self.origin_mode { self.grid.top_margin } else { 0 };
304
+ self.grid.cursor_row = (base + row).min(self.grid.rows.saturating_sub(1));
305
+ self.grid.cursor_col = col.min(self.grid.cols.saturating_sub(1));
306
+ }
307
+
308
+ fn handle_ed(&mut self, params: &[u16]) {
309
+ let mode = param_or!(params, 0, 0);
310
+ let row = self.grid.cursor_row;
311
+ let col = self.grid.cursor_col;
312
+
313
+ match mode {
314
+ 0 => {
315
+ self.grid.clear_line_right(row, col);
316
+ for r in (row + 1)..self.grid.rows {
317
+ self.grid.clear_line(r);
318
+ }
319
+ self.damage = Damage::Full;
320
+ }
321
+ 1 => {
322
+ self.grid.clear_line_left(row, col);
323
+ for r in 0..row {
324
+ self.grid.clear_line(r);
325
+ }
326
+ self.damage = Damage::Full;
327
+ }
328
+ 2 | 3 => {
329
+ self.grid.clear_screen();
330
+ if mode == 3 {
331
+ self.grid.scrollback.clear();
332
+ }
333
+ self.damage = Damage::Full;
334
+ }
335
+ _ => {}
336
+ }
337
+ }
338
+
339
+ fn handle_el(&mut self, params: &[u16]) {
340
+ let mode = param_or!(params, 0, 0);
341
+ let row = self.grid.cursor_row;
342
+ let col = self.grid.cursor_col;
343
+
344
+ match mode {
345
+ 0 => self.grid.clear_line_right(row, col),
346
+ 1 => self.grid.clear_line_left(row, col),
347
+ 2 => self.grid.clear_line(row),
348
+ _ => {}
349
+ }
350
+ }
351
+
352
+ fn handle_cuu(&mut self, params: &[u16]) {
353
+ let n = param_or!(params, 0, 1) as usize;
354
+ let top = if self.origin_mode { self.grid.top_margin } else { 0 };
355
+ self.grid.cursor_row = self.grid.cursor_row.saturating_sub(n).max(top);
356
+ }
357
+
358
+ fn handle_cud(&mut self, params: &[u16]) {
359
+ let n = param_or!(params, 0, 1) as usize;
360
+ let bottom = if self.origin_mode {
361
+ self.grid.bottom_margin
362
+ } else {
363
+ self.grid.rows.saturating_sub(1)
364
+ };
365
+ self.grid.cursor_row = (self.grid.cursor_row + n).min(bottom);
366
+ }
367
+
368
+ fn handle_cuf(&mut self, params: &[u16]) {
369
+ let n = param_or!(params, 0, 1) as usize;
370
+ self.grid.cursor_col = (self.grid.cursor_col + n).min(self.grid.cols.saturating_sub(1));
371
+ }
372
+
373
+ fn handle_cub(&mut self, params: &[u16]) {
374
+ let n = param_or!(params, 0, 1) as usize;
375
+ self.grid.cursor_col = self.grid.cursor_col.saturating_sub(n);
376
+ }
377
+
378
+ fn handle_cnl(&mut self, params: &[u16]) {
379
+ let n = param_or!(params, 0, 1) as usize;
380
+ self.grid.cursor_col = 0;
381
+ self.handle_cud(&[n as u16]);
382
+ }
383
+
384
+ fn handle_cpl(&mut self, params: &[u16]) {
385
+ let n = param_or!(params, 0, 1) as usize;
386
+ self.grid.cursor_col = 0;
387
+ self.handle_cuu(&[n as u16]);
388
+ }
389
+
390
+ fn handle_cha(&mut self, params: &[u16]) {
391
+ let col = param_or!(params, 0, 1).saturating_sub(1) as usize;
392
+ self.grid.cursor_col = col.min(self.grid.cols.saturating_sub(1));
393
+ }
394
+
395
+ fn handle_vpa(&mut self, params: &[u16]) {
396
+ let row = param_or!(params, 0, 1).saturating_sub(1) as usize;
397
+ let base = if self.origin_mode { self.grid.top_margin } else { 0 };
398
+ self.grid.cursor_row = (base + row).min(self.grid.rows.saturating_sub(1));
399
+ }
400
+
401
+ fn handle_dsr(&mut self, _params: &[u16]) { }
402
+
403
+ fn handle_sm(&mut self, params: &[u16]) {
404
+ for &param in params {
405
+ match param {
406
+ 1 => { }
407
+ 7 => self.auto_wrap = true,
408
+ 25 => self.cursor_visible = true,
409
+ 1049 => { }
410
+ 1000 => self.mouse_tracking = true,
411
+ 1002 => self.mouse_tracking = true,
412
+ 1004 => self.focus_tracking = true,
413
+ 2004 => self.bracketed_paste = true,
414
+ _ => {}
415
+ }
416
+ }
417
+ }
418
+
419
+ fn handle_rm(&mut self, params: &[u16]) {
420
+ for &param in params {
421
+ match param {
422
+ 7 => self.auto_wrap = false,
423
+ 25 => self.cursor_visible = false,
424
+ 1049 => { }
425
+ 1000 => self.mouse_tracking = false,
426
+ 1002 => self.mouse_tracking = false,
427
+ 1004 => self.focus_tracking = false,
428
+ 2004 => self.bracketed_paste = false,
429
+ _ => {}
430
+ }
431
+ }
432
+ }
433
+
434
+ fn handle_decstbm(&mut self, params: &[u16]) {
435
+ let top = param_or!(params, 0, 1).saturating_sub(1) as usize;
436
+ let bottom = param_or!(params, 1, self.grid.rows as u16) as usize;
437
+ if top < bottom && bottom <= self.grid.rows {
438
+ self.grid.top_margin = top;
439
+ self.grid.bottom_margin = bottom.saturating_sub(1);
440
+ self.grid.cursor_row = top;
441
+ self.grid.cursor_col = 0;
442
+ }
443
+ }
444
+
445
+ fn handle_il(&mut self, params: &[u16]) {
446
+ let n = param_or!(params, 0, 1) as usize;
447
+ let row = self.grid.cursor_row;
448
+ let top = self.grid.top_margin;
449
+ let bottom = self.grid.bottom_margin;
450
+ let cols = self.grid.cols;
451
+
452
+ for _ in 0..n {
453
+ if row <= bottom {
454
+ self.grid.lines.remove(bottom);
455
+ let mut new_line = crate::grid::Line::new(cols);
456
+ new_line.dirty = true;
457
+ self.grid.lines.insert(row, new_line);
458
+ }
459
+ }
460
+ for i in top..=bottom {
461
+ if let Some(line) = self.grid.lines.get_mut(i) {
462
+ line.dirty = true;
463
+ }
464
+ }
465
+ self.damage = Damage::Full;
466
+ }
467
+
468
+ fn handle_dl(&mut self, params: &[u16]) {
469
+ let n = param_or!(params, 0, 1) as usize;
470
+ let row = self.grid.cursor_row;
471
+ let top = self.grid.top_margin;
472
+ let bottom = self.grid.bottom_margin;
473
+ let cols = self.grid.cols;
474
+
475
+ for _ in 0..n {
476
+ if row <= bottom {
477
+ self.grid.lines.remove(row);
478
+ let mut new_line = crate::grid::Line::new(cols);
479
+ new_line.dirty = true;
480
+ self.grid.lines.insert(bottom, new_line);
481
+ }
482
+ }
483
+ for i in top..=bottom {
484
+ if let Some(line) = self.grid.lines.get_mut(i) {
485
+ line.dirty = true;
486
+ }
487
+ }
488
+ self.damage = Damage::Full;
489
+ }
490
+
491
+ fn handle_dch(&mut self, params: &[u16]) {
492
+ let n = param_or!(params, 0, 1) as usize;
493
+ let row = self.grid.cursor_row;
494
+ let col = self.grid.cursor_col;
495
+ let cols = self.grid.cols;
496
+ if let Some(line) = self.grid.line_mut(row) {
497
+ for i in col..cols.saturating_sub(n) {
498
+ line.cells[i] = line.cells[i + n].clone();
499
+ }
500
+ for i in (cols.saturating_sub(n))..cols {
501
+ line.cells[i].reset();
502
+ }
503
+ line.dirty = true;
504
+ self.damage.add_line(row, col, cols);
505
+ }
506
+ }
507
+
508
+ fn handle_ich(&mut self, params: &[u16]) {
509
+ let n = param_or!(params, 0, 1) as usize;
510
+ let row = self.grid.cursor_row;
511
+ let col = self.grid.cursor_col;
512
+ let cols = self.grid.cols;
513
+ if let Some(line) = self.grid.line_mut(row) {
514
+ let shift_count = (cols - col).saturating_sub(n);
515
+ for i in (0..shift_count).rev() {
516
+ line.cells[col + i + n] = line.cells[col + i].clone();
517
+ }
518
+ let clear_end = col + n.min(cols - col);
519
+ for i in col..clear_end {
520
+ line.cells[i].reset();
521
+ }
522
+ line.dirty = true;
523
+ self.damage.add_line(row, col, cols);
524
+ }
525
+ }
526
+
527
+ fn handle_ech(&mut self, params: &[u16]) {
528
+ let n = param_or!(params, 0, 1) as usize;
529
+ let row = self.grid.cursor_row;
530
+ let col = self.grid.cursor_col;
531
+ let end = (col + n).min(self.grid.cols);
532
+ if let Some(line) = self.grid.line_mut(row) {
533
+ for i in col..end {
534
+ line.cells[i].reset();
535
+ }
536
+ line.dirty = true;
537
+ self.damage.add_line(row, col, end);
538
+ }
539
+ }
540
+
541
+ fn handle_da(&mut self, _params: &[u16]) { }
542
+
543
+ fn handle_tbc(&mut self, _params: &[u16]) { }
544
+ }
545
+
546
+ fn extended_256_color(idx: usize) -> u32 {
547
+ const TABLE: [u32; 216] = {
548
+ let mut table = [0u32; 216];
549
+ let mut i = 0usize;
550
+ while i < 216 {
551
+ let r = (i / 36) % 6;
552
+ let g = (i / 6) % 6;
553
+ let b = i % 6;
554
+ let rv = if r > 0 { 55 + r * 40 } else { 0 };
555
+ let gv = if g > 0 { 55 + g * 40 } else { 0 };
556
+ let bv = if b > 0 { 55 + b * 40 } else { 0 };
557
+ table[i] = 0xFF_000000 | ((rv as u32) << 16) | ((gv as u32) << 8) | (bv as u32);
558
+ i += 1;
559
+ }
560
+ table
561
+ };
562
+
563
+ if idx < 16 {
564
+ ANSI_COLORS[idx]
565
+ } else if idx < 232 {
566
+ TABLE[idx - 16]
567
+ } else {
568
+ let v = 8 + (idx - 232) * 10;
569
+ let v = v as u32;
570
+ 0xFF_000000 | (v << 16) | (v << 8) | v
571
+ }
572
+ }