1use crate::cells::{CellBuffer, Style};
2use crate::styles::*;
3use core::cmp::min;
4use fltk::enums::Color;
5use vte::{Params, Perform};
6
7pub struct CellsPerformer<'a> {
8 pub buf: &'a mut CellBuffer,
9 cur_style: Style,
10 fg_base: Option<u16>,
11 bg_base: Option<u16>,
12}
13
14impl<'a> CellsPerformer<'a> {
15 pub fn new(buf: &'a mut CellBuffer) -> Self {
16 let cur_style = Style::new(buf.default_bg, buf.default_fg);
17 Self {
18 buf,
19 cur_style,
20 fg_base: None,
21 bg_base: None,
22 }
23 }
24}
25
26fn fg_from_code(code: u16) -> Option<Color> {
27 match code {
28 30 => Some(BLACK),
29 31 => Some(RED),
30 32 => Some(GREEN),
31 33 => Some(YELLOW),
32 34 => Some(BLUE),
33 35 => Some(MAGENTA),
34 36 => Some(CYAN),
35 37 => Some(WHITE),
36 90 => Some(BRIGHT_BLACK),
38 91 => Some(BRIGHT_RED),
39 92 => Some(BRIGHT_GREEN),
40 93 => Some(BRIGHT_YELLOW),
41 94 => Some(BRIGHT_BLUE),
42 95 => Some(BRIGHT_MAGENTA),
43 96 => Some(BRIGHT_CYAN),
44 97 => Some(BRIGHT_WHITE),
45 _ => None,
46 }
47}
48
49fn bg_from_code(code: u16) -> Option<Color> {
50 match code {
51 40 => Some(BLACK),
52 41 => Some(RED),
53 42 => Some(GREEN),
54 43 => Some(YELLOW),
55 44 => Some(BLUE),
56 45 => Some(MAGENTA),
57 46 => Some(CYAN),
58 47 => Some(WHITE),
59 100 => Some(BRIGHT_BLACK),
61 101 => Some(BRIGHT_RED),
62 102 => Some(BRIGHT_GREEN),
63 103 => Some(BRIGHT_YELLOW),
64 104 => Some(BRIGHT_BLUE),
65 105 => Some(BRIGHT_MAGENTA),
66 106 => Some(BRIGHT_CYAN),
67 107 => Some(BRIGHT_WHITE),
68 _ => None,
69 }
70}
71
72fn xterm256_to_color(idx: u16) -> Color {
73 match idx {
74 0 => Color::from_rgb(0, 0, 0),
75 1 => Color::from_rgb(205, 0, 0),
76 2 => Color::from_rgb(0, 205, 0),
77 3 => Color::from_rgb(205, 205, 0),
78 4 => Color::from_rgb(0, 0, 238),
79 5 => Color::from_rgb(205, 0, 205),
80 6 => Color::from_rgb(0, 205, 205),
81 7 => Color::from_rgb(229, 229, 229),
82 8 => Color::from_rgb(127, 127, 127),
83 9 => Color::from_rgb(255, 0, 0),
84 10 => Color::from_rgb(0, 255, 0),
85 11 => Color::from_rgb(255, 255, 0),
86 12 => Color::from_rgb(92, 92, 255),
87 13 => Color::from_rgb(255, 0, 255),
88 14 => Color::from_rgb(0, 255, 255),
89 15 => Color::from_rgb(255, 255, 255),
90 16..=231 => {
91 let i = idx - 16;
92 let r = i / 36;
93 let g = (i % 36) / 6;
94 let b = i % 6;
95 let conv = |v: u16| -> u8 { [0, 95, 135, 175, 215, 255][min(v as usize, 5)] as u8 };
96 Color::from_rgb(conv(r), conv(g), conv(b))
97 }
98 232..=255 => {
99 let shade = 8 + 10 * (idx - 232);
100 let c = shade as u8;
101 Color::from_rgb(c, c, c)
102 }
103 _ => WHITE,
104 }
105}
106
107impl Perform for CellsPerformer<'_> {
108 fn print(&mut self, c: char) {
109 self.buf.write_char(c);
110 }
111
112 fn execute(&mut self, byte: u8) {
113 match byte {
114 b'\n' => {
115 self.buf.line_feed();
117 }
118 b'\r' => {
119 self.buf.carriage_return();
121 }
122 b'\t' => {
123 self.buf.tab();
125 }
126 8 => {
127 let (row, col) = self.buf.cursor();
129 if col > 0 {
130 self.buf.move_cursor_abs(row, col - 1);
131 }
132 }
133 7 => {
134 }
136 _ => {}
137 }
138 }
139
140 fn csi_dispatch(&mut self, params: &Params, _intermediates: &[u8], _ignore: bool, c: char) {
141 match c {
142 'm' => {
143 if params.is_empty() {
145 self.cur_style = Style::new(self.buf.default_bg, self.buf.default_fg);
146 self.buf.set_style(self.cur_style);
147 return;
148 }
149 let mut it = params.iter().peekable();
150 while let Some(p) = it.next() {
151 let n = p[0];
152 match n {
153 0 => {
154 self.cur_style = Style::new(self.buf.default_bg, self.buf.default_fg);
155 self.fg_base = None;
156 self.bg_base = None;
157 }
158 1 => {
159 self.cur_style.bold = true;
160 }
161 2 => {
162 self.cur_style.faint = true;
163 }
164 3 => {
165 self.cur_style.italic = true;
166 }
167 4 => {
168 self.cur_style.underline = true;
169 }
170 5 => {
171 }
173 7 => {
174 self.cur_style.inverse = true;
175 }
176 8 => {
177 self.cur_style.faint = true;
179 }
180 9 => {
181 self.cur_style.strikethrough = true;
182 }
183 21 => {
184 self.cur_style.underline = true;
186 }
187 22 => {
188 self.cur_style.bold = false;
189 self.cur_style.faint = false;
190 }
191 23 => {
192 self.cur_style.italic = false;
193 }
194 24 => {
195 self.cur_style.underline = false;
196 }
197 25 => {
198 }
200 27 => {
201 self.cur_style.inverse = false;
202 }
203 28 => {
204 self.cur_style.faint = false;
205 }
206 29 => {
207 self.cur_style.strikethrough = false;
208 }
209 53 => {
210 self.cur_style.overline = true;
211 }
212 55 => {
213 self.cur_style.overline = false;
214 }
215 30..=37 => {
216 self.fg_base = Some(n);
217 if let Some(c) = fg_from_code(n) {
218 self.cur_style.fg = c;
219 }
220 }
221 90..=97 => {
222 self.fg_base = None;
223 if let Some(c) = fg_from_code(n) {
224 self.cur_style.fg = c;
225 }
226 }
227 39 => {
228 self.cur_style.fg = WHITE;
229 self.fg_base = None;
230 }
231 40..=47 => {
232 self.bg_base = Some(n);
233 if let Some(c) = bg_from_code(n) {
234 self.cur_style.bg = c;
235 }
236 }
237 100..=107 => {
238 self.bg_base = None;
239 if let Some(c) = bg_from_code(n) {
240 self.cur_style.bg = c;
241 }
242 }
243 49 => {
244 self.cur_style.bg = BLACK;
245 self.bg_base = None;
246 }
247 38 => {
248 if let Some(mode) = it.next() {
249 match mode[0] {
250 5 => {
251 if let Some(col) = it.next() {
252 self.cur_style.fg = xterm256_to_color(col[0]);
253 self.fg_base = None;
254 }
255 }
256 2 => {
257 let r = it.next().map(|x| x[0] as u8).unwrap_or(255);
258 let g = it.next().map(|x| x[0] as u8).unwrap_or(255);
259 let b = it.next().map(|x| x[0] as u8).unwrap_or(255);
260 self.cur_style.fg = Color::from_rgb(r, g, b);
261 self.fg_base = None;
262 }
263 _ => {}
264 }
265 }
266 }
267 48 => {
268 if let Some(mode) = it.next() {
269 match mode[0] {
270 5 => {
271 if let Some(col) = it.next() {
272 self.cur_style.bg = xterm256_to_color(col[0]);
273 self.bg_base = None;
274 }
275 }
276 2 => {
277 let r = it.next().map(|x| x[0] as u8).unwrap_or(0);
278 let g = it.next().map(|x| x[0] as u8).unwrap_or(0);
279 let b = it.next().map(|x| x[0] as u8).unwrap_or(0);
280 self.cur_style.bg = Color::from_rgb(r, g, b);
281 self.bg_base = None;
282 }
283 _ => {}
284 }
285 }
286 }
287 _ => {}
288 }
289 }
290 self.buf.set_style(self.cur_style);
291 }
292 'K' => {
293 let mode = params.iter().next().map(|p| p[0]).unwrap_or(0);
295 match mode {
296 0 => self.buf.clear_eol_0(),
297 1 => self.buf.clear_eol_1(),
298 2 => self.buf.clear_eol_2(),
299 _ => {}
300 }
301 }
302 'H' | 'f' => {
303 let mut it = params.iter();
305 let row = it
306 .next()
307 .map(|p| p[0] as usize)
308 .unwrap_or(1)
309 .saturating_sub(1);
310 let col = it
311 .next()
312 .map(|p| p[0] as usize)
313 .unwrap_or(1)
314 .saturating_sub(1);
315 self.buf.move_cursor_abs(row, col);
316 }
317 'G' => {
318 let col = params
320 .iter()
321 .next()
322 .map(|p| p[0] as usize)
323 .unwrap_or(1)
324 .saturating_sub(1);
325 let (row, _) = self.buf.cursor();
326 self.buf.move_cursor_abs(row, col);
327 }
328 'A' => {
329 let count = params.iter().next().map(|p| p[0] as isize).unwrap_or(1);
331 self.buf.move_cursor_rel(-{ count }, 0);
332 }
333 'B' => {
334 let count = params.iter().next().map(|p| p[0] as isize).unwrap_or(1);
336 self.buf.move_cursor_rel(count, 0);
337 }
338 'C' => {
339 let count = params.iter().next().map(|p| p[0] as isize).unwrap_or(1);
341 self.buf.move_cursor_rel(0, count);
342 }
343 'D' => {
344 let count = params.iter().next().map(|p| p[0] as isize).unwrap_or(1);
346 self.buf.move_cursor_rel(0, -{ count });
347 }
348 'J' => {
349 let mode = params.iter().next().map(|p| p[0]).unwrap_or(0);
351 match mode {
352 0 => self.buf.clear_ed_0(),
353 1 => self.buf.clear_ed_1(),
354 2 => self.buf.clear_ed_2(),
355 3 => self.buf.clear_scrollback(),
356 _ => {}
357 }
358 }
359 '@' => {
360 let count = params.iter().next().map(|p| p[0] as usize).unwrap_or(1);
362 self.buf.insert_blanks(count);
363 }
364 'P' => {
365 let count = params.iter().next().map(|p| p[0] as usize).unwrap_or(1);
367 self.buf.delete_chars(count);
368 }
369 'X' => {
370 let count = params.iter().next().map(|p| p[0] as usize).unwrap_or(1);
372 self.buf.erase_chars(count);
373 }
374 'L' => {
375 let count = params.iter().next().map(|p| p[0] as usize).unwrap_or(1);
377 self.buf.insert_lines(count);
378 }
379 'M' => {
380 let count = params.iter().next().map(|p| p[0] as usize).unwrap_or(1);
382 self.buf.delete_lines(count);
383 }
384 _ => {}
385 }
386 }
387
388 fn osc_dispatch(&mut self, _params: &[&[u8]], _bell_terminated: bool) {}
389 fn hook(&mut self, _params: &Params, _intermediates: &[u8], _ignore: bool, _c: char) {}
390 fn put(&mut self, _byte: u8) {}
391 fn unhook(&mut self) {}
392 fn esc_dispatch(&mut self, _intermediates: &[u8], _ignore: bool, _byte: u8) {}
393}