tui_lib/tui_io/
input_parser.rs

1use crate::tui_events::TuiEvents;
2
3use super::input_interface::InputInterfaceT;
4
5pub trait ParseInput: InputInterfaceT {
6    fn parse_input(&self, input_char: char) -> TuiEvents {
7        match input_char {
8            '\x1b' => {
9                return self.handle_escape_input_s1();
10            }
11            '\x7F' => {
12                return TuiEvents::Backspace;
13            }
14            '\n' | '\r' => {
15                return TuiEvents::Enter;
16            }
17            ' ' => {
18                return TuiEvents::Space;
19            }
20            '\t' => {
21                return TuiEvents::Tab;
22            }
23            _ => match input_char as u32 {
24                0x20..=0x7D => return TuiEvents::AsciiReadable(input_char),
25                0 => TuiEvents::Ignore,
26                1..=26 => return TuiEvents::Control((input_char as u8 + 0x40) as char),
27                _ => return TuiEvents::Other(input_char),
28            },
29        }
30    }
31    fn handle_escape_input_s1(&self) -> TuiEvents {
32        let input_char_option: Option<char> = self.read_raw_immediate();
33        let result = match input_char_option {
34            None => TuiEvents::Escape,
35            Some('[') => self.handle_escape_input_s2(),
36            Some(_) => TuiEvents::Error,
37        };
38        match result {
39            TuiEvents::Error | TuiEvents::Ignore => loop {
40                if let None = self.read_raw_immediate() {
41                    return result;
42                };
43            },
44            _ => return result,
45        }
46    }
47
48    fn handle_escape_input_s2(&self) -> TuiEvents {
49        let input_char = self.read_raw_immediate();
50        return match input_char {
51            Some('A') => TuiEvents::UpArrow,
52            Some('B') => TuiEvents::DownArrow,
53            Some('C') => TuiEvents::RightArrow,
54            Some('D') => TuiEvents::LeftArrow,
55            Some('3') => {
56                if let Some('~') = self.read_raw_immediate() {
57                    return TuiEvents::Delete;
58                }
59                TuiEvents::Error
60            }
61            Some('<') => self.handle_mouse_events(),
62            Some(_) | None => TuiEvents::Error,
63        };
64    }
65    fn handle_mouse_events(&self) -> TuiEvents {
66        return match self.read_raw_immediate() {
67            Some('0') => match self.get_coordinates() {
68                Some((coordinates, 'M')) => TuiEvents::LeftClick(coordinates),
69                Some((_, 'm')) => TuiEvents::Ignore,
70                None | Some(_) => TuiEvents::Error,
71            },
72            Some('1') => match self.get_coordinates() {
73                Some((coordinates, 'M')) => TuiEvents::MiddleClick(coordinates),
74                Some((_, 'm')) => TuiEvents::Ignore,
75                None | Some(_) => TuiEvents::Error,
76            },
77            Some('2') => match self.get_coordinates() {
78                Some((coordinates, 'M')) => TuiEvents::RightClick(coordinates),
79                Some((_, 'm')) => TuiEvents::Ignore,
80                None | Some(_) => TuiEvents::Error,
81            },
82            Some('3') => self.handle_mouse_move_event(),
83            Some('6') => self.handle_scroll_event(),
84            None | Some(_) => return TuiEvents::Error,
85        };
86    }
87
88    fn handle_mouse_move_event(&self) -> TuiEvents {
89        return match self.read_raw_immediate() {
90            Some('2') => match self.get_coordinates() {
91                Some((coordinates, 'M')) => TuiEvents::LeftDrag(coordinates),
92                Some(_) | None => TuiEvents::Error,
93            },
94            Some('3') => match self.get_coordinates() {
95                Some((coordinates, 'M')) => TuiEvents::MiddleDrag(coordinates),
96                Some(_) | None => TuiEvents::Error,
97            },
98            Some('4') => match self.get_coordinates() {
99                Some((coordinates, 'M')) => TuiEvents::RightDrag(coordinates),
100                Some(_) | None => TuiEvents::Error,
101            },
102            Some('5') => match self.get_coordinates() {
103                Some((coordinates, 'm')) => TuiEvents::MouseMove(coordinates),
104                Some(_) | None => TuiEvents::Error,
105            },
106            None | Some(_) => TuiEvents::Error,
107        };
108    }
109
110    fn handle_scroll_event(&self) -> TuiEvents {
111        return match self.read_raw_immediate() {
112            Some('4') => match self.get_coordinates() {
113                Some((coordinates, 'M')) => TuiEvents::ScrollUp(coordinates),
114                None | Some(_) => TuiEvents::Error,
115            },
116            Some('5') => match self.get_coordinates() {
117                Some((coordinates, 'M')) => TuiEvents::ScrollDown(coordinates),
118                None | Some(_) => TuiEvents::Error,
119            },
120            None | Some(_) => TuiEvents::Error,
121        };
122    }
123
124    fn get_u16(&self) -> Option<(u16, char)> {
125        let mut num = 0;
126        loop {
127            let next = self.read_raw_immediate()?;
128            match next as u16 {
129                0x30..=0x39 => {
130                    let digit = next as u16 - 0x30;
131                    if num > u16::MAX {
132                        return None;
133                    }
134                    num *= 10;
135                    if digit > u16::MAX - num {
136                        return None;
137                    }
138                    num += digit;
139                }
140                _ => return Some((num, next)),
141            }
142        }
143    }
144
145    fn get_coordinates(&self) -> Option<((u16, u16), char)> {
146        let Some(';') = self.read_raw_immediate() else {
147            return None;
148        };
149        let Some((x, ';')) = self.get_u16() else {
150            return None;
151        };
152        return match self.get_u16() {
153            Some((y, c)) => Some(((x, y), c)),
154            None => None,
155        };
156    }
157}