1extern crate vte;
2#[macro_use]
3extern crate log;
4
5use std::{char, cmp, str};
6
7pub use color::Color;
8
9pub mod color;
10
11pub enum Event<'a> {
12 Char {
13 x: usize,
14 y: usize,
15 c: char,
16 bold: bool,
17 italic: bool,
18 underlined: bool,
19 strikethrough: bool,
20 color: Color
21 },
22 Input {
23 data: &'a [u8]
24 },
25 Rect {
26 x: usize,
27 y: usize,
28 w: usize,
29 h: usize,
30 color: Color
31 },
32 ScreenBuffer {
33 alternate: bool,
34 clear: bool,
35 },
36 Move {
37 from_x: usize,
38 from_y: usize,
39 to_x: usize,
40 to_y: usize,
41 w: usize,
42 h: usize,
43 },
44 Resize {
45 w: usize,
46 h: usize,
47 },
48 Title {
49 title: String
50 }
51}
52
53pub struct State {
54 pub x: usize,
55 pub y: usize,
56 pub save_x: usize,
57 pub save_y: usize,
58 pub w: usize,
59 pub h: usize,
60 pub top_margin: usize,
61 pub bottom_margin: usize,
62 pub g0: char,
63 pub g1: char,
64 pub foreground: Color,
65 pub background: Color,
66 pub foreground_default: Color,
67 pub background_default: Color,
68 pub bold: bool,
69 pub inverted: bool,
70 pub italic: bool,
71 pub underlined: bool,
72 pub strikethrough: bool,
73 pub cursor: bool,
74 pub redraw: bool,
75 pub origin: bool,
76 pub autowrap: bool,
77 pub mouse_vt200: bool,
78 pub mouse_btn: bool,
79 pub mouse_sgr: bool,
80 pub mouse_rxvt: bool,
81}
82
83impl State {
84 pub fn new(w: usize, h: usize) -> State {
85 State {
86 x: 0,
87 y: 0,
88 save_x: 0,
89 save_y: 0,
90 w: w,
91 h: h,
92 top_margin: 0,
93 bottom_margin: cmp::max(0, h as isize - 1) as usize,
94 g0: 'B',
95 g1: '0',
96 foreground: Color::Ansi(7),
97 background: Color::Ansi(0),
98 foreground_default: Color::Ansi(7),
99 background_default: Color::Ansi(0),
100 bold: false,
101 inverted: false,
102 italic: false,
103 underlined: false,
104 strikethrough: false,
105 cursor: true,
106 redraw: true,
107 origin: false,
108 autowrap: true,
109 mouse_vt200: false,
110 mouse_btn: false,
111 mouse_sgr: false,
112 mouse_rxvt: false,
113 }
114 }
115
116 fn block<F: FnMut(Event)>(&self, c: char, callback: &mut F) {
117 callback(Event::Rect {
118 x: self.x,
119 y: self.y,
120 w: 1,
121 h: 1,
122 color: if self.inverted { self.foreground } else { self.background }
123 });
124 callback(Event::Char {
125 x: self.x,
126 y: self.y,
127 c: c,
128 bold: self.bold,
129 italic: self.italic,
130 underlined: self.underlined,
131 strikethrough: self.strikethrough,
132 color: if self.inverted { self.background } else { self.foreground }
133 });
134 }
135
136 fn scroll<F: FnMut(Event)>(&self, rows: usize, callback: &mut F) {
137 callback(Event::Move {
139 from_x: 0,
140 from_y: self.top_margin + rows,
141 to_x: 0,
142 to_y: self.top_margin,
143 w: self.w,
144 h: (self.bottom_margin + 1) - rows,
145 });
146 callback(Event::Rect {
147 x: 0,
148 y: (self.bottom_margin + 1) - rows,
149 w: self.w,
150 h: rows,
151 color: self.background,
152 });
153 }
154
155 fn reverse_scroll<F: FnMut(Event)>(&self, rows: usize, callback: &mut F) {
156 callback(Event::Move {
158 from_x: 0,
159 from_y: self.top_margin,
160 to_x: 0,
161 to_y: self.top_margin + rows,
162 w: self.w,
163 h: (self.bottom_margin + 1) - rows,
164 });
165 callback(Event::Rect {
166 x: 0,
167 y: self.top_margin,
168 w: self.w,
169 h: rows,
170 color: self.background,
171 });
172 }
173
174 fn fix_cursor<F: FnMut(Event)>(&mut self, callback: &mut F) {
175 let w = self.w;
176 let h = cmp::min(self.h, self.bottom_margin + 1);
177
178 if self.x >= w {
179 if self.autowrap {
180 self.x = 0;
181 self.y += 1;
182 } else {
183 self.x = w.checked_sub(1).unwrap_or(0);
184 }
185 }
186
187 if self.y + 1 > h {
188 let rows = self.y + 1 - h;
189 self.scroll(rows, callback);
190 self.y = self.y.checked_sub(rows).unwrap_or(0);
191 }
192 }
193
194 pub fn print<F: FnMut(Event)>(&mut self, c: char, callback: &mut F) {
195 self.fix_cursor(callback);
196 self.block(c, callback);
197 self.x += 1;
198 }
199
200 pub fn execute<F: FnMut(Event)>(&mut self, c: char, _callback: &mut F) {
201 let xenl = false;
204
205 match c {
206 '\x08' => { self.x = cmp::max(0, self.x as i64 - 1) as usize;
209 },
210 '\x09' => if ! xenl { self.x = cmp::max(0, cmp::min(self.w as i64 - 1, ((self.x as i64 / 8) + 1) * 8)) as usize;
212 },
213 '\x0A' => if ! xenl { self.x = 0;
215 self.y += 1;
216 },
217 '\x0D' => if ! xenl { self.x = 0;
219 },
220 _ => {
221 warn!("Unknown execute {:?}", c);
222 }
223 }
224 }
225
226 pub fn csi<F: FnMut(Event)>(&mut self, c: char, params: &[i64], _intermediates: &[u8], callback: &mut F) {
227 match c {
228 'A' => {
229 let param = params.get(0).map(|v| *v).unwrap_or(1);
230 if self.y < self.top_margin {
231 self.y = cmp::max(0, self.y as i64 - cmp::max(1, param)) as usize;
232 } else {
233 self.y = cmp::max(self.top_margin as i64, self.y as i64 - cmp::max(1, param)) as usize;
234 }
235 },
236 'B' => {
237 let param = params.get(0).map(|v| *v).unwrap_or(1);
238 if self.y > self.bottom_margin {
239 self.y = cmp::max(0, cmp::min(self.h as i64 - 1, self.y as i64 + cmp::max(1, param))) as usize;
240 } else {
241 self.y = cmp::max(0, cmp::min(self.bottom_margin as i64, self.y as i64 + cmp::max(1, param))) as usize;
242 }
243 },
244 'C' => {
245 let param = params.get(0).map(|v| *v).unwrap_or(1);
246 self.x = cmp::max(0, cmp::min(self.w as i64 - 1, self.x as i64 + cmp::max(1, param))) as usize;
247 },
248 'D' => {
249 let param = params.get(0).map(|v| *v).unwrap_or(1);
250 self.x = cmp::max(0, self.x as i64 - cmp::max(1, param)) as usize;
251 },
252 'E' => {
253 let param = params.get(0).map(|v| *v).unwrap_or(1);
254 self.x = 0;
255 self.y += cmp::min(self.h.checked_sub(self.y + 1).unwrap_or(0), cmp::max(1, param) as usize);
256 },
257 'F' => {
258 let param = params.get(0).map(|v| *v).unwrap_or(1);
259 self.x = 0;
260 self.y -= cmp::min(self.y, cmp::max(1, param) as usize);
261 },
262 'G' => {
263 let param = params.get(0).map(|v| *v).unwrap_or(1);
264 let col = cmp::max(1, param);
265 self.x = cmp::max(0, cmp::min(self.w as i64 - 1, col - 1)) as usize;
266 },
267 'H' | 'f' => {
268 {
269 let param = params.get(0).map(|v| *v).unwrap_or(1);
270 let row = cmp::max(1, param);
271
272 let (top, bottom) = if self.origin {
273 (self.top_margin, self.bottom_margin + 1)
274 } else {
275 (0, self.h)
276 };
277
278 self.y = cmp::max(0, cmp::min(bottom as i64 - 1, row + top as i64 - 1)) as usize;
279 }
280
281 {
282 let param = params.get(1).map(|v| *v).unwrap_or(1);
283 let col = cmp::max(1, param);
284 self.x = cmp::max(0, cmp::min(self.w as i64 - 1, col - 1)) as usize;
285 }
286 },
287 'J' => {
288 self.fix_cursor(callback);
289
290 let param = params.get(0).map(|v| *v).unwrap_or(0);
291 match param {
292 0 => {
293 callback(Event::Rect {
295 x: self.x,
296 y: self.y,
297 w: self.w - self.x,
298 h: 1,
299 color: self.background
300 });
301
302 callback(Event::Rect {
304 x: 0,
305 y: self.y,
306 w: self.w,
307 h: self.h - self.y,
308 color: self.background
309 });
310 },
311 1 => {
312 callback(Event::Rect {
314 x: 0,
315 y: 0,
316 w: self.w,
317 h: self.y,
318 color: self.background
319 });
320
321 callback(Event::Rect {
323 x: 0,
324 y: self.y,
325 w: self.x,
326 h: 1,
327 color: self.background
328 });
329 },
330 2 => {
331 self.x = 0;
333 self.y = 0;
334
335 callback(Event::Rect {
337 x: 0,
338 y: 0,
339 w: self.w,
340 h: self.h,
341 color: self.background
342 });
343 },
344 _ => {
345 warn!("Unknown CSI {:?} param {:?}", c, param);
346 }
347 }
348 },
349 'K' => {
350 self.fix_cursor(callback);
351
352 let param = params.get(0).map(|v| *v).unwrap_or(0);
353 match param {
354 0 => {
355 callback(Event::Rect {
357 x: self.x,
358 y: self.y,
359 w: self.w - self.x,
360 h: 1,
361 color: self.background
362 });
363 },
364 1 => {
365 callback(Event::Rect {
367 x: 0,
368 y: self.y,
369 w: self.x,
370 h: 1,
371 color: self.background
372 });
373 },
374 2 => {
375 callback(Event::Rect {
377 x: 0,
378 y: self.y,
379 w: self.w,
380 h: 1,
381 color: self.background
382 });
383 },
384 _ => {
385 warn!("Unknown CSI {:?} param {:?}", c, param);
386 }
387 }
388 },
389 'P' => {
390 let param = params.get(0).map(|v| *v).unwrap_or(1);
391 let cols = cmp::max(0, cmp::min(self.w as i64 - self.x as i64 - 1, param)) as usize;
392 callback(Event::Move {
394 from_x: self.x + cols,
395 from_y: self.y,
396 to_x: self.x,
397 to_y: self.y,
398 w: self.w - (self.x + cols),
399 h: 1,
400 });
401 callback(Event::Rect {
402 x: self.w - cols,
403 y: self.y,
404 w: cols,
405 h: 1,
406 color: self.background,
407 });
408 },
409 'S' => {
410 let param = params.get(0).map(|v| *v).unwrap_or(1);;
411 self.scroll(cmp::max(0, param) as usize, callback);
412 },
413 'T' => {
414 let param = params.get(0).map(|v| *v).unwrap_or(1);
415 self.reverse_scroll(cmp::max(0, param) as usize, callback);
416 },
417 'c' => {
418 let report = format!("\x1B[?6c");
419 callback(Event::Input {
420 data: &report.into_bytes()
421 });
422 },
423 'd' => {
424 let param = params.get(0).map(|v| *v).unwrap_or(1);
425 self.y = cmp::max(0, cmp::min(self.h as i64 - 1, param - 1)) as usize;
426 },
427 'h' => {
428 let param = params.get(0).map(|v| *v).unwrap_or(0);
430 match param {
431 3 => {
432 self.x = 0;
433 self.y = 0;
434 self.top_margin = 0;
435 self.bottom_margin = cmp::max(0, self.h as isize - 1) as usize;
436
437 self.w = 132;
438 callback(Event::Resize {
440 w: self.w,
441 h: self.h
442 });
443
444 callback(Event::Rect {
446 x: 0,
447 y: 0,
448 w: self.w,
449 h: self.h,
450 color: self.background
451 });
452 },
453 6 => {
454 self.origin = true;
455 self.x = 0;
456 self.y = self.top_margin;
457 },
458 7 => self.autowrap = true,
459 25 => self.cursor = true,
460 47 => callback(Event::ScreenBuffer {
461 alternate: true,
462 clear: false,
463 }),
464 1000 => self.mouse_vt200 = true,
465 1002 => self.mouse_btn = true,
466 1006 => self.mouse_sgr = true,
467 1015 => self.mouse_rxvt = true,
468 1047 => callback(Event::ScreenBuffer {
469 alternate: true,
470 clear: false,
471 }),
472 1048 => {
473 self.save_x = self.x;
474 self.save_y = self.y;
475 },
476 1049 => {
477 self.save_x = self.x;
478 self.save_y = self.y;
479
480 callback(Event::ScreenBuffer {
481 alternate: true,
482 clear: true,
483 });
484 },
485 unknown => {
486 warn!("Unknown CSI {:?} param {:?}", c, unknown);
487 }
488 }
489 },
490 'l' => {
491 let param = params.get(0).map(|v| *v).unwrap_or(0);
493 match param {
494 3 => {
495 self.x = 0;
496 self.y = 0;
497 self.top_margin = 0;
498 self.bottom_margin = cmp::max(0, self.h as isize - 1) as usize;
499
500 self.w = 80;
501 callback(Event::Resize {
503 w: self.w,
504 h: self.h
505 });
506
507 callback(Event::Rect {
509 x: 0,
510 y: 0,
511 w: self.w,
512 h: self.h,
513 color: self.background
514 });
515 },
516 6 => {
517 self.origin = false;
518 self.x = 0;
519 self. y = 0;
520 },
521 7 => self.autowrap = false,
522 25 => self.cursor = false,
523 47 => callback(Event::ScreenBuffer {
524 alternate: false,
525 clear: false,
526 }),
527 1000 => self.mouse_vt200 = false,
528 1002 => self.mouse_btn = false,
529 1006 => self.mouse_sgr = false,
530 1015 => self.mouse_rxvt = false,
531 1047 => callback(Event::ScreenBuffer {
532 alternate: false,
533 clear: true
534 }),
535 1048 => {
536 self.x = self.save_x;
537 self.y = self.save_y;
538 },
539 1049 => {
540 self.x = self.save_x;
541 self.y = self.save_y;
542
543 callback(Event::ScreenBuffer {
544 alternate: false,
545 clear: false,
546 });
547 }
548 unknown => {
549 warn!("Unknown CSI {:?} param {:?}", c, unknown);
550 }
551 }
552 },
553 'm' => {
554 let mut value_iter = if params.len() == 0 {
556 [0].iter()
557 } else {
558 params.iter()
559 };
560 while let Some(value) = value_iter.next() {
561 match *value {
562 0 => {
563 self.foreground = self.foreground_default;
564 self.background = self.background_default;
565 self.bold = false;
566 self.italic = false;
567 self.underlined = false;
568 self.strikethrough = false;
569 self.inverted = false;
570 },
571 1 => {
572 self.bold = true;
573 },
574 3 => {
575 self.italic = true;
576 },
577 4 => {
578 self.underlined = true;
579 },
580 7 => {
581 self.inverted = true;
582 },
583 9 => {
584 self.strikethrough = true;
585 }
586 21 => {
587 self.bold = false;
588 },
589 23 => {
590 self.italic = false;
591 },
592 24 => {
593 self.underlined = false;
594 },
595 27 => {
596 self.inverted = false;
597 },
598 30 ... 37 => self.foreground = Color::Ansi(*value as u8 - 30),
599 38 => match value_iter.next().map(|v| *v).unwrap_or(0) {
600 2 => {
601 let r = value_iter.next().map(|v| *v).unwrap_or(0);
603 let g = value_iter.next().map(|v| *v).unwrap_or(0);
604 let b = value_iter.next().map(|v| *v).unwrap_or(0);
605 self.foreground = Color::TrueColor(r as u8, g as u8, b as u8);
606 },
607 5 => {
608 let color_value = value_iter.next().map(|v| *v).unwrap_or(0);
610 self.foreground = Color::Ansi(color_value as u8);
611 },
612 _ => {}
613 },
614 39 => {
615 self.foreground = self.foreground_default;
616 },
617 40 ... 47 => self.background = Color::Ansi(*value as u8 - 40),
618 48 => match value_iter.next().map(|v| *v).unwrap_or(0) {
619 2 => {
620 let r = value_iter.next().map(|v| *v).unwrap_or(0);
622 let g = value_iter.next().map(|v| *v).unwrap_or(0);
623 let b = value_iter.next().map(|v| *v).unwrap_or(0);
624 self.background = Color::TrueColor(r as u8, g as u8, b as u8);
625 },
626 5 => {
627 let color_value = value_iter.next().map(|v| *v).unwrap_or(0);
629 self.background = Color::Ansi(color_value as u8);
630 },
631 _ => {}
632 },
633 49 => {
634 self.background = self.background_default;
635 },
636 _ => {
637 warn!("Unknown CSI {:?} param {:?}", c, value);
638 },
639 }
640 }
641 },
642 'n' => {
643 let param = params.get(0).map(|v| *v).unwrap_or(0);
644 match param {
645 6 => {
646 let report = format!("\x1B[{};{}R", self.y + 1, self.x + 1);
647 callback(Event::Input {
648 data: &report.into_bytes()
649 });
650 },
651 _ => {
652 warn!("Unknown CSI {:?} param {:?}", c, param);
653 }
654 }
655 },
656 'r' => {
657 let top = params.get(0).map(|v| *v).unwrap_or(1);
658 let bottom = params.get(1).map(|v| *v).unwrap_or(self.h as i64);
659 self.top_margin = cmp::max(0, cmp::min(self.h as isize - 1, top as isize - 1)) as usize;
660 self.bottom_margin = cmp::max(self.top_margin as isize, cmp::min(self.h as isize - 1, bottom as isize - 1)) as usize;
661 },
662 's' => {
663 self.save_x = self.x;
664 self.save_y = self.y;
665 },
666 'u' => {
667 self.x = self.save_x;
668 self.y = self.save_y;
669 },
670 '@' => {
671 let param = params.get(0).map(|v| *v).unwrap_or(1);
672 let cols = cmp::max(0, cmp::min(self.w as i64 - self.x as i64 - 1, param)) as usize;
673 callback(Event::Move {
675 from_x: self.x,
676 from_y: self.y,
677 to_x: self.x + cols,
678 to_y: self.y,
679 w: self.w - (self.x + cols),
680 h: 1,
681 });
682 callback(Event::Rect {
683 x: self.x,
684 y: self.y,
685 w: cols,
686 h: 1,
687 color: self.background,
688 });
689 },
690 _ => {
691 warn!("Unknown CSI {:?}", c);
692 }
693 }
694 }
695
696 pub fn esc<F: FnMut(Event)>(&mut self, c: char, _params: &[i64], intermediates: &[u8], callback: &mut F) {
697 match c {
698 'D' => {
699 self.y += 1;
700 },
701 'E' => {
702 self.x = 0;
703 self.y += 1;
704 },
705 'M' => {
706 while self.y <= 0 {
707 self.reverse_scroll(1, callback);
708 self.y += 1;
709 }
710 self.y -= 1;
711 },
712 '7' => {
713 self.save_x = self.x;
715 self.save_y = self.y;
716 },
717 '8' => {
718 match intermediates.get(0).map(|v| *v as char) {
719 Some('#') => {
720 for x in (self.w/2).checked_sub(30).unwrap_or(10)..(self.w/2).checked_add(30).unwrap_or(70) {
722 self.x = x;
723
724 self.y = 8;
725 self.block('E', callback);
726
727 self.y = 15;
728 self.block('E', callback);
729 }
730
731 for y in 9..15 {
732 self.y = y;
733
734 self.x = (self.w/2).checked_sub(30).unwrap_or(10);
735 self.block('E', callback);
736
737 self.x = (self.w/2).checked_add(29).unwrap_or(69);
738 self.block('E', callback);
739 }
740
741 self.x = 0;
742 self.y = 0;
743 },
744 Some(inter) => {
745 warn!("Unknown ESC {:?} intermediate {:?}", c, inter);
746 },
747 None => {
748 self.x = self.save_x;
750 self.y = self.save_y;
751 }
752 }
753 },
754 'c' => {
755 self.x = 0;
757 self.y = 0;
758 self.save_x = 0;
759 self.save_y = 0;
760 self.top_margin = 0;
761 self.bottom_margin = cmp::max(0, self.h as isize - 1) as usize;
762 self.cursor = true;
763 self.g0 = 'B';
764 self.g1 = '0';
765 self.foreground = self.foreground_default;
766 self.background = self.background_default;
767 self.bold = false;
768 self.inverted = false;
769 self.italic = false;
770 self.underlined = false;
771 self.strikethrough = false;
772
773 callback(Event::Rect {
775 x: 0,
776 y: 0,
777 w: self.w,
778 h: self.h,
779 color: self.background
780 });
781
782 self.redraw = true;
783 },
784 _ => {
785 warn!("Unknown ESC {:?}", c);
786 }
787 }
788 }
789
790 pub fn osc<F: FnMut(Event)>(&mut self, params: &[&[u8]], callback: &mut F) {
791 match params.get(0).map(|s| s.get(0).map(|b| *b).unwrap_or(0)).unwrap_or(0) as char {
792 '0' | '1' | '2' => if let Some(bytes) = params.get(1) {
793 if let Ok(string) = str::from_utf8(bytes) {
794 callback(Event::Title {
795 title: string.to_string()
796 });
797 } else {
798 warn!("Invalid UTF-8 {:?}", bytes);
799 }
800 } else {
801 warn!("Unknown OSC {:?}", params);
802 },
803 _ => {
804 warn!("Unknown OSC {:?}", params);
805 }
806 }
807 }
808}
809
810pub struct Performer<'a, F: FnMut(Event) + 'a> {
811 state: &'a mut State,
812 callback: &'a mut F,
813}
814
815impl<'a, F: FnMut(Event)> vte::Perform for Performer<'a, F> {
816 fn print(&mut self, c: char) {
817 self.state.print(c, self.callback);
819 }
820
821 fn execute(&mut self, byte: u8) {
822 self.state.execute(byte as char, self.callback);
824 }
825
826 fn hook(&mut self, _params: &[i64], _intermediates: &[u8], _ignore: bool) {
827 }
829
830 fn put(&mut self, _byte: u8) {
831 }
833
834 fn unhook(&mut self) {
835 }
837
838 fn osc_dispatch(&mut self, params: &[&[u8]]) {
839 self.state.osc(params, self.callback);
841 }
842
843 fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], _ignore: bool, c: char) {
844 self.state.csi(c, params, intermediates, self.callback);
846 }
847
848 fn esc_dispatch(&mut self, params: &[i64], intermediates: &[u8], _ignore: bool, byte: u8) {
849 self.state.esc(byte as char, params, intermediates, self.callback);
851 }
852}
853
854pub struct Console {
855 pub parser: vte::Parser,
856 pub state: State,
857}
858
859impl Console {
860 pub fn new(w: usize, h: usize) -> Console {
861 Console {
862 parser: vte::Parser::new(),
863 state: State::new(w, h),
864 }
865 }
866
867 pub fn resize(&mut self, w: usize, h: usize) {
868 let state = &mut self.state;
869
870 state.top_margin = cmp::max(0, cmp::min(h as isize - 1, state.top_margin as isize)) as usize;
871 state.bottom_margin = cmp::max(state.top_margin as isize, cmp::min(h as isize - 1, state.bottom_margin as isize + h as isize - state.h as isize)) as usize;
872
873 state.w = w;
874 state.h = h;
875 }
876
877 pub fn write<F: FnMut(Event)>(&mut self, bytes: &[u8], mut callback: F) {
878 for byte in bytes.iter() {
879 self.parser.advance(&mut Performer {
880 state: &mut self.state,
881 callback: &mut callback,
882 }, *byte);
883 };
884 }
885}