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}