1use std::io;
17use std::str;
18
19use log::{debug, trace};
20use serde::{Deserialize, Serialize};
21
22use crate::index::{Column, Line};
23use crate::term::color::Rgb;
24
25fn xparse_color(color: &[u8]) -> Option<Rgb> {
27    if !color.is_empty() && color[0] == b'#' {
28        parse_legacy_color(&color[1..])
29    } else if color.len() >= 4 && &color[..4] == b"rgb:" {
30        parse_rgb_color(&color[4..])
31    } else {
32        None
33    }
34}
35
36fn parse_rgb_color(color: &[u8]) -> Option<Rgb> {
38    let colors = str::from_utf8(color).ok()?.split('/').collect::<Vec<_>>();
39
40    if colors.len() != 3 {
41        return None;
42    }
43
44    let scale = |input: &str| {
46        let max = u32::pow(16, input.len() as u32) - 1;
47        let value = u32::from_str_radix(input, 16).ok()?;
48        Some((255 * value / max) as u8)
49    };
50
51    Some(Rgb { r: scale(colors[0])?, g: scale(colors[1])?, b: scale(colors[2])? })
52}
53
54fn parse_legacy_color(color: &[u8]) -> Option<Rgb> {
56    let item_len = color.len() / 3;
57
58    let color_from_slice = |slice: &[u8]| {
60        let col = usize::from_str_radix(str::from_utf8(slice).ok()?, 16).ok()? << 4;
61        Some((col >> (4 * slice.len().saturating_sub(1))) as u8)
62    };
63
64    Some(Rgb {
65        r: color_from_slice(&color[0..item_len])?,
66        g: color_from_slice(&color[item_len..item_len * 2])?,
67        b: color_from_slice(&color[item_len * 2..])?,
68    })
69}
70
71fn parse_number(input: &[u8]) -> Option<u8> {
72    if input.is_empty() {
73        return None;
74    }
75    let mut num: u8 = 0;
76    for c in input {
77        let c = *c as char;
78        if let Some(digit) = c.to_digit(10) {
79            num = match num.checked_mul(10).and_then(|v| v.checked_add(digit as u8)) {
80                Some(v) => v,
81                None => return None,
82            }
83        } else {
84            return None;
85        }
86    }
87    Some(num)
88}
89
90pub struct Processor {
92    state: ProcessorState,
93    parser: vte::Parser,
94}
95
96struct ProcessorState {
98    preceding_char: Option<char>,
99}
100
101struct Performer<'a, H: Handler + TermInfo, W: io::Write> {
106    state: &'a mut ProcessorState,
107    handler: &'a mut H,
108    writer: &'a mut W,
109}
110
111impl<'a, H: Handler + TermInfo + 'a, W: io::Write> Performer<'a, H, W> {
112    #[inline]
114    pub fn new<'b>(
115        state: &'b mut ProcessorState,
116        handler: &'b mut H,
117        writer: &'b mut W,
118    ) -> Performer<'b, H, W> {
119        Performer { state, handler, writer }
120    }
121}
122
123impl Default for Processor {
124    fn default() -> Processor {
125        Processor { state: ProcessorState { preceding_char: None }, parser: vte::Parser::new() }
126    }
127}
128
129impl Processor {
130    pub fn new() -> Processor {
131        Default::default()
132    }
133
134    #[inline]
135    pub fn advance<H, W>(&mut self, handler: &mut H, byte: u8, writer: &mut W)
136    where
137        H: Handler + TermInfo,
138        W: io::Write,
139    {
140        let mut performer = Performer::new(&mut self.state, handler, writer);
141        self.parser.advance(&mut performer, byte);
142    }
143}
144
145pub trait TermInfo {
147    fn lines(&self) -> Line;
148    fn cols(&self) -> Column;
149}
150
151pub trait Handler {
156    fn set_title(&mut self, _: &str) {}
158
159    fn set_cursor_style(&mut self, _: Option<CursorStyle>) {}
161
162    fn input(&mut self, _c: char) {}
164
165    fn goto(&mut self, _: Line, _: Column) {}
167
168    fn goto_line(&mut self, _: Line) {}
170
171    fn goto_col(&mut self, _: Column) {}
173
174    fn insert_blank(&mut self, _: Column) {}
176
177    fn move_up(&mut self, _: Line) {}
179
180    fn move_down(&mut self, _: Line) {}
182
183    fn identify_terminal<W: io::Write>(&mut self, _: &mut W) {}
187
188    fn device_status<W: io::Write>(&mut self, _: &mut W, _: usize) {}
190
191    fn move_forward(&mut self, _: Column) {}
193
194    fn move_backward(&mut self, _: Column) {}
196
197    fn move_down_and_cr(&mut self, _: Line) {}
199
200    fn move_up_and_cr(&mut self, _: Line) {}
202
203    fn put_tab(&mut self, _count: i64) {}
205
206    fn backspace(&mut self) {}
208
209    fn carriage_return(&mut self) {}
211
212    fn linefeed(&mut self) {}
214
215    fn bell(&mut self) {}
219
220    fn substitute(&mut self) {}
222
223    fn newline(&mut self) {}
225
226    fn set_horizontal_tabstop(&mut self) {}
228
229    fn scroll_up(&mut self, _: Line) {}
231
232    fn scroll_down(&mut self, _: Line) {}
234
235    fn insert_blank_lines(&mut self, _: Line) {}
237
238    fn delete_lines(&mut self, _: Line) {}
240
241    fn erase_chars(&mut self, _: Column) {}
246
247    fn delete_chars(&mut self, _: Column) {}
252
253    fn move_backward_tabs(&mut self, _count: i64) {}
255
256    fn move_forward_tabs(&mut self, _count: i64) {}
258
259    fn save_cursor_position(&mut self) {}
261
262    fn restore_cursor_position(&mut self) {}
264
265    fn clear_line(&mut self, _mode: LineClearMode) {}
267
268    fn clear_screen(&mut self, _mode: ClearMode) {}
270
271    fn clear_tabs(&mut self, _mode: TabulationClearMode) {}
273
274    fn reset_state(&mut self) {}
276
277    fn reverse_index(&mut self) {}
283
284    fn terminal_attribute(&mut self, _attr: Attr) {}
286
287    fn set_mode(&mut self, _mode: Mode) {}
289
290    fn unset_mode(&mut self, _: Mode) {}
292
293    fn set_scrolling_region(&mut self, _top: usize, _bottom: usize) {}
295
296    fn set_keypad_application_mode(&mut self) {}
298
299    fn unset_keypad_application_mode(&mut self) {}
301
302    fn set_active_charset(&mut self, _: CharsetIndex) {}
307
308    fn configure_charset(&mut self, _: CharsetIndex, _: StandardCharset) {}
313
314    fn set_color(&mut self, _: usize, _: Rgb) {}
316
317    fn dynamic_color_sequence<W: io::Write>(&mut self, _: &mut W, _: u8, _: usize) {}
319
320    fn reset_color(&mut self, _: usize) {}
322
323    fn set_clipboard(&mut self, _: u8, _: &[u8]) {}
325
326    fn write_clipboard<W: io::Write>(&mut self, _: u8, _: &mut W) {}
328
329    fn decaln(&mut self) {}
331
332    fn push_title(&mut self) {}
334
335    fn pop_title(&mut self) {}
337}
338
339#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash, Deserialize)]
341pub enum CursorStyle {
342    Block,
344
345    Underline,
347
348    Beam,
350
351    HollowBlock,
353
354    Hidden,
356}
357
358impl Default for CursorStyle {
359    fn default() -> CursorStyle {
360        CursorStyle::Block
361    }
362}
363
364#[derive(Debug, Eq, PartialEq)]
366pub enum Mode {
367    CursorKeys = 1,
369    DECCOLM = 3,
381    Insert = 4,
388    Origin = 6,
390    LineWrap = 7,
392    BlinkingCursor = 12,
394    LineFeedNewLine = 20,
399    ShowCursor = 25,
401    ReportMouseClicks = 1000,
403    ReportCellMouseMotion = 1002,
405    ReportAllMouseMotion = 1003,
407    ReportFocusInOut = 1004,
409    Utf8Mouse = 1005,
411    SgrMouse = 1006,
413    AlternateScroll = 1007,
415    SwapScreenAndSetRestoreCursor = 1049,
417    BracketedPaste = 2004,
419}
420
421impl Mode {
422    pub fn from_primitive(intermediate: Option<&u8>, num: i64) -> Option<Mode> {
426        let private = match intermediate {
427            Some(b'?') => true,
428            None => false,
429            _ => return None,
430        };
431
432        if private {
433            Some(match num {
434                1 => Mode::CursorKeys,
435                3 => Mode::DECCOLM,
436                6 => Mode::Origin,
437                7 => Mode::LineWrap,
438                12 => Mode::BlinkingCursor,
439                25 => Mode::ShowCursor,
440                1000 => Mode::ReportMouseClicks,
441                1002 => Mode::ReportCellMouseMotion,
442                1003 => Mode::ReportAllMouseMotion,
443                1004 => Mode::ReportFocusInOut,
444                1005 => Mode::Utf8Mouse,
445                1006 => Mode::SgrMouse,
446                1007 => Mode::AlternateScroll,
447                1049 => Mode::SwapScreenAndSetRestoreCursor,
448                2004 => Mode::BracketedPaste,
449                _ => {
450                    trace!("[unimplemented] primitive mode: {}", num);
451                    return None;
452                },
453            })
454        } else {
455            Some(match num {
456                4 => Mode::Insert,
457                20 => Mode::LineFeedNewLine,
458                _ => return None,
459            })
460        }
461    }
462}
463
464#[derive(Debug)]
468pub enum LineClearMode {
469    Right,
471    Left,
473    All,
475}
476
477#[derive(Debug)]
481pub enum ClearMode {
482    Below,
484    Above,
486    All,
488    Saved,
490}
491
492#[derive(Debug)]
494pub enum TabulationClearMode {
495    Current,
497    All,
499}
500
501#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
506pub enum NamedColor {
507    Black = 0,
509    Red,
511    Green,
513    Yellow,
515    Blue,
517    Magenta,
519    Cyan,
521    White,
523    BrightBlack,
525    BrightRed,
527    BrightGreen,
529    BrightYellow,
531    BrightBlue,
533    BrightMagenta,
535    BrightCyan,
537    BrightWhite,
539    Foreground = 256,
541    Background,
543    Cursor,
545    DimBlack,
547    DimRed,
549    DimGreen,
551    DimYellow,
553    DimBlue,
555    DimMagenta,
557    DimCyan,
559    DimWhite,
561    BrightForeground,
563    DimForeground,
565}
566
567impl NamedColor {
568    pub fn to_bright(self) -> Self {
569        match self {
570            NamedColor::Foreground => NamedColor::BrightForeground,
571            NamedColor::Black => NamedColor::BrightBlack,
572            NamedColor::Red => NamedColor::BrightRed,
573            NamedColor::Green => NamedColor::BrightGreen,
574            NamedColor::Yellow => NamedColor::BrightYellow,
575            NamedColor::Blue => NamedColor::BrightBlue,
576            NamedColor::Magenta => NamedColor::BrightMagenta,
577            NamedColor::Cyan => NamedColor::BrightCyan,
578            NamedColor::White => NamedColor::BrightWhite,
579            NamedColor::DimForeground => NamedColor::Foreground,
580            NamedColor::DimBlack => NamedColor::Black,
581            NamedColor::DimRed => NamedColor::Red,
582            NamedColor::DimGreen => NamedColor::Green,
583            NamedColor::DimYellow => NamedColor::Yellow,
584            NamedColor::DimBlue => NamedColor::Blue,
585            NamedColor::DimMagenta => NamedColor::Magenta,
586            NamedColor::DimCyan => NamedColor::Cyan,
587            NamedColor::DimWhite => NamedColor::White,
588            val => val,
589        }
590    }
591
592    pub fn to_dim(self) -> Self {
593        match self {
594            NamedColor::Black => NamedColor::DimBlack,
595            NamedColor::Red => NamedColor::DimRed,
596            NamedColor::Green => NamedColor::DimGreen,
597            NamedColor::Yellow => NamedColor::DimYellow,
598            NamedColor::Blue => NamedColor::DimBlue,
599            NamedColor::Magenta => NamedColor::DimMagenta,
600            NamedColor::Cyan => NamedColor::DimCyan,
601            NamedColor::White => NamedColor::DimWhite,
602            NamedColor::Foreground => NamedColor::DimForeground,
603            NamedColor::BrightBlack => NamedColor::Black,
604            NamedColor::BrightRed => NamedColor::Red,
605            NamedColor::BrightGreen => NamedColor::Green,
606            NamedColor::BrightYellow => NamedColor::Yellow,
607            NamedColor::BrightBlue => NamedColor::Blue,
608            NamedColor::BrightMagenta => NamedColor::Magenta,
609            NamedColor::BrightCyan => NamedColor::Cyan,
610            NamedColor::BrightWhite => NamedColor::White,
611            NamedColor::BrightForeground => NamedColor::Foreground,
612            val => val,
613        }
614    }
615}
616
617#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
618pub enum Color {
619    Named(NamedColor),
620    Spec(Rgb),
621    Indexed(u8),
622}
623
624#[derive(Debug, Eq, PartialEq)]
626pub enum Attr {
627    Reset,
629    Bold,
631    Dim,
633    Italic,
635    Underline,
637    BlinkSlow,
639    BlinkFast,
641    Reverse,
643    Hidden,
645    Strike,
647    CancelBold,
649    CancelBoldDim,
651    CancelItalic,
653    CancelUnderline,
655    CancelBlink,
657    CancelReverse,
659    CancelHidden,
661    CancelStrike,
663    Foreground(Color),
665    Background(Color),
667}
668
669#[derive(Clone, Copy, Debug, Eq, PartialEq)]
671pub enum CharsetIndex {
672    G0,
674    G1,
675    G2,
676    G3,
677}
678
679impl Default for CharsetIndex {
680    fn default() -> Self {
681        CharsetIndex::G0
682    }
683}
684
685#[derive(Clone, Copy, Debug, Eq, PartialEq)]
687pub enum StandardCharset {
688    Ascii,
689    SpecialCharacterAndLineDrawing,
690}
691
692impl Default for StandardCharset {
693    fn default() -> Self {
694        StandardCharset::Ascii
695    }
696}
697
698impl<'a, H, W> vte::Perform for Performer<'a, H, W>
699where
700    H: Handler + TermInfo + 'a,
701    W: io::Write + 'a,
702{
703    #[inline]
704    fn print(&mut self, c: char) {
705        self.handler.input(c);
706        self.state.preceding_char = Some(c);
707    }
708
709    #[inline]
710    fn execute(&mut self, byte: u8) {
711        match byte {
712            C0::HT => self.handler.put_tab(1),
713            C0::BS => self.handler.backspace(),
714            C0::CR => self.handler.carriage_return(),
715            C0::LF | C0::VT | C0::FF => self.handler.linefeed(),
716            C0::BEL => self.handler.bell(),
717            C0::SUB => self.handler.substitute(),
718            C0::SI => self.handler.set_active_charset(CharsetIndex::G0),
719            C0::SO => self.handler.set_active_charset(CharsetIndex::G1),
720            _ => debug!("[unhandled] execute byte={:02x}", byte),
721        }
722    }
723
724    #[inline]
725    fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool) {
726        debug!(
727            "[unhandled hook] params={:?}, ints: {:?}, ignore: {:?}",
728            params, intermediates, ignore
729        );
730    }
731
732    #[inline]
733    fn put(&mut self, byte: u8) {
734        debug!("[unhandled put] byte={:?}", byte);
735    }
736
737    #[inline]
738    fn unhook(&mut self) {
739        debug!("[unhandled unhook]");
740    }
741
742    #[inline]
744    fn osc_dispatch(&mut self, params: &[&[u8]]) {
745        let writer = &mut self.writer;
746
747        fn unhandled(params: &[&[u8]]) {
748            let mut buf = String::new();
749            for items in params {
750                buf.push_str("[");
751                for item in *items {
752                    buf.push_str(&format!("{:?},", *item as char));
753                }
754                buf.push_str("],");
755            }
756            debug!("[unhandled osc_dispatch]: [{}] at line {}", &buf, line!());
757        }
758
759        if params.is_empty() || params[0].is_empty() {
760            return;
761        }
762
763        match params[0] {
764            b"0" | b"2" => {
766                if params.len() >= 2 {
767                    let title = params[1..]
768                        .iter()
769                        .flat_map(|x| str::from_utf8(x))
770                        .collect::<Vec<&str>>()
771                        .join(";");
772                    self.handler.set_title(&title);
773                    return;
774                }
775                unhandled(params);
776            },
777
778            b"1" => (),
781
782            b"4" => {
784                if params.len() > 1 && params.len() % 2 != 0 {
785                    for chunk in params[1..].chunks(2) {
786                        let index = parse_number(chunk[0]);
787                        let color = xparse_color(chunk[1]);
788                        if let (Some(i), Some(c)) = (index, color) {
789                            self.handler.set_color(i as usize, c);
790                            return;
791                        }
792                    }
793                }
794                unhandled(params);
795            },
796
797            b"10" | b"11" | b"12" => {
799                if params.len() >= 2 {
800                    if let Some(mut dynamic_code) = parse_number(params[0]) {
801                        for param in ¶ms[1..] {
802                            let offset = dynamic_code as usize - 10;
804                            let index = NamedColor::Foreground as usize + offset;
805
806                            if index > NamedColor::Cursor as usize {
808                                unhandled(params);
809                                break;
810                            }
811
812                            if let Some(color) = xparse_color(param) {
813                                self.handler.set_color(index, color);
814                            } else if param == b"?" {
815                                self.handler.dynamic_color_sequence(writer, dynamic_code, index);
816                            } else {
817                                unhandled(params);
818                            }
819                            dynamic_code += 1;
820                        }
821                        return;
822                    }
823                }
824                unhandled(params);
825            },
826
827            b"50" => {
829                if params.len() >= 2
830                    && params[1].len() >= 13
831                    && params[1][0..12] == *b"CursorShape="
832                {
833                    let style = match params[1][12] as char {
834                        '0' => CursorStyle::Block,
835                        '1' => CursorStyle::Beam,
836                        '2' => CursorStyle::Underline,
837                        _ => return unhandled(params),
838                    };
839                    self.handler.set_cursor_style(Some(style));
840                    return;
841                }
842                unhandled(params);
843            },
844
845            b"52" => {
847                if params.len() < 3 {
848                    return unhandled(params);
849                }
850
851                let clipboard = params[1].get(0).unwrap_or(&b'c');
852                match params[2] {
853                    b"?" => self.handler.write_clipboard(*clipboard, writer),
854                    base64 => self.handler.set_clipboard(*clipboard, base64),
855                }
856            },
857
858            b"104" => {
860                if params.len() == 1 {
862                    for i in 0..256 {
863                        self.handler.reset_color(i);
864                    }
865                    return;
866                }
867
868                for param in ¶ms[1..] {
870                    match parse_number(param) {
871                        Some(index) => self.handler.reset_color(index as usize),
872                        None => unhandled(params),
873                    }
874                }
875            },
876
877            b"110" => self.handler.reset_color(NamedColor::Foreground as usize),
879
880            b"111" => self.handler.reset_color(NamedColor::Background as usize),
882
883            b"112" => self.handler.reset_color(NamedColor::Cursor as usize),
885
886            _ => unhandled(params),
887        }
888    }
889
890    #[inline]
891    fn csi_dispatch(
892        &mut self,
893        args: &[i64],
894        intermediates: &[u8],
895        has_ignored_intermediates: bool,
896        action: char,
897    ) {
898        macro_rules! unhandled {
899            () => {{
900                debug!(
901                    "[Unhandled CSI] action={:?}, args={:?}, intermediates={:?}",
902                    action, args, intermediates
903                );
904            }};
905        }
906
907        macro_rules! arg_or_default {
908            (idx: $idx:expr, default: $default:expr) => {
909                args.get($idx)
910                    .and_then(|v| if *v == 0 { None } else { Some(*v) })
911                    .unwrap_or($default)
912            };
913        }
914
915        if has_ignored_intermediates || intermediates.len() > 1 {
916            unhandled!();
917            return;
918        }
919
920        let handler = &mut self.handler;
921        let writer = &mut self.writer;
922
923        match (action, intermediates.get(0)) {
924            ('@', None) => {
925                handler.insert_blank(Column(arg_or_default!(idx: 0, default: 1) as usize))
926            },
927            ('A', None) => {
928                handler.move_up(Line(arg_or_default!(idx: 0, default: 1) as usize));
929            },
930            ('b', None) => {
931                if let Some(c) = self.state.preceding_char {
932                    for _ in 0..arg_or_default!(idx: 0, default: 1) {
933                        handler.input(c);
934                    }
935                } else {
936                    debug!("tried to repeat with no preceding char");
937                }
938            },
939            ('B', None) | ('e', None) => {
940                handler.move_down(Line(arg_or_default!(idx: 0, default: 1) as usize))
941            },
942            ('c', None) if arg_or_default!(idx: 0, default: 0) == 0 => {
943                handler.identify_terminal(writer)
944            },
945            ('C', None) | ('a', None) => {
946                handler.move_forward(Column(arg_or_default!(idx: 0, default: 1) as usize))
947            },
948            ('D', None) => {
949                handler.move_backward(Column(arg_or_default!(idx: 0, default: 1) as usize))
950            },
951            ('E', None) => {
952                handler.move_down_and_cr(Line(arg_or_default!(idx: 0, default: 1) as usize))
953            },
954            ('F', None) => {
955                handler.move_up_and_cr(Line(arg_or_default!(idx: 0, default: 1) as usize))
956            },
957            ('g', None) => {
958                let mode = match arg_or_default!(idx: 0, default: 0) {
959                    0 => TabulationClearMode::Current,
960                    3 => TabulationClearMode::All,
961                    _ => {
962                        unhandled!();
963                        return;
964                    },
965                };
966
967                handler.clear_tabs(mode);
968            },
969            ('G', None) | ('`', None) => {
970                handler.goto_col(Column(arg_or_default!(idx: 0, default: 1) as usize - 1))
971            },
972            ('H', None) | ('f', None) => {
973                let y = arg_or_default!(idx: 0, default: 1) as usize;
974                let x = arg_or_default!(idx: 1, default: 1) as usize;
975                handler.goto(Line(y - 1), Column(x - 1));
976            },
977            ('I', None) => handler.move_forward_tabs(arg_or_default!(idx: 0, default: 1)),
978            ('J', None) => {
979                let mode = match arg_or_default!(idx: 0, default: 0) {
980                    0 => ClearMode::Below,
981                    1 => ClearMode::Above,
982                    2 => ClearMode::All,
983                    3 => ClearMode::Saved,
984                    _ => {
985                        unhandled!();
986                        return;
987                    },
988                };
989
990                handler.clear_screen(mode);
991            },
992            ('K', None) => {
993                let mode = match arg_or_default!(idx: 0, default: 0) {
994                    0 => LineClearMode::Right,
995                    1 => LineClearMode::Left,
996                    2 => LineClearMode::All,
997                    _ => {
998                        unhandled!();
999                        return;
1000                    },
1001                };
1002
1003                handler.clear_line(mode);
1004            },
1005            ('S', None) => handler.scroll_up(Line(arg_or_default!(idx: 0, default: 1) as usize)),
1006            ('t', None) => match arg_or_default!(idx: 0, default: 1) as usize {
1007                22 => handler.push_title(),
1008                23 => handler.pop_title(),
1009                _ => unhandled!(),
1010            },
1011            ('T', None) => handler.scroll_down(Line(arg_or_default!(idx: 0, default: 1) as usize)),
1012            ('L', None) => {
1013                handler.insert_blank_lines(Line(arg_or_default!(idx: 0, default: 1) as usize))
1014            },
1015            ('l', intermediate) => {
1016                for arg in args {
1017                    match Mode::from_primitive(intermediate, *arg) {
1018                        Some(mode) => handler.unset_mode(mode),
1019                        None => {
1020                            unhandled!();
1021                            return;
1022                        },
1023                    }
1024                }
1025            },
1026            ('M', None) => handler.delete_lines(Line(arg_or_default!(idx: 0, default: 1) as usize)),
1027            ('X', None) => {
1028                handler.erase_chars(Column(arg_or_default!(idx: 0, default: 1) as usize))
1029            },
1030            ('P', None) => {
1031                handler.delete_chars(Column(arg_or_default!(idx: 0, default: 1) as usize))
1032            },
1033            ('Z', None) => handler.move_backward_tabs(arg_or_default!(idx: 0, default: 1)),
1034            ('d', None) => {
1035                handler.goto_line(Line(arg_or_default!(idx: 0, default: 1) as usize - 1))
1036            },
1037            ('h', intermediate) => {
1038                for arg in args {
1039                    match Mode::from_primitive(intermediate, *arg) {
1040                        Some(mode) => handler.set_mode(mode),
1041                        None => {
1042                            unhandled!();
1043                            return;
1044                        },
1045                    }
1046                }
1047            },
1048            ('m', None) => {
1049                if args.is_empty() {
1050                    handler.terminal_attribute(Attr::Reset);
1051                } else {
1052                    for attr in attrs_from_sgr_parameters(args) {
1053                        match attr {
1054                            Some(attr) => handler.terminal_attribute(attr),
1055                            None => {
1056                                unhandled!();
1057                                return;
1058                            },
1059                        }
1060                    }
1061                }
1062            },
1063            ('n', None) => {
1064                handler.device_status(writer, arg_or_default!(idx: 0, default: 0) as usize)
1065            },
1066            ('q', Some(b' ')) => {
1067                let style = match arg_or_default!(idx: 0, default: 0) {
1069                    0 => None,
1070                    1 | 2 => Some(CursorStyle::Block),
1071                    3 | 4 => Some(CursorStyle::Underline),
1072                    5 | 6 => Some(CursorStyle::Beam),
1073                    _ => {
1074                        unhandled!();
1075                        return;
1076                    },
1077                };
1078
1079                handler.set_cursor_style(style);
1080            },
1081            ('r', None) => {
1082                let top = arg_or_default!(idx: 0, default: 1) as usize;
1083                let bottom = arg_or_default!(idx: 1, default: handler.lines().0 as _) as usize;
1084
1085                handler.set_scrolling_region(top, bottom);
1086            },
1087            ('s', None) => handler.save_cursor_position(),
1088            ('u', None) => handler.restore_cursor_position(),
1089            _ => unhandled!(),
1090        }
1091    }
1092
1093    #[inline]
1094    fn esc_dispatch(&mut self, params: &[i64], intermediates: &[u8], _ignore: bool, byte: u8) {
1095        macro_rules! unhandled {
1096            () => {{
1097                debug!(
1098                    "[unhandled] esc_dispatch params={:?}, ints={:?}, byte={:?} ({:02x})",
1099                    params, intermediates, byte as char, byte
1100                );
1101            }};
1102        }
1103
1104        macro_rules! configure_charset {
1105            ($charset:path, $intermediate:expr) => {{
1106                let index: CharsetIndex = match $intermediate {
1107                    Some(b'(') => CharsetIndex::G0,
1108                    Some(b')') => CharsetIndex::G1,
1109                    Some(b'*') => CharsetIndex::G2,
1110                    Some(b'+') => CharsetIndex::G3,
1111                    _ => {
1112                        unhandled!();
1113                        return;
1114                    },
1115                };
1116                self.handler.configure_charset(index, $charset)
1117            }};
1118        }
1119
1120        match (byte, intermediates.get(0)) {
1121            (b'B', intermediate) => configure_charset!(StandardCharset::Ascii, intermediate),
1122            (b'D', None) => self.handler.linefeed(),
1123            (b'E', None) => {
1124                self.handler.linefeed();
1125                self.handler.carriage_return();
1126            },
1127            (b'H', None) => self.handler.set_horizontal_tabstop(),
1128            (b'M', None) => self.handler.reverse_index(),
1129            (b'Z', None) => self.handler.identify_terminal(self.writer),
1130            (b'c', None) => self.handler.reset_state(),
1131            (b'0', intermediate) => {
1132                configure_charset!(StandardCharset::SpecialCharacterAndLineDrawing, intermediate)
1133            },
1134            (b'7', None) => self.handler.save_cursor_position(),
1135            (b'8', Some(b'#')) => self.handler.decaln(),
1136            (b'8', None) => self.handler.restore_cursor_position(),
1137            (b'=', None) => self.handler.set_keypad_application_mode(),
1138            (b'>', None) => self.handler.unset_keypad_application_mode(),
1139            (b'\\', None) => (),
1141            _ => unhandled!(),
1142        }
1143    }
1144}
1145
1146fn attrs_from_sgr_parameters(parameters: &[i64]) -> Vec<Option<Attr>> {
1147    let mut i = 0; let mut attrs = Vec::with_capacity(parameters.len());
1150    loop {
1151        if i >= parameters.len() {
1152            break;
1154        }
1155
1156        let attr = match parameters[i] {
1157            0 => Some(Attr::Reset),
1158            1 => Some(Attr::Bold),
1159            2 => Some(Attr::Dim),
1160            3 => Some(Attr::Italic),
1161            4 => Some(Attr::Underline),
1162            5 => Some(Attr::BlinkSlow),
1163            6 => Some(Attr::BlinkFast),
1164            7 => Some(Attr::Reverse),
1165            8 => Some(Attr::Hidden),
1166            9 => Some(Attr::Strike),
1167            21 => Some(Attr::CancelBold),
1168            22 => Some(Attr::CancelBoldDim),
1169            23 => Some(Attr::CancelItalic),
1170            24 => Some(Attr::CancelUnderline),
1171            25 => Some(Attr::CancelBlink),
1172            27 => Some(Attr::CancelReverse),
1173            28 => Some(Attr::CancelHidden),
1174            29 => Some(Attr::CancelStrike),
1175            30 => Some(Attr::Foreground(Color::Named(NamedColor::Black))),
1176            31 => Some(Attr::Foreground(Color::Named(NamedColor::Red))),
1177            32 => Some(Attr::Foreground(Color::Named(NamedColor::Green))),
1178            33 => Some(Attr::Foreground(Color::Named(NamedColor::Yellow))),
1179            34 => Some(Attr::Foreground(Color::Named(NamedColor::Blue))),
1180            35 => Some(Attr::Foreground(Color::Named(NamedColor::Magenta))),
1181            36 => Some(Attr::Foreground(Color::Named(NamedColor::Cyan))),
1182            37 => Some(Attr::Foreground(Color::Named(NamedColor::White))),
1183            38 => {
1184                let mut start = 0;
1185                if let Some(color) = parse_sgr_color(¶meters[i..], &mut start) {
1186                    i += start;
1187                    Some(Attr::Foreground(color))
1188                } else {
1189                    None
1190                }
1191            },
1192            39 => Some(Attr::Foreground(Color::Named(NamedColor::Foreground))),
1193            40 => Some(Attr::Background(Color::Named(NamedColor::Black))),
1194            41 => Some(Attr::Background(Color::Named(NamedColor::Red))),
1195            42 => Some(Attr::Background(Color::Named(NamedColor::Green))),
1196            43 => Some(Attr::Background(Color::Named(NamedColor::Yellow))),
1197            44 => Some(Attr::Background(Color::Named(NamedColor::Blue))),
1198            45 => Some(Attr::Background(Color::Named(NamedColor::Magenta))),
1199            46 => Some(Attr::Background(Color::Named(NamedColor::Cyan))),
1200            47 => Some(Attr::Background(Color::Named(NamedColor::White))),
1201            48 => {
1202                let mut start = 0;
1203                if let Some(color) = parse_sgr_color(¶meters[i..], &mut start) {
1204                    i += start;
1205                    Some(Attr::Background(color))
1206                } else {
1207                    None
1208                }
1209            },
1210            49 => Some(Attr::Background(Color::Named(NamedColor::Background))),
1211            90 => Some(Attr::Foreground(Color::Named(NamedColor::BrightBlack))),
1212            91 => Some(Attr::Foreground(Color::Named(NamedColor::BrightRed))),
1213            92 => Some(Attr::Foreground(Color::Named(NamedColor::BrightGreen))),
1214            93 => Some(Attr::Foreground(Color::Named(NamedColor::BrightYellow))),
1215            94 => Some(Attr::Foreground(Color::Named(NamedColor::BrightBlue))),
1216            95 => Some(Attr::Foreground(Color::Named(NamedColor::BrightMagenta))),
1217            96 => Some(Attr::Foreground(Color::Named(NamedColor::BrightCyan))),
1218            97 => Some(Attr::Foreground(Color::Named(NamedColor::BrightWhite))),
1219            100 => Some(Attr::Background(Color::Named(NamedColor::BrightBlack))),
1220            101 => Some(Attr::Background(Color::Named(NamedColor::BrightRed))),
1221            102 => Some(Attr::Background(Color::Named(NamedColor::BrightGreen))),
1222            103 => Some(Attr::Background(Color::Named(NamedColor::BrightYellow))),
1223            104 => Some(Attr::Background(Color::Named(NamedColor::BrightBlue))),
1224            105 => Some(Attr::Background(Color::Named(NamedColor::BrightMagenta))),
1225            106 => Some(Attr::Background(Color::Named(NamedColor::BrightCyan))),
1226            107 => Some(Attr::Background(Color::Named(NamedColor::BrightWhite))),
1227            _ => None,
1228        };
1229
1230        attrs.push(attr);
1231
1232        i += 1; }
1234    attrs
1235}
1236
1237fn parse_sgr_color(attrs: &[i64], i: &mut usize) -> Option<Color> {
1239    if attrs.len() < 2 {
1240        return None;
1241    }
1242
1243    match attrs[*i + 1] {
1244        2 => {
1245            if attrs.len() < 5 {
1247                debug!("Expected RGB color spec; got {:?}", attrs);
1248                return None;
1249            }
1250
1251            let r = attrs[*i + 2];
1252            let g = attrs[*i + 3];
1253            let b = attrs[*i + 4];
1254
1255            *i += 4;
1256
1257            let range = 0..256;
1258            if !range.contains(&r) || !range.contains(&g) || !range.contains(&b) {
1259                debug!("Invalid RGB color spec: ({}, {}, {})", r, g, b);
1260                return None;
1261            }
1262
1263            Some(Color::Spec(Rgb { r: r as u8, g: g as u8, b: b as u8 }))
1264        },
1265        5 => {
1266            if attrs.len() < 3 {
1267                debug!("Expected color index; got {:?}", attrs);
1268                None
1269            } else {
1270                *i += 2;
1271                let idx = attrs[*i];
1272                match idx {
1273                    0..=255 => Some(Color::Indexed(idx as u8)),
1274                    _ => {
1275                        debug!("Invalid color index: {}", idx);
1276                        None
1277                    },
1278                }
1279            }
1280        },
1281        _ => {
1282            debug!("Unexpected color attr: {}", attrs[*i + 1]);
1283            None
1284        },
1285    }
1286}
1287
1288#[allow(non_snake_case)]
1290pub mod C0 {
1291    pub const NUL: u8 = 0x00;
1293    pub const SOH: u8 = 0x01;
1295    pub const STX: u8 = 0x02;
1297    pub const ETX: u8 = 0x03;
1299    pub const EOT: u8 = 0x04;
1301    pub const ENQ: u8 = 0x05;
1303    pub const ACK: u8 = 0x06;
1305    pub const BEL: u8 = 0x07;
1307    pub const BS: u8 = 0x08;
1309    pub const HT: u8 = 0x09;
1311    pub const LF: u8 = 0x0A;
1313    pub const VT: u8 = 0x0B;
1315    pub const FF: u8 = 0x0C;
1317    pub const CR: u8 = 0x0D;
1319    pub const SO: u8 = 0x0E;
1321    pub const SI: u8 = 0x0F;
1323    pub const DLE: u8 = 0x10;
1325    pub const XON: u8 = 0x11;
1327    pub const DC2: u8 = 0x12;
1329    pub const XOFF: u8 = 0x13;
1331    pub const DC4: u8 = 0x14;
1333    pub const NAK: u8 = 0x15;
1335    pub const SYN: u8 = 0x16;
1337    pub const ETB: u8 = 0x17;
1339    pub const CAN: u8 = 0x18;
1341    pub const EM: u8 = 0x19;
1343    pub const SUB: u8 = 0x1A;
1345    pub const ESC: u8 = 0x1B;
1347    pub const FS: u8 = 0x1C;
1349    pub const GS: u8 = 0x1D;
1351    pub const RS: u8 = 0x1E;
1353    pub const US: u8 = 0x1F;
1355    pub const DEL: u8 = 0x7f;
1357}
1358
1359#[cfg(test)]
1363mod tests {
1364    use super::{
1365        parse_number, xparse_color, Attr, CharsetIndex, Color, Handler, Processor, StandardCharset,
1366        TermInfo,
1367    };
1368    use crate::index::{Column, Line};
1369    use crate::term::color::Rgb;
1370    use std::io;
1371
1372    struct MockHandler {
1373        index: CharsetIndex,
1374        charset: StandardCharset,
1375        attr: Option<Attr>,
1376        identity_reported: bool,
1377    }
1378
1379    impl Handler for MockHandler {
1380        fn terminal_attribute(&mut self, attr: Attr) {
1381            self.attr = Some(attr);
1382        }
1383
1384        fn configure_charset(&mut self, index: CharsetIndex, charset: StandardCharset) {
1385            self.index = index;
1386            self.charset = charset;
1387        }
1388
1389        fn set_active_charset(&mut self, index: CharsetIndex) {
1390            self.index = index;
1391        }
1392
1393        fn identify_terminal<W: io::Write>(&mut self, _: &mut W) {
1394            self.identity_reported = true;
1395        }
1396
1397        fn reset_state(&mut self) {
1398            *self = Self::default();
1399        }
1400    }
1401
1402    impl TermInfo for MockHandler {
1403        fn lines(&self) -> Line {
1404            Line(200)
1405        }
1406
1407        fn cols(&self) -> Column {
1408            Column(90)
1409        }
1410    }
1411
1412    impl Default for MockHandler {
1413        fn default() -> MockHandler {
1414            MockHandler {
1415                index: CharsetIndex::G0,
1416                charset: StandardCharset::Ascii,
1417                attr: None,
1418                identity_reported: false,
1419            }
1420        }
1421    }
1422
1423    #[test]
1424    fn parse_control_attribute() {
1425        static BYTES: &[u8] = &[0x1b, b'[', b'1', b'm'];
1426
1427        let mut parser = Processor::new();
1428        let mut handler = MockHandler::default();
1429
1430        for byte in &BYTES[..] {
1431            parser.advance(&mut handler, *byte, &mut io::sink());
1432        }
1433
1434        assert_eq!(handler.attr, Some(Attr::Bold));
1435    }
1436
1437    #[test]
1438    fn parse_terminal_identity_csi() {
1439        let bytes: &[u8] = &[0x1b, b'[', b'1', b'c'];
1440
1441        let mut parser = Processor::new();
1442        let mut handler = MockHandler::default();
1443
1444        for byte in &bytes[..] {
1445            parser.advance(&mut handler, *byte, &mut io::sink());
1446        }
1447
1448        assert!(!handler.identity_reported);
1449        handler.reset_state();
1450
1451        let bytes: &[u8] = &[0x1b, b'[', b'c'];
1452
1453        for byte in &bytes[..] {
1454            parser.advance(&mut handler, *byte, &mut io::sink());
1455        }
1456
1457        assert!(handler.identity_reported);
1458        handler.reset_state();
1459
1460        let bytes: &[u8] = &[0x1b, b'[', b'0', b'c'];
1461
1462        for byte in &bytes[..] {
1463            parser.advance(&mut handler, *byte, &mut io::sink());
1464        }
1465
1466        assert!(handler.identity_reported);
1467    }
1468
1469    #[test]
1470    fn parse_terminal_identity_esc() {
1471        let bytes: &[u8] = &[0x1b, b'Z'];
1472
1473        let mut parser = Processor::new();
1474        let mut handler = MockHandler::default();
1475
1476        for byte in &bytes[..] {
1477            parser.advance(&mut handler, *byte, &mut io::sink());
1478        }
1479
1480        assert!(handler.identity_reported);
1481        handler.reset_state();
1482
1483        let bytes: &[u8] = &[0x1b, b'#', b'Z'];
1484
1485        let mut parser = Processor::new();
1486        let mut handler = MockHandler::default();
1487
1488        for byte in &bytes[..] {
1489            parser.advance(&mut handler, *byte, &mut io::sink());
1490        }
1491
1492        assert!(!handler.identity_reported);
1493        handler.reset_state();
1494    }
1495
1496    #[test]
1497    fn parse_truecolor_attr() {
1498        static BYTES: &[u8] = &[
1499            0x1b, b'[', b'3', b'8', b';', b'2', b';', b'1', b'2', b'8', b';', b'6', b'6', b';',
1500            b'2', b'5', b'5', b'm',
1501        ];
1502
1503        let mut parser = Processor::new();
1504        let mut handler = MockHandler::default();
1505
1506        for byte in &BYTES[..] {
1507            parser.advance(&mut handler, *byte, &mut io::sink());
1508        }
1509
1510        let spec = Rgb { r: 128, g: 66, b: 255 };
1511
1512        assert_eq!(handler.attr, Some(Attr::Foreground(Color::Spec(spec))));
1513    }
1514
1515    #[test]
1517    fn parse_zsh_startup() {
1518        static BYTES: &[u8] = &[
1519            0x1b, b'[', b'1', b'm', 0x1b, b'[', b'7', b'm', b'%', 0x1b, b'[', b'2', b'7', b'm',
1520            0x1b, b'[', b'1', b'm', 0x1b, b'[', b'0', b'm', b' ', b' ', b' ', b' ', b' ', b' ',
1521            b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ',
1522            b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ',
1523            b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ',
1524            b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ',
1525            b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ', b' ',
1526            b' ', b' ', b' ', b'\r', b' ', b'\r', b'\r', 0x1b, b'[', b'0', b'm', 0x1b, b'[', b'2',
1527            b'7', b'm', 0x1b, b'[', b'2', b'4', b'm', 0x1b, b'[', b'J', b'j', b'w', b'i', b'l',
1528            b'm', b'@', b'j', b'w', b'i', b'l', b'm', b'-', b'd', b'e', b's', b'k', b' ', 0x1b,
1529            b'[', b'0', b'1', b';', b'3', b'2', b'm', 0xe2, 0x9e, 0x9c, b' ', 0x1b, b'[', b'0',
1530            b'1', b';', b'3', b'2', b'm', b' ', 0x1b, b'[', b'3', b'6', b'm', b'~', b'/', b'c',
1531            b'o', b'd', b'e',
1532        ];
1533
1534        let mut handler = MockHandler::default();
1535        let mut parser = Processor::new();
1536
1537        for byte in &BYTES[..] {
1538            parser.advance(&mut handler, *byte, &mut io::sink());
1539        }
1540    }
1541
1542    #[test]
1543    fn parse_designate_g0_as_line_drawing() {
1544        static BYTES: &[u8] = &[0x1b, b'(', b'0'];
1545        let mut parser = Processor::new();
1546        let mut handler = MockHandler::default();
1547
1548        for byte in &BYTES[..] {
1549            parser.advance(&mut handler, *byte, &mut io::sink());
1550        }
1551
1552        assert_eq!(handler.index, CharsetIndex::G0);
1553        assert_eq!(handler.charset, StandardCharset::SpecialCharacterAndLineDrawing);
1554    }
1555
1556    #[test]
1557    fn parse_designate_g1_as_line_drawing_and_invoke() {
1558        static BYTES: &[u8] = &[0x1b, b')', b'0', 0x0e];
1559        let mut parser = Processor::new();
1560        let mut handler = MockHandler::default();
1561
1562        for byte in &BYTES[..3] {
1563            parser.advance(&mut handler, *byte, &mut io::sink());
1564        }
1565
1566        assert_eq!(handler.index, CharsetIndex::G1);
1567        assert_eq!(handler.charset, StandardCharset::SpecialCharacterAndLineDrawing);
1568
1569        let mut handler = MockHandler::default();
1570        parser.advance(&mut handler, BYTES[3], &mut io::sink());
1571
1572        assert_eq!(handler.index, CharsetIndex::G1);
1573    }
1574
1575    #[test]
1576    fn parse_valid_rgb_colors() {
1577        assert_eq!(xparse_color(b"rgb:f/e/d"), Some(Rgb { r: 0xff, g: 0xee, b: 0xdd }));
1578        assert_eq!(xparse_color(b"rgb:11/aa/ff"), Some(Rgb { r: 0x11, g: 0xaa, b: 0xff }));
1579        assert_eq!(xparse_color(b"rgb:f/ed1/cb23"), Some(Rgb { r: 0xff, g: 0xec, b: 0xca }));
1580        assert_eq!(xparse_color(b"rgb:ffff/0/0"), Some(Rgb { r: 0xff, g: 0x0, b: 0x0 }));
1581    }
1582
1583    #[test]
1584    fn parse_valid_legacy_rgb_colors() {
1585        assert_eq!(xparse_color(b"#1af"), Some(Rgb { r: 0x10, g: 0xa0, b: 0xf0 }));
1586        assert_eq!(xparse_color(b"#11aaff"), Some(Rgb { r: 0x11, g: 0xaa, b: 0xff }));
1587        assert_eq!(xparse_color(b"#110aa0ff0"), Some(Rgb { r: 0x11, g: 0xaa, b: 0xff }));
1588        assert_eq!(xparse_color(b"#1100aa00ff00"), Some(Rgb { r: 0x11, g: 0xaa, b: 0xff }));
1589    }
1590
1591    #[test]
1592    fn parse_invalid_rgb_colors() {
1593        assert_eq!(xparse_color(b"rgb:0//"), None);
1594        assert_eq!(xparse_color(b"rgb://///"), None);
1595    }
1596
1597    #[test]
1598    fn parse_invalid_legacy_rgb_colors() {
1599        assert_eq!(xparse_color(b"#"), None);
1600        assert_eq!(xparse_color(b"#f"), None);
1601    }
1602
1603    #[test]
1604    fn parse_invalid_number() {
1605        assert_eq!(parse_number(b"1abc"), None);
1606    }
1607
1608    #[test]
1609    fn parse_valid_number() {
1610        assert_eq!(parse_number(b"123"), Some(123));
1611    }
1612
1613    #[test]
1614    fn parse_number_too_large() {
1615        assert_eq!(parse_number(b"321"), None);
1616    }
1617}