1use std::io;
17use std::ops::Range;
18use std::str;
19
20use crate::index::{Column, Contains, Line};
21use base64;
22use vte;
23
24#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
25pub struct Rgb {
26 pub r: u8,
27 pub g: u8,
28 pub b: u8,
29}
30
31fn parse_rgb_color(color: &[u8]) -> Option<Rgb> {
35 let mut iter = color.iter();
36
37 macro_rules! next {
38 () => {
39 iter.next().map(|v| *v as char)
40 };
41 }
42
43 macro_rules! parse_hex {
44 () => {{
45 let mut digit: u8 = 0;
46 let next = next!().and_then(|v| v.to_digit(16));
47 if let Some(value) = next {
48 digit = value as u8;
49 }
50
51 let next = next!().and_then(|v| v.to_digit(16));
52 if let Some(value) = next {
53 digit <<= 4;
54 digit += value as u8;
55 }
56 digit
57 }};
58 }
59
60 match next!() {
61 Some('r') => {
62 if next!() != Some('g') {
63 return None;
64 }
65 if next!() != Some('b') {
66 return None;
67 }
68 if next!() != Some(':') {
69 return None;
70 }
71
72 let r = parse_hex!();
73 let val = next!();
74 if val != Some('/') {
75 return None;
76 }
77 let g = parse_hex!();
78 if next!() != Some('/') {
79 return None;
80 }
81 let b = parse_hex!();
82
83 Some(Rgb { r, g, b })
84 }
85 Some('#') => Some(Rgb {
86 r: parse_hex!(),
87 g: parse_hex!(),
88 b: parse_hex!(),
89 }),
90 _ => None,
91 }
92}
93
94fn parse_number(input: &[u8]) -> Option<u8> {
95 if input.is_empty() {
96 return None;
97 }
98 let mut num: u8 = 0;
99 for c in input {
100 let c = *c as char;
101 if let Some(digit) = c.to_digit(10) {
102 num = match num.checked_mul(10).and_then(|v| v.checked_add(digit as u8)) {
103 Some(v) => v,
104 None => return None,
105 }
106 } else {
107 return None;
108 }
109 }
110 Some(num)
111}
112
113pub struct Processor {
115 state: ProcessorState,
116 parser: vte::Parser,
117}
118
119pub struct ProcessorState {
121 preceding_char: Option<char>,
122}
123
124pub struct Performer<'a, H: Handler + TermInfo, W: io::Write> {
129 state: &'a mut ProcessorState,
130 handler: &'a mut H,
131 writer: &'a mut W,
132}
133
134impl<'a, H: Handler + TermInfo + 'a, W: io::Write> Performer<'a, H, W> {
135 #[inline]
137 pub fn new<'b>(
138 state: &'b mut ProcessorState,
139 handler: &'b mut H,
140 writer: &'b mut W,
141 ) -> Performer<'b, H, W> {
142 Performer {
143 state,
144 handler,
145 writer,
146 }
147 }
148}
149
150impl Default for Processor {
151 fn default() -> Processor {
152 Processor {
153 state: ProcessorState {
154 preceding_char: None,
155 },
156 parser: vte::Parser::new(),
157 }
158 }
159}
160
161impl Processor {
162 pub fn new() -> Processor {
163 Default::default()
164 }
165
166 #[inline]
167 pub fn advance<H, W>(&mut self, handler: &mut H, byte: u8, writer: &mut W)
168 where
169 H: Handler + TermInfo,
170 W: io::Write,
171 {
172 let mut performer = Performer::new(&mut self.state, handler, writer);
173 self.parser.advance(&mut performer, byte);
174 }
175}
176
177pub trait TermInfo {
179 fn lines(&self) -> Line;
180 fn cols(&self) -> Column;
181}
182
183#[derive(Debug, Eq, PartialEq, Copy, Clone)]
185pub enum MouseCursor {
186 Arrow,
187 Text,
188}
189
190pub trait Handler {
195 fn set_title(&mut self, _: &str) {}
197
198 fn set_mouse_cursor(&mut self, _: MouseCursor) {}
200
201 fn set_cursor_style(&mut self, _: Option<CursorStyle>) {}
203
204 fn input(&mut self, _c: char) {}
206
207 fn goto(&mut self, _: Line, _: Column) {}
209
210 fn goto_line(&mut self, _: Line) {}
212
213 fn goto_col(&mut self, _: Column) {}
215
216 fn insert_blank(&mut self, _: Column) {}
218
219 fn move_up(&mut self, _: Line) {}
221
222 fn move_down(&mut self, _: Line) {}
224
225 fn identify_terminal<W: io::Write>(&mut self, _: &mut W) {}
229
230 fn device_status<W: io::Write>(&mut self, _: &mut W, _: usize) {}
232
233 fn move_forward(&mut self, _: Column) {}
235
236 fn move_backward(&mut self, _: Column) {}
238
239 fn move_down_and_cr(&mut self, _: Line) {}
241
242 fn move_up_and_cr(&mut self, _: Line) {}
244
245 fn put_tab(&mut self, _count: i64) {}
247
248 fn backspace(&mut self) {}
250
251 fn carriage_return(&mut self) {}
253
254 fn linefeed(&mut self) {}
256
257 fn bell(&mut self) {}
261
262 fn substitute(&mut self) {}
264
265 fn newline(&mut self) {}
267
268 fn set_horizontal_tabstop(&mut self) {}
270
271 fn scroll_up(&mut self, _: Line) {}
273
274 fn scroll_down(&mut self, _: Line) {}
276
277 fn insert_blank_lines(&mut self, _: Line) {}
279
280 fn delete_lines(&mut self, _: Line) {}
282
283 fn erase_chars(&mut self, _: Column) {}
288
289 fn delete_chars(&mut self, _: Column) {}
294
295 fn move_backward_tabs(&mut self, _count: i64) {}
297
298 fn move_forward_tabs(&mut self, _count: i64) {}
300
301 fn save_cursor_position(&mut self) {}
303
304 fn restore_cursor_position(&mut self) {}
306
307 fn clear_line(&mut self, _mode: LineClearMode) {}
309
310 fn clear_screen(&mut self, _mode: ClearMode) {}
312
313 fn clear_tabs(&mut self, _mode: TabulationClearMode) {}
315
316 fn reset_state(&mut self) {}
318
319 fn reverse_index(&mut self) {}
325
326 fn terminal_attribute(&mut self, _attr: Attr) {}
328
329 fn set_mode(&mut self, _mode: Mode) {}
331
332 fn unset_mode(&mut self, _: Mode) {}
334
335 fn set_scrolling_region(&mut self, _: Range<Line>) {}
337
338 fn set_keypad_application_mode(&mut self) {}
340
341 fn unset_keypad_application_mode(&mut self) {}
343
344 fn set_active_charset(&mut self, _: CharsetIndex) {}
349
350 fn configure_charset(&mut self, _: CharsetIndex, _: StandardCharset) {}
355
356 fn set_color(&mut self, _: usize, _: Rgb) {}
358
359 fn reset_color(&mut self, _: usize) {}
361
362 fn set_clipboard(&mut self, _: &str) {}
364
365 fn dectest(&mut self) {}
367}
368
369#[derive(Debug, Eq, PartialEq, Copy, Clone)]
371pub enum CursorStyle {
372 Block,
374
375 Underline,
377
378 Beam,
380
381 HollowBlock,
383}
384
385impl Default for CursorStyle {
386 fn default() -> CursorStyle {
387 CursorStyle::Block
388 }
389}
390
391#[derive(Debug, Eq, PartialEq)]
393pub enum Mode {
394 CursorKeys = 1,
396 DECCOLM = 3,
408 Insert = 4,
415 Origin = 6,
417 LineWrap = 7,
419 BlinkingCursor = 12,
421 LineFeedNewLine = 20,
426 ShowCursor = 25,
428 ReportMouseClicks = 1000,
430 ReportCellMouseMotion = 1002,
432 ReportAllMouseMotion = 1003,
434 ReportFocusInOut = 1004,
436 SgrMouse = 1006,
438 SwapScreenAndSetRestoreCursor = 1049,
440 BracketedPaste = 2004,
442}
443
444impl Mode {
445 pub fn from_primitive(private: bool, num: i64) -> Option<Mode> {
449 if private {
450 Some(match num {
451 1 => Mode::CursorKeys,
452 3 => Mode::DECCOLM,
453 6 => Mode::Origin,
454 7 => Mode::LineWrap,
455 12 => Mode::BlinkingCursor,
456 25 => Mode::ShowCursor,
457 1000 => Mode::ReportMouseClicks,
458 1002 => Mode::ReportCellMouseMotion,
459 1003 => Mode::ReportAllMouseMotion,
460 1004 => Mode::ReportFocusInOut,
461 1006 => Mode::SgrMouse,
462 1049 => Mode::SwapScreenAndSetRestoreCursor,
463 2004 => Mode::BracketedPaste,
464 _ => {
465 trace!("[unimplemented] primitive mode: {}", num);
466 return None;
467 }
468 })
469 } else {
470 Some(match num {
471 4 => Mode::Insert,
472 20 => Mode::LineFeedNewLine,
473 _ => return None,
474 })
475 }
476 }
477}
478
479#[derive(Debug)]
483pub enum LineClearMode {
484 Right,
486 Left,
488 All,
490}
491
492#[derive(Debug)]
496pub enum ClearMode {
497 Below,
499 Above,
501 All,
503 Saved,
505}
506
507#[derive(Debug)]
509pub enum TabulationClearMode {
510 Current,
512 All,
514}
515
516#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
521pub enum NamedColor {
522 Black = 0,
524 Red,
526 Green,
528 Yellow,
530 Blue,
532 Magenta,
534 Cyan,
536 White,
538 BrightBlack,
540 BrightRed,
542 BrightGreen,
544 BrightYellow,
546 BrightBlue,
548 BrightMagenta,
550 BrightCyan,
552 BrightWhite,
554 Foreground = 256,
556 Background,
558 CursorText,
560 Cursor,
562 DimBlack,
564 DimRed,
566 DimGreen,
568 DimYellow,
570 DimBlue,
572 DimMagenta,
574 DimCyan,
576 DimWhite,
578 BrightForeground,
580 DimForeground,
582}
583
584impl NamedColor {
585 pub fn to_bright(self) -> Self {
586 match self {
587 NamedColor::Foreground => NamedColor::BrightForeground,
588 NamedColor::Black => NamedColor::BrightBlack,
589 NamedColor::Red => NamedColor::BrightRed,
590 NamedColor::Green => NamedColor::BrightGreen,
591 NamedColor::Yellow => NamedColor::BrightYellow,
592 NamedColor::Blue => NamedColor::BrightBlue,
593 NamedColor::Magenta => NamedColor::BrightMagenta,
594 NamedColor::Cyan => NamedColor::BrightCyan,
595 NamedColor::White => NamedColor::BrightWhite,
596 NamedColor::DimForeground => NamedColor::Foreground,
597 NamedColor::DimBlack => NamedColor::Black,
598 NamedColor::DimRed => NamedColor::Red,
599 NamedColor::DimGreen => NamedColor::Green,
600 NamedColor::DimYellow => NamedColor::Yellow,
601 NamedColor::DimBlue => NamedColor::Blue,
602 NamedColor::DimMagenta => NamedColor::Magenta,
603 NamedColor::DimCyan => NamedColor::Cyan,
604 NamedColor::DimWhite => NamedColor::White,
605 val => val,
606 }
607 }
608
609 pub fn to_dim(self) -> Self {
610 match self {
611 NamedColor::Black => NamedColor::DimBlack,
612 NamedColor::Red => NamedColor::DimRed,
613 NamedColor::Green => NamedColor::DimGreen,
614 NamedColor::Yellow => NamedColor::DimYellow,
615 NamedColor::Blue => NamedColor::DimBlue,
616 NamedColor::Magenta => NamedColor::DimMagenta,
617 NamedColor::Cyan => NamedColor::DimCyan,
618 NamedColor::White => NamedColor::DimWhite,
619 NamedColor::Foreground => NamedColor::DimForeground,
620 NamedColor::BrightBlack => NamedColor::Black,
621 NamedColor::BrightRed => NamedColor::Red,
622 NamedColor::BrightGreen => NamedColor::Green,
623 NamedColor::BrightYellow => NamedColor::Yellow,
624 NamedColor::BrightBlue => NamedColor::Blue,
625 NamedColor::BrightMagenta => NamedColor::Magenta,
626 NamedColor::BrightCyan => NamedColor::Cyan,
627 NamedColor::BrightWhite => NamedColor::White,
628 NamedColor::BrightForeground => NamedColor::Foreground,
629 val => val,
630 }
631 }
632}
633
634#[derive(Debug, Clone, Copy, PartialEq, Eq)]
635pub enum Color {
636 Named(NamedColor),
637 Spec(Rgb),
638 Indexed(u8),
639}
640
641#[derive(Debug, Eq, PartialEq)]
643pub enum Attr {
644 Reset,
646 Bold,
648 Dim,
650 Italic,
652 Underscore,
654 BlinkSlow,
656 BlinkFast,
658 Reverse,
660 Hidden,
662 Strike,
664 CancelBold,
666 CancelBoldDim,
668 CancelItalic,
670 CancelUnderline,
672 CancelBlink,
674 CancelReverse,
676 CancelHidden,
678 CancelStrike,
680 Foreground(Color),
682 Background(Color),
684}
685
686#[derive(Clone, Copy, Debug, Eq, PartialEq)]
688pub enum CharsetIndex {
689 G0,
691 G1,
692 G2,
693 G3,
694}
695
696impl Default for CharsetIndex {
697 fn default() -> Self {
698 CharsetIndex::G0
699 }
700}
701
702#[derive(Clone, Copy, Debug, Eq, PartialEq)]
704pub enum StandardCharset {
705 Ascii,
706 SpecialCharacterAndLineDrawing,
707}
708
709impl Default for StandardCharset {
710 fn default() -> Self {
711 StandardCharset::Ascii
712 }
713}
714
715impl<'a, H, W> vte::Perform for Performer<'a, H, W>
716where
717 H: Handler + TermInfo + 'a,
718 W: io::Write + 'a,
719{
720 #[inline]
721 fn print(&mut self, c: char) {
722 self.handler.input(c);
723 self.state.preceding_char = Some(c);
724 }
725
726 #[inline]
727 fn execute(&mut self, byte: u8) {
728 match byte {
729 C0::HT => self.handler.put_tab(1),
730 C0::BS => self.handler.backspace(),
731 C0::CR => self.handler.carriage_return(),
732 C0::LF | C0::VT | C0::FF => self.handler.linefeed(),
733 C0::BEL => self.handler.bell(),
734 C0::SUB => self.handler.substitute(),
735 C0::SI => self.handler.set_active_charset(CharsetIndex::G0),
736 C0::SO => self.handler.set_active_charset(CharsetIndex::G1),
737 C1::NEL => self.handler.newline(),
738 C1::HTS => self.handler.set_horizontal_tabstop(),
739 C1::DECID => self.handler.identify_terminal(self.writer),
740 _ => debug!("[unhandled] execute byte={:02x}", byte),
741 }
742 }
743
744 #[inline]
745 fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool) {
746 debug!(
747 "[unhandled hook] params={:?}, ints: {:?}, ignore: {:?}",
748 params, intermediates, ignore
749 );
750 }
751
752 #[inline]
753 fn put(&mut self, byte: u8) {
754 debug!("[unhandled put] byte={:?}", byte);
755 }
756
757 #[inline]
758 fn unhook(&mut self) {
759 debug!("[unhandled unhook]");
760 }
761
762 #[inline]
764 fn osc_dispatch(&mut self, params: &[&[u8]]) {
765 fn unhandled(params: &[&[u8]]) {
766 let mut buf = String::new();
767 for items in params {
768 buf.push_str("[");
769 for item in *items {
770 buf.push_str(&format!("{:?},", *item as char));
771 }
772 buf.push_str("],");
773 }
774 debug!("[unhandled osc_dispatch]: [{}] at line {}", &buf, line!());
775 }
776
777 if params.is_empty() || params[0].is_empty() {
778 return;
779 }
780
781 match params[0] {
782 b"0" | b"2" => {
784 if params.len() >= 2 {
785 if let Ok(utf8_title) = str::from_utf8(params[1]) {
786 self.handler.set_title(utf8_title);
787 return;
788 }
789 }
790 unhandled(params);
791 }
792
793 b"1" => return,
796
797 b"4" => {
799 if params.len() > 1 && params.len() % 2 != 0 {
800 for chunk in params[1..].chunks(2) {
801 let index = parse_number(chunk[0]);
802 let color = parse_rgb_color(chunk[1]);
803 if let (Some(i), Some(c)) = (index, color) {
804 self.handler.set_color(i as usize, c);
805 return;
806 }
807 }
808 }
809 unhandled(params);
810 }
811
812 b"10" => {
814 if params.len() >= 2 {
815 if let Some(color) = parse_rgb_color(params[1]) {
816 self.handler
817 .set_color(NamedColor::Foreground as usize, color);
818 return;
819 }
820 }
821 unhandled(params);
822 }
823
824 b"11" => {
826 if params.len() >= 2 {
827 if let Some(color) = parse_rgb_color(params[1]) {
828 self.handler
829 .set_color(NamedColor::Background as usize, color);
830 return;
831 }
832 }
833 unhandled(params);
834 }
835
836 b"12" => {
838 if params.len() >= 2 {
839 if let Some(color) = parse_rgb_color(params[1]) {
840 self.handler.set_color(NamedColor::Cursor as usize, color);
841 return;
842 }
843 }
844 unhandled(params);
845 }
846
847 b"50" => {
849 if params.len() >= 2
850 && params[1].len() >= 13
851 && params[1][0..12] == *b"CursorShape="
852 {
853 let style = match params[1][12] as char {
854 '0' => CursorStyle::Block,
855 '1' => CursorStyle::Beam,
856 '2' => CursorStyle::Underline,
857 _ => return unhandled(params),
858 };
859 self.handler.set_cursor_style(Some(style));
860 return;
861 }
862 unhandled(params);
863 }
864
865 b"52" => {
867 if params.len() < 3 {
868 return unhandled(params);
869 }
870
871 match params[2] {
872 b"?" => unhandled(params),
873 selection => {
874 if let Ok(string) = base64::decode(selection) {
875 if let Ok(utf8_string) = str::from_utf8(&string) {
876 self.handler.set_clipboard(utf8_string);
877 }
878 }
879 }
880 }
881 }
882
883 b"104" => {
885 if params.len() == 1 {
887 for i in 0..256 {
888 self.handler.reset_color(i);
889 }
890 return;
891 }
892
893 for param in ¶ms[1..] {
895 match parse_number(param) {
896 Some(index) => self.handler.reset_color(index as usize),
897 None => unhandled(params),
898 }
899 }
900 }
901
902 b"110" => self.handler.reset_color(NamedColor::Foreground as usize),
904
905 b"111" => self.handler.reset_color(NamedColor::Background as usize),
907
908 b"112" => self.handler.reset_color(NamedColor::Cursor as usize),
910
911 _ => unhandled(params),
912 }
913 }
914
915 #[inline]
916 fn csi_dispatch(&mut self, args: &[i64], intermediates: &[u8], _ignore: bool, action: char) {
917 let private = intermediates.get(0).map(|b| *b == b'?').unwrap_or(false);
918 let handler = &mut self.handler;
919 let writer = &mut self.writer;
920
921 macro_rules! unhandled {
922 () => {{
923 debug!(
924 "[Unhandled CSI] action={:?}, args={:?}, intermediates={:?}",
925 action, args, intermediates
926 );
927 return;
928 }};
929 }
930
931 macro_rules! arg_or_default {
932 (idx: $idx:expr, default: $default:expr) => {
933 args.get($idx)
934 .and_then(|v| if *v == 0 { None } else { Some(*v) })
935 .unwrap_or($default)
936 };
937 }
938
939 match action {
940 '@' => handler.insert_blank(Column(arg_or_default!(idx: 0, default: 1) as usize)),
941 'A' => {
942 handler.move_up(Line(arg_or_default!(idx: 0, default: 1) as usize));
943 }
944 'b' => {
945 if let Some(c) = self.state.preceding_char {
946 for _ in 0..arg_or_default!(idx: 0, default: 1) {
947 handler.input(c);
948 }
949 } else {
950 debug!("tried to repeat with no preceding char");
951 }
952 }
953 'B' | 'e' => handler.move_down(Line(arg_or_default!(idx: 0, default: 1) as usize)),
954 'c' => handler.identify_terminal(writer),
955 'C' | 'a' => handler.move_forward(Column(arg_or_default!(idx: 0, default: 1) as usize)),
956 'D' => handler.move_backward(Column(arg_or_default!(idx: 0, default: 1) as usize)),
957 'E' => handler.move_down_and_cr(Line(arg_or_default!(idx: 0, default: 1) as usize)),
958 'F' => handler.move_up_and_cr(Line(arg_or_default!(idx: 0, default: 1) as usize)),
959 'g' => {
960 let mode = match arg_or_default!(idx: 0, default: 0) {
961 0 => TabulationClearMode::Current,
962 3 => TabulationClearMode::All,
963 _ => unhandled!(),
964 };
965
966 handler.clear_tabs(mode);
967 }
968 'G' | '`' => handler.goto_col(Column(arg_or_default!(idx: 0, default: 1) as usize - 1)),
969 'H' | 'f' => {
970 let y = arg_or_default!(idx: 0, default: 1) as usize;
971 let x = arg_or_default!(idx: 1, default: 1) as usize;
972 handler.goto(Line(y - 1), Column(x - 1));
973 }
974 'I' => handler.move_forward_tabs(arg_or_default!(idx: 0, default: 1)),
975 'J' => {
976 let mode = match arg_or_default!(idx: 0, default: 0) {
977 0 => ClearMode::Below,
978 1 => ClearMode::Above,
979 2 => ClearMode::All,
980 3 => ClearMode::Saved,
981 _ => unhandled!(),
982 };
983
984 handler.clear_screen(mode);
985 }
986 'K' => {
987 let mode = match arg_or_default!(idx: 0, default: 0) {
988 0 => LineClearMode::Right,
989 1 => LineClearMode::Left,
990 2 => LineClearMode::All,
991 _ => unhandled!(),
992 };
993
994 handler.clear_line(mode);
995 }
996 'S' => handler.scroll_up(Line(arg_or_default!(idx: 0, default: 1) as usize)),
997 'T' => handler.scroll_down(Line(arg_or_default!(idx: 0, default: 1) as usize)),
998 'L' => handler.insert_blank_lines(Line(arg_or_default!(idx: 0, default: 1) as usize)),
999 'l' => {
1000 for arg in args {
1001 let mode = Mode::from_primitive(private, *arg);
1002 match mode {
1003 Some(mode) => handler.unset_mode(mode),
1004 None => unhandled!(),
1005 }
1006 }
1007 }
1008 'M' => handler.delete_lines(Line(arg_or_default!(idx: 0, default: 1) as usize)),
1009 'X' => handler.erase_chars(Column(arg_or_default!(idx: 0, default: 1) as usize)),
1010 'P' => handler.delete_chars(Column(arg_or_default!(idx: 0, default: 1) as usize)),
1011 'Z' => handler.move_backward_tabs(arg_or_default!(idx: 0, default: 1)),
1012 'd' => handler.goto_line(Line(arg_or_default!(idx: 0, default: 1) as usize - 1)),
1013 'h' => {
1014 for arg in args {
1015 let mode = Mode::from_primitive(private, *arg);
1016 match mode {
1017 Some(mode) => handler.set_mode(mode),
1018 None => unhandled!(),
1019 }
1020 }
1021 }
1022 'm' => {
1023 let mut i = 0; if args.is_empty() {
1026 handler.terminal_attribute(Attr::Reset);
1027 return;
1028 }
1029 loop {
1030 if i >= args.len() {
1031 break;
1033 }
1034
1035 let attr = match args[i] {
1036 0 => Attr::Reset,
1037 1 => Attr::Bold,
1038 2 => Attr::Dim,
1039 3 => Attr::Italic,
1040 4 => Attr::Underscore,
1041 5 => Attr::BlinkSlow,
1042 6 => Attr::BlinkFast,
1043 7 => Attr::Reverse,
1044 8 => Attr::Hidden,
1045 9 => Attr::Strike,
1046 21 => Attr::CancelBold,
1047 22 => Attr::CancelBoldDim,
1048 23 => Attr::CancelItalic,
1049 24 => Attr::CancelUnderline,
1050 25 => Attr::CancelBlink,
1051 27 => Attr::CancelReverse,
1052 28 => Attr::CancelHidden,
1053 29 => Attr::CancelStrike,
1054 30 => Attr::Foreground(Color::Named(NamedColor::Black)),
1055 31 => Attr::Foreground(Color::Named(NamedColor::Red)),
1056 32 => Attr::Foreground(Color::Named(NamedColor::Green)),
1057 33 => Attr::Foreground(Color::Named(NamedColor::Yellow)),
1058 34 => Attr::Foreground(Color::Named(NamedColor::Blue)),
1059 35 => Attr::Foreground(Color::Named(NamedColor::Magenta)),
1060 36 => Attr::Foreground(Color::Named(NamedColor::Cyan)),
1061 37 => Attr::Foreground(Color::Named(NamedColor::White)),
1062 38 => {
1063 let mut start = 0;
1064 if let Some(color) = parse_color(&args[i..], &mut start) {
1065 i += start;
1066 Attr::Foreground(color)
1067 } else {
1068 break;
1069 }
1070 }
1071 39 => Attr::Foreground(Color::Named(NamedColor::Foreground)),
1072 40 => Attr::Background(Color::Named(NamedColor::Black)),
1073 41 => Attr::Background(Color::Named(NamedColor::Red)),
1074 42 => Attr::Background(Color::Named(NamedColor::Green)),
1075 43 => Attr::Background(Color::Named(NamedColor::Yellow)),
1076 44 => Attr::Background(Color::Named(NamedColor::Blue)),
1077 45 => Attr::Background(Color::Named(NamedColor::Magenta)),
1078 46 => Attr::Background(Color::Named(NamedColor::Cyan)),
1079 47 => Attr::Background(Color::Named(NamedColor::White)),
1080 48 => {
1081 let mut start = 0;
1082 if let Some(color) = parse_color(&args[i..], &mut start) {
1083 i += start;
1084 Attr::Background(color)
1085 } else {
1086 break;
1087 }
1088 }
1089 49 => Attr::Background(Color::Named(NamedColor::Background)),
1090 90 => Attr::Foreground(Color::Named(NamedColor::BrightBlack)),
1091 91 => Attr::Foreground(Color::Named(NamedColor::BrightRed)),
1092 92 => Attr::Foreground(Color::Named(NamedColor::BrightGreen)),
1093 93 => Attr::Foreground(Color::Named(NamedColor::BrightYellow)),
1094 94 => Attr::Foreground(Color::Named(NamedColor::BrightBlue)),
1095 95 => Attr::Foreground(Color::Named(NamedColor::BrightMagenta)),
1096 96 => Attr::Foreground(Color::Named(NamedColor::BrightCyan)),
1097 97 => Attr::Foreground(Color::Named(NamedColor::BrightWhite)),
1098 100 => Attr::Background(Color::Named(NamedColor::BrightBlack)),
1099 101 => Attr::Background(Color::Named(NamedColor::BrightRed)),
1100 102 => Attr::Background(Color::Named(NamedColor::BrightGreen)),
1101 103 => Attr::Background(Color::Named(NamedColor::BrightYellow)),
1102 104 => Attr::Background(Color::Named(NamedColor::BrightBlue)),
1103 105 => Attr::Background(Color::Named(NamedColor::BrightMagenta)),
1104 106 => Attr::Background(Color::Named(NamedColor::BrightCyan)),
1105 107 => Attr::Background(Color::Named(NamedColor::BrightWhite)),
1106 _ => unhandled!(),
1107 };
1108
1109 handler.terminal_attribute(attr);
1110
1111 i += 1; }
1113 }
1114 'n' => handler.device_status(writer, arg_or_default!(idx: 0, default: 0) as usize),
1115 'r' => {
1116 if private {
1117 unhandled!();
1118 }
1119 let arg_0 = arg_or_default!(idx: 0, default: 1) as usize;
1120 let top = Line(arg_0 - 1);
1121 let arg_1 = arg_or_default!(idx: 1, default: handler.lines().0 as _) as usize;
1126 let bottom = Line(arg_1);
1127
1128 handler.set_scrolling_region(top..bottom);
1129 }
1130 's' => handler.save_cursor_position(),
1131 'u' => handler.restore_cursor_position(),
1132 'q' => {
1133 let style = match arg_or_default!(idx: 0, default: 0) {
1134 0 => None,
1135 1 | 2 => Some(CursorStyle::Block),
1136 3 | 4 => Some(CursorStyle::Underline),
1137 5 | 6 => Some(CursorStyle::Beam),
1138 _ => unhandled!(),
1139 };
1140
1141 handler.set_cursor_style(style);
1142 }
1143 _ => unhandled!(),
1144 }
1145 }
1146
1147 #[inline]
1148 fn esc_dispatch(&mut self, params: &[i64], intermediates: &[u8], _ignore: bool, byte: u8) {
1149 macro_rules! unhandled {
1150 () => {{
1151 debug!(
1152 "[unhandled] esc_dispatch params={:?}, ints={:?}, byte={:?} ({:02x})",
1153 params, intermediates, byte as char, byte
1154 );
1155 return;
1156 }};
1157 }
1158
1159 macro_rules! configure_charset {
1160 ($charset:path) => {{
1161 let index: CharsetIndex = match intermediates.first().cloned() {
1162 Some(b'(') => CharsetIndex::G0,
1163 Some(b')') => CharsetIndex::G1,
1164 Some(b'*') => CharsetIndex::G2,
1165 Some(b'+') => CharsetIndex::G3,
1166 _ => unhandled!(),
1167 };
1168 self.handler.configure_charset(index, $charset)
1169 }};
1170 }
1171
1172 match byte {
1173 b'B' => configure_charset!(StandardCharset::Ascii),
1174 b'D' => self.handler.linefeed(),
1175 b'E' => {
1176 self.handler.linefeed();
1177 self.handler.carriage_return();
1178 }
1179 b'H' => self.handler.set_horizontal_tabstop(),
1180 b'M' => self.handler.reverse_index(),
1181 b'Z' => self.handler.identify_terminal(self.writer),
1182 b'c' => self.handler.reset_state(),
1183 b'0' => configure_charset!(StandardCharset::SpecialCharacterAndLineDrawing),
1184 b'7' => self.handler.save_cursor_position(),
1185 b'8' => {
1186 if !intermediates.is_empty() && intermediates[0] == b'#' {
1187 self.handler.dectest();
1188 } else {
1189 self.handler.restore_cursor_position();
1190 }
1191 }
1192 b'=' => self.handler.set_keypad_application_mode(),
1193 b'>' => self.handler.unset_keypad_application_mode(),
1194 b'\\' => (), _ => unhandled!(),
1196 }
1197 }
1198}
1199
1200fn parse_color(attrs: &[i64], i: &mut usize) -> Option<Color> {
1202 if attrs.len() < 2 {
1203 return None;
1204 }
1205
1206 match attrs[*i + 1] {
1207 2 => {
1208 if attrs.len() < 5 {
1210 debug!("Expected RGB color spec; got {:?}", attrs);
1211 return None;
1212 }
1213
1214 let r = attrs[*i + 2];
1215 let g = attrs[*i + 3];
1216 let b = attrs[*i + 4];
1217
1218 *i += 4;
1219
1220 let range = 0..256;
1221 if !range.contains_(r) || !range.contains_(g) || !range.contains_(b) {
1222 debug!("Invalid RGB color spec: ({}, {}, {})", r, g, b);
1223 return None;
1224 }
1225
1226 Some(Color::Spec(Rgb {
1227 r: r as u8,
1228 g: g as u8,
1229 b: b as u8,
1230 }))
1231 }
1232 5 => {
1233 if attrs.len() < 3 {
1234 debug!("Expected color index; got {:?}", attrs);
1235 None
1236 } else {
1237 *i += 2;
1238 let idx = attrs[*i];
1239 match idx {
1240 0..=255 => Some(Color::Indexed(idx as u8)),
1241 _ => {
1242 debug!("Invalid color index: {}", idx);
1243 None
1244 }
1245 }
1246 }
1247 }
1248 _ => {
1249 debug!("Unexpected color attr: {}", attrs[*i + 1]);
1250 None
1251 }
1252 }
1253}
1254
1255#[allow(non_snake_case)]
1257pub mod C0 {
1258 pub const NUL: u8 = 0x00;
1260 pub const SOH: u8 = 0x01;
1262 pub const STX: u8 = 0x02;
1264 pub const ETX: u8 = 0x03;
1266 pub const EOT: u8 = 0x04;
1268 pub const ENQ: u8 = 0x05;
1270 pub const ACK: u8 = 0x06;
1272 pub const BEL: u8 = 0x07;
1274 pub const BS: u8 = 0x08;
1276 pub const HT: u8 = 0x09;
1278 pub const LF: u8 = 0x0A;
1280 pub const VT: u8 = 0x0B;
1282 pub const FF: u8 = 0x0C;
1284 pub const CR: u8 = 0x0D;
1286 pub const SO: u8 = 0x0E;
1288 pub const SI: u8 = 0x0F;
1290 pub const DLE: u8 = 0x10;
1292 pub const XON: u8 = 0x11;
1294 pub const DC2: u8 = 0x12;
1296 pub const XOFF: u8 = 0x13;
1298 pub const DC4: u8 = 0x14;
1300 pub const NAK: u8 = 0x15;
1302 pub const SYN: u8 = 0x16;
1304 pub const ETB: u8 = 0x17;
1306 pub const CAN: u8 = 0x18;
1308 pub const EM: u8 = 0x19;
1310 pub const SUB: u8 = 0x1A;
1312 pub const ESC: u8 = 0x1B;
1314 pub const FS: u8 = 0x1C;
1316 pub const GS: u8 = 0x1D;
1318 pub const RS: u8 = 0x1E;
1320 pub const US: u8 = 0x1F;
1322 pub const DEL: u8 = 0x7f;
1324}
1325
1326#[allow(non_snake_case)]
1332pub mod C1 {
1333 pub const PAD: u8 = 0x80;
1335 pub const HOP: u8 = 0x81;
1337 pub const BPH: u8 = 0x82;
1339 pub const NBH: u8 = 0x83;
1341 pub const IND: u8 = 0x84;
1343 pub const NEL: u8 = 0x85;
1345 pub const SSA: u8 = 0x86;
1347 pub const ESA: u8 = 0x87;
1349 pub const HTS: u8 = 0x88;
1351 pub const HTJ: u8 = 0x89;
1353 pub const VTS: u8 = 0x8A;
1355 pub const PLD: u8 = 0x8B;
1357 pub const PLU: u8 = 0x8C;
1359 pub const RI: u8 = 0x8D;
1361 pub const SS2: u8 = 0x8E;
1363 pub const SS3: u8 = 0x8F;
1365 pub const DCS: u8 = 0x90;
1367 pub const PU1: u8 = 0x91;
1369 pub const PU2: u8 = 0x92;
1371 pub const STS: u8 = 0x93;
1373 pub const CCH: u8 = 0x94;
1375 pub const MW: u8 = 0x95;
1377 pub const SPA: u8 = 0x96;
1379 pub const EPA: u8 = 0x97;
1381 pub const SOS: u8 = 0x98;
1383 pub const SGCI: u8 = 0x99;
1385 pub const DECID: u8 = 0x9a;
1387 pub const CSI: u8 = 0x9B;
1389 pub const ST: u8 = 0x9C;
1391 pub const OSC: u8 = 0x9D;
1393 pub const PM: u8 = 0x9E;
1395 pub const APC: u8 = 0x9F;
1397}
1398
1399#[cfg(test)]
1403mod tests {
1404 use super::{
1405 parse_number, parse_rgb_color, Attr, CharsetIndex, Color, Handler, Processor, Rgb,
1406 StandardCharset, TermInfo,
1407 };
1408 use crate::index::{Column, Line};
1409 use std::io;
1410
1411 struct Void;
1413
1414 impl io::Write for Void {
1415 fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
1416 Ok(bytes.len())
1417 }
1418
1419 fn flush(&mut self) -> io::Result<()> {
1420 Ok(())
1421 }
1422 }
1423
1424 #[derive(Default)]
1425 struct AttrHandler {
1426 attr: Option<Attr>,
1427 }
1428
1429 impl Handler for AttrHandler {
1430 fn terminal_attribute(&mut self, attr: Attr) {
1431 self.attr = Some(attr);
1432 }
1433 }
1434
1435 impl TermInfo for AttrHandler {
1436 fn lines(&self) -> Line {
1437 Line(24)
1438 }
1439
1440 fn cols(&self) -> Column {
1441 Column(80)
1442 }
1443 }
1444
1445 #[test]
1446 fn parse_control_attribute() {
1447 static BYTES: &'static [u8] = &[0x1b, 0x5b, 0x31, 0x6d];
1448
1449 let mut parser = Processor::new();
1450 let mut handler = AttrHandler::default();
1451
1452 for byte in &BYTES[..] {
1453 parser.advance(&mut handler, *byte, &mut Void);
1454 }
1455
1456 assert_eq!(handler.attr, Some(Attr::Bold));
1457 }
1458
1459 #[test]
1460 fn parse_truecolor_attr() {
1461 static BYTES: &'static [u8] = &[
1462 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x32, 0x3b, 0x31, 0x32, 0x38, 0x3b, 0x36, 0x36, 0x3b,
1463 0x32, 0x35, 0x35, 0x6d,
1464 ];
1465
1466 let mut parser = Processor::new();
1467 let mut handler = AttrHandler::default();
1468
1469 for byte in &BYTES[..] {
1470 parser.advance(&mut handler, *byte, &mut Void);
1471 }
1472
1473 let spec = Rgb {
1474 r: 128,
1475 g: 66,
1476 b: 255,
1477 };
1478
1479 assert_eq!(handler.attr, Some(Attr::Foreground(Color::Spec(spec))));
1480 }
1481
1482 #[test]
1484 fn parse_zsh_startup() {
1485 static BYTES: &'static [u8] = &[
1486 0x1b, 0x5b, 0x31, 0x6d, 0x1b, 0x5b, 0x37, 0x6d, 0x25, 0x1b, 0x5b, 0x32, 0x37, 0x6d,
1487 0x1b, 0x5b, 0x31, 0x6d, 0x1b, 0x5b, 0x30, 0x6d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
1488 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
1489 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
1490 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
1491 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
1492 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
1493 0x20, 0x20, 0x20, 0x0d, 0x20, 0x0d, 0x0d, 0x1b, 0x5b, 0x30, 0x6d, 0x1b, 0x5b, 0x32,
1494 0x37, 0x6d, 0x1b, 0x5b, 0x32, 0x34, 0x6d, 0x1b, 0x5b, 0x4a, 0x6a, 0x77, 0x69, 0x6c,
1495 0x6d, 0x40, 0x6a, 0x77, 0x69, 0x6c, 0x6d, 0x2d, 0x64, 0x65, 0x73, 0x6b, 0x20, 0x1b,
1496 0x5b, 0x30, 0x31, 0x3b, 0x33, 0x32, 0x6d, 0xe2, 0x9e, 0x9c, 0x20, 0x1b, 0x5b, 0x30,
1497 0x31, 0x3b, 0x33, 0x32, 0x6d, 0x20, 0x1b, 0x5b, 0x33, 0x36, 0x6d, 0x7e, 0x2f, 0x63,
1498 0x6f, 0x64, 0x65,
1499 ];
1500
1501 let mut handler = AttrHandler::default();
1502 let mut parser = Processor::new();
1503
1504 for byte in &BYTES[..] {
1505 parser.advance(&mut handler, *byte, &mut Void);
1506 }
1507 }
1508
1509 struct CharsetHandler {
1510 index: CharsetIndex,
1511 charset: StandardCharset,
1512 }
1513
1514 impl Default for CharsetHandler {
1515 fn default() -> CharsetHandler {
1516 CharsetHandler {
1517 index: CharsetIndex::G0,
1518 charset: StandardCharset::Ascii,
1519 }
1520 }
1521 }
1522
1523 impl Handler for CharsetHandler {
1524 fn configure_charset(&mut self, index: CharsetIndex, charset: StandardCharset) {
1525 self.index = index;
1526 self.charset = charset;
1527 }
1528
1529 fn set_active_charset(&mut self, index: CharsetIndex) {
1530 self.index = index;
1531 }
1532 }
1533
1534 impl TermInfo for CharsetHandler {
1535 fn lines(&self) -> Line {
1536 Line(200)
1537 }
1538 fn cols(&self) -> Column {
1539 Column(90)
1540 }
1541 }
1542
1543 #[test]
1544 fn parse_designate_g0_as_line_drawing() {
1545 static BYTES: &'static [u8] = &[0x1b, b'(', b'0'];
1546 let mut parser = Processor::new();
1547 let mut handler = CharsetHandler::default();
1548
1549 for byte in &BYTES[..] {
1550 parser.advance(&mut handler, *byte, &mut Void);
1551 }
1552
1553 assert_eq!(handler.index, CharsetIndex::G0);
1554 assert_eq!(
1555 handler.charset,
1556 StandardCharset::SpecialCharacterAndLineDrawing
1557 );
1558 }
1559
1560 #[test]
1561 fn parse_designate_g1_as_line_drawing_and_invoke() {
1562 static BYTES: &'static [u8] = &[0x1b, 0x29, 0x30, 0x0e];
1563 let mut parser = Processor::new();
1564 let mut handler = CharsetHandler::default();
1565
1566 for byte in &BYTES[..3] {
1567 parser.advance(&mut handler, *byte, &mut Void);
1568 }
1569
1570 assert_eq!(handler.index, CharsetIndex::G1);
1571 assert_eq!(
1572 handler.charset,
1573 StandardCharset::SpecialCharacterAndLineDrawing
1574 );
1575
1576 let mut handler = CharsetHandler::default();
1577 parser.advance(&mut handler, BYTES[3], &mut Void);
1578
1579 assert_eq!(handler.index, CharsetIndex::G1);
1580 }
1581
1582 #[test]
1583 fn parse_valid_rgb_color() {
1584 assert_eq!(
1585 parse_rgb_color(b"rgb:11/aa/ff"),
1586 Some(Rgb {
1587 r: 0x11,
1588 g: 0xaa,
1589 b: 0xff
1590 })
1591 );
1592 }
1593
1594 #[test]
1595 fn parse_valid_rgb_color2() {
1596 assert_eq!(
1597 parse_rgb_color(b"#11aaff"),
1598 Some(Rgb {
1599 r: 0x11,
1600 g: 0xaa,
1601 b: 0xff
1602 })
1603 );
1604 }
1605
1606 #[test]
1607 fn parse_invalid_number() {
1608 assert_eq!(parse_number(b"1abc"), None);
1609 }
1610
1611 #[test]
1612 fn parse_valid_number() {
1613 assert_eq!(parse_number(b"123"), Some(123));
1614 }
1615
1616 #[test]
1617 fn parse_number_too_large() {
1618 assert_eq!(parse_number(b"321"), None);
1619 }
1620}