1mod cell;
9mod colour;
10mod commands;
11mod csi_helpers;
12mod dispatch;
13mod params;
14mod sgr;
15mod states;
16mod tables;
17#[cfg(test)]
18mod tests;
19mod writer;
20
21pub use cell::{CellState, GridAttr, SavedState};
22pub use colour::{
23 colour_join_rgb, Colour, COLOUR_DEFAULT, COLOUR_FLAG_256, COLOUR_FLAG_RGB, COLOUR_NONE,
24 COLOUR_TERMINAL,
25};
26pub use dispatch::{CsiCommand, DcsPayload, EscCommand, InputAction, OscCommand, ScreenWriter};
27pub use params::{InputParam, ParamType};
28pub use states::InputState;
29
30use params::ParamList;
31use states::Transition;
32
33const PARAM_LIST_MAX: usize = 24;
35
36const INTERM_BUF_MAX: usize = 4;
38
39const INPUT_BUF_START: usize = 32;
41
42const INPUT_BUF_MAX: usize = 1_048_576;
44
45const PARAM_BUF_MAX: usize = 64;
47
48const INPUT_DISCARD: u32 = 0x1;
50const INPUT_LAST: u32 = 0x2;
52
53pub mod mode {
55 pub const MODE_CURSOR: u32 = 0x1;
57 pub const MODE_INSERT: u32 = 0x2;
59 pub const MODE_KCURSOR: u32 = 0x4;
61 pub const MODE_KKEYPAD: u32 = 0x8;
63 pub const MODE_WRAP: u32 = 0x10;
65 pub const MODE_MOUSE_STANDARD: u32 = 0x20;
67 pub const MODE_MOUSE_BUTTON: u32 = 0x40;
69 pub const MODE_CURSOR_BLINKING: u32 = 0x80;
71 pub const MODE_MOUSE_UTF8: u32 = 0x100;
73 pub const MODE_MOUSE_SGR: u32 = 0x200;
75 pub const MODE_BRACKETPASTE: u32 = 0x400;
77 pub const MODE_FOCUSON: u32 = 0x800;
79 pub const MODE_MOUSE_ALL: u32 = 0x1000;
81 pub const MODE_ORIGIN: u32 = 0x2000;
83 pub const MODE_CRLF: u32 = 0x4000;
85 pub const MODE_KEYS_EXTENDED: u32 = 0x8000;
87 pub const MODE_CURSOR_VERY_VISIBLE: u32 = 0x1_0000;
89 pub const MODE_CURSOR_BLINKING_SET: u32 = 0x2_0000;
91 pub const MODE_KEYS_EXTENDED_2: u32 = 0x4_0000;
93 pub const MODE_THEME_UPDATES: u32 = 0x8_0000;
95 pub const MODE_SYNC: u32 = 0x10_0000;
97
98 pub const ALL_MOUSE_MODES: u32 = MODE_MOUSE_STANDARD | MODE_MOUSE_BUTTON | MODE_MOUSE_ALL;
100 pub const EXTENDED_KEY_MODES: u32 = MODE_KEYS_EXTENDED | MODE_KEYS_EXTENDED_2;
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq)]
106pub enum InputEndType {
107 St,
109 Bel,
111}
112
113pub struct InputParser {
115 state: InputState,
117 flags: u32,
119
120 ch: u8,
122
123 interm_buf: [u8; INTERM_BUF_MAX],
125 interm_len: usize,
126
127 param_buf: [u8; PARAM_BUF_MAX],
129 param_len: usize,
130
131 input_buf: Vec<u8>,
133 input_end: InputEndType,
135
136 param_list: ParamList,
138
139 cell: CellState,
141 saved: SavedState,
143
144 utf8_buf: [u8; 4],
146 utf8_len: u8,
147 utf8_expected: u8,
148 utf8_started: bool,
149
150 last_char: Option<char>,
152
153 since_ground: Vec<u8>,
155
156 ground_timer_active: bool,
159
160 reply_buf: Vec<u8>,
162}
163
164impl InputParser {
165 #[must_use]
167 pub fn new() -> Self {
168 Self {
169 state: InputState::Ground,
170 flags: 0,
171 ch: 0,
172 interm_buf: [0; INTERM_BUF_MAX],
173 interm_len: 0,
174 param_buf: [0; PARAM_BUF_MAX],
175 param_len: 0,
176 input_buf: Vec::with_capacity(INPUT_BUF_START),
177 input_end: InputEndType::St,
178 param_list: ParamList::new(),
179 cell: CellState::default(),
180 saved: SavedState::default(),
181 utf8_buf: [0; 4],
182 utf8_len: 0,
183 utf8_expected: 0,
184 utf8_started: false,
185 last_char: None,
186 since_ground: Vec::new(),
187 ground_timer_active: false,
188 reply_buf: Vec::new(),
189 }
190 }
191
192 #[must_use]
194 pub fn state(&self) -> InputState {
195 self.state
196 }
197
198 pub fn take_replies(&mut self) -> Vec<u8> {
200 std::mem::take(&mut self.reply_buf)
201 }
202
203 pub fn take_since_ground(&mut self) -> Vec<u8> {
205 std::mem::take(&mut self.since_ground)
206 }
207
208 #[must_use]
210 pub fn pending_bytes(&self) -> Vec<u8> {
211 if self.state != InputState::Ground {
212 return self.since_ground.clone();
213 }
214 if self.utf8_started {
215 return self.utf8_buf[..usize::from(self.utf8_len)].to_vec();
216 }
217 Vec::new()
218 }
219
220 #[must_use]
222 pub fn ground_timer_active(&self) -> bool {
223 self.ground_timer_active
224 }
225
226 pub fn ground_timer_expired(&mut self) {
228 self.reset_to_ground();
229 }
230
231 pub fn reset_to_ground(&mut self) {
233 self.clear();
234 self.state = InputState::Ground;
235 self.flags = 0;
236 self.enter_ground();
237 }
238
239 #[must_use]
241 pub fn cell_state(&self) -> &CellState {
242 &self.cell
243 }
244
245 pub fn parse(&mut self, buf: &[u8], writer: &mut dyn ScreenWriter) {
247 for &byte in buf {
248 self.ch = byte;
249 let transition = self.find_transition();
250 self.execute_transition(transition, writer);
251 }
252 }
253
254 fn find_transition(&self) -> Transition {
255 let table = self.state.transition_table();
256 for entry in table {
257 if self.ch >= entry.first && self.ch <= entry.last {
258 return Transition {
259 handler: entry.handler,
260 next_state: entry.next_state,
261 };
262 }
263 }
264 Transition {
266 handler: states::Handler::None,
267 next_state: None,
268 }
269 }
270
271 fn execute_transition(&mut self, trans: Transition, writer: &mut dyn ScreenWriter) {
272 if !matches!(
274 trans.handler,
275 states::Handler::Print | states::Handler::TopBitSet
276 ) {
277 writer.collect_end();
278 }
279
280 let skip_state = match trans.handler {
282 states::Handler::None => false,
283 states::Handler::Print => self.handle_print(writer),
284 states::Handler::C0Dispatch => self.handle_c0_dispatch(writer),
285 states::Handler::EscDispatch => self.handle_esc_dispatch(writer),
286 states::Handler::CsiDispatch => self.handle_csi_dispatch(writer),
287 states::Handler::DcsDispatch => self.handle_dcs_dispatch(writer),
288 states::Handler::Intermediate => self.handle_intermediate(),
289 states::Handler::Parameter => self.handle_parameter(),
290 states::Handler::Input => self.handle_input(),
291 states::Handler::TopBitSet => self.handle_top_bit_set(writer),
292 states::Handler::EndBel => self.handle_end_bel(),
293 };
294
295 if skip_state {
296 return;
297 }
298
299 if let Some(next) = trans.next_state {
300 self.set_state(next, writer);
301 }
302
303 if self.state != InputState::Ground {
305 self.since_ground.push(self.ch);
306 }
307 }
308
309 fn set_state(&mut self, next: InputState, writer: &mut dyn ScreenWriter) {
310 self.exit_state(writer);
312 self.state = next;
313 self.enter_state(writer);
315 }
316
317 fn enter_state(&mut self, writer: &mut dyn ScreenWriter) {
318 match self.state {
319 InputState::Ground => self.enter_ground(),
320 InputState::EscEnter => self.clear(),
321 InputState::CsiEnter => self.clear(),
322 InputState::DcsEnter => self.enter_dcs(),
323 InputState::OscString => self.enter_osc(),
324 InputState::ApcString => self.enter_apc(),
325 InputState::RenameString => self.enter_rename(),
326 InputState::ConsumeSt => self.enter_rename(), _ => {}
328 }
329 let _ = writer; }
331
332 fn exit_state(&mut self, writer: &mut dyn ScreenWriter) {
333 match self.state {
334 InputState::OscString => self.exit_osc(writer),
335 InputState::ApcString => self.exit_apc(writer),
336 InputState::RenameString => self.exit_rename(writer),
337 _ => {}
338 }
339 }
340
341 fn clear(&mut self) {
342 self.ground_timer_active = false;
343 self.interm_buf = [0; INTERM_BUF_MAX];
344 self.interm_len = 0;
345 self.param_buf = [0; PARAM_BUF_MAX];
346 self.param_len = 0;
347 self.input_buf.clear();
348 self.input_end = InputEndType::St;
349 self.flags &= !INPUT_DISCARD;
350 }
351
352 fn enter_ground(&mut self) {
353 self.ground_timer_active = false;
354 self.since_ground.clear();
355 if self.input_buf.capacity() > INPUT_BUF_START {
357 self.input_buf = Vec::with_capacity(INPUT_BUF_START);
358 }
359 }
360
361 fn enter_dcs(&mut self) {
362 self.clear();
363 self.ground_timer_active = true;
364 self.flags &= !INPUT_LAST;
365 }
366
367 fn enter_osc(&mut self) {
368 self.clear();
369 self.ground_timer_active = true;
370 self.flags &= !INPUT_LAST;
371 }
372
373 fn enter_apc(&mut self) {
374 self.clear();
375 self.ground_timer_active = true;
376 self.flags &= !INPUT_LAST;
377 }
378
379 fn enter_rename(&mut self) {
380 self.clear();
381 self.ground_timer_active = true;
382 self.flags &= !INPUT_LAST;
383 }
384
385 fn exit_osc(&mut self, writer: &mut dyn ScreenWriter) {
386 if self.flags & INPUT_DISCARD != 0 {
387 return;
388 }
389 dispatch::dispatch_osc(self, writer);
390 }
391
392 fn exit_apc(&mut self, writer: &mut dyn ScreenWriter) {
393 if self.flags & INPUT_DISCARD != 0 {
394 return;
395 }
396 let buf = String::from_utf8_lossy(&self.input_buf).into_owned();
397 writer.set_title(&buf);
398 }
399
400 fn exit_rename(&mut self, writer: &mut dyn ScreenWriter) {
401 if self.flags & INPUT_DISCARD != 0 {
402 return;
403 }
404 let buf = String::from_utf8_lossy(&self.input_buf).into_owned();
405 writer.set_window_name(&buf);
406 }
407
408 fn stop_utf8(&mut self, writer: &mut dyn ScreenWriter) {
410 if self.utf8_started {
411 writer.collect_add('\u{FFFD}', &self.cell);
412 self.utf8_started = false;
413 self.utf8_len = 0;
414 self.utf8_expected = 0;
415 }
416 }
417
418 fn handle_print(&mut self, writer: &mut dyn ScreenWriter) -> bool {
419 self.stop_utf8(writer);
420
421 let ch = self.ch as char;
422 let set = if self.cell.set == 0 {
423 self.cell.g0set
424 } else {
425 self.cell.g1set
426 };
427
428 writer.collect_add_with_charset(ch, &self.cell, set != 0);
429
430 self.last_char = Some(ch);
431 self.flags |= INPUT_LAST;
432
433 false
434 }
435
436 fn handle_intermediate(&mut self) -> bool {
437 if self.interm_len >= INTERM_BUF_MAX - 1 {
438 self.flags |= INPUT_DISCARD;
439 } else {
440 self.interm_buf[self.interm_len] = self.ch;
441 self.interm_len += 1;
442 }
443 false
444 }
445
446 fn handle_parameter(&mut self) -> bool {
447 if self.param_len >= PARAM_BUF_MAX - 1 {
448 self.flags |= INPUT_DISCARD;
449 } else {
450 self.param_buf[self.param_len] = self.ch;
451 self.param_len += 1;
452 }
453 false
454 }
455
456 fn handle_input(&mut self) -> bool {
457 if self.input_buf.len() + 1 >= INPUT_BUF_MAX {
458 self.flags |= INPUT_DISCARD;
459 } else {
460 self.input_buf.push(self.ch);
461 }
462 false
463 }
464
465 fn handle_end_bel(&mut self) -> bool {
466 self.input_end = InputEndType::Bel;
467 false
468 }
469
470 fn handle_c0_dispatch(&mut self, writer: &mut dyn ScreenWriter) -> bool {
471 self.stop_utf8(writer);
472 dispatch::dispatch_c0(self, writer);
473 self.flags &= !INPUT_LAST;
474 false
475 }
476
477 fn handle_esc_dispatch(&mut self, writer: &mut dyn ScreenWriter) -> bool {
478 if self.flags & INPUT_DISCARD != 0 {
479 return false;
480 }
481 dispatch::dispatch_esc(self, writer);
482 self.flags &= !INPUT_LAST;
483 false
484 }
485
486 fn handle_csi_dispatch(&mut self, writer: &mut dyn ScreenWriter) -> bool {
487 if self.flags & INPUT_DISCARD != 0 {
488 return false;
489 }
490 dispatch::dispatch_csi(self, writer);
491 self.flags &= !INPUT_LAST;
492 false
493 }
494
495 fn handle_dcs_dispatch(&mut self, writer: &mut dyn ScreenWriter) -> bool {
496 if self.flags & INPUT_DISCARD != 0 {
497 return false;
498 }
499 dispatch::dispatch_dcs(self, writer);
500 false
501 }
502
503 fn handle_top_bit_set(&mut self, writer: &mut dyn ScreenWriter) -> bool {
504 self.flags &= !INPUT_LAST;
505
506 if !self.utf8_started {
507 self.utf8_started = true;
508 self.utf8_len = 0;
509 let expected = if self.ch & 0xE0 == 0xC0 {
511 2
512 } else if self.ch & 0xF0 == 0xE0 {
513 3
514 } else if self.ch & 0xF8 == 0xF0 {
515 4
516 } else {
517 self.stop_utf8(writer);
519 return false;
520 };
521 self.utf8_expected = expected;
522 self.utf8_buf[0] = self.ch;
523 self.utf8_len = 1;
524 return false;
525 }
526
527 if self.ch & 0xC0 != 0x80 {
529 self.stop_utf8(writer);
531 if self.ch >= 0x80 {
533 return self.handle_top_bit_set(writer);
534 }
535 return false;
536 }
537
538 self.utf8_buf[self.utf8_len as usize] = self.ch;
539 self.utf8_len += 1;
540
541 if self.utf8_len < self.utf8_expected {
542 return false; }
544
545 self.utf8_started = false;
547 let bytes = &self.utf8_buf[..self.utf8_len as usize];
548 let s = match std::str::from_utf8(bytes) {
549 Ok(s) => s,
550 Err(_) => {
551 writer.collect_add('\u{FFFD}', &self.cell);
552 return false;
553 }
554 };
555 let c = match s.chars().next() {
556 Some(c) => c,
557 None => {
558 writer.collect_add('\u{FFFD}', &self.cell);
559 return false;
560 }
561 };
562
563 writer.collect_add(c, &self.cell);
564
565 self.last_char = Some(c);
566 self.flags |= INPUT_LAST;
567
568 false
569 }
570
571 fn reply(&mut self, s: &str) {
573 self.reply_buf.extend_from_slice(s.as_bytes());
574 }
575
576 fn interm_str(&self) -> &[u8] {
578 &self.interm_buf[..self.interm_len]
579 }
580}
581
582impl Default for InputParser {
583 fn default() -> Self {
584 Self::new()
585 }
586}