vt100/
parser.rs

1use std::sync::{Arc, Mutex};
2
3use crate::TermReplySender;
4
5/// A parser for terminal output which produces an in-memory representation of
6/// the terminal contents.
7pub struct Parser<Reply: TermReplySender + Clone> {
8  parser: Arc<Mutex<termwiz::escape::parser::Parser>>,
9  screen: crate::screen::Screen<Reply>,
10}
11
12impl<Reply: TermReplySender + Clone> Parser<Reply> {
13  /// Creates a new terminal parser of the given size and with the given
14  /// amount of scrollback.
15  #[must_use]
16  pub fn new(
17    rows: u16,
18    cols: u16,
19    scrollback_len: usize,
20    reply_sender: Reply,
21  ) -> Self {
22    let parser = Arc::new(Mutex::new(termwiz::escape::parser::Parser::new()));
23    Self {
24      parser,
25      screen: crate::screen::Screen::new(
26        crate::grid::Size { rows, cols },
27        scrollback_len,
28        reply_sender,
29      ),
30    }
31  }
32
33  /// Processes the contents of the given byte string, and updates the
34  /// in-memory terminal state.
35  pub fn process(&mut self, bytes: &[u8]) {
36    self.parser.lock().unwrap().parse(bytes, |action| {
37      self.screen.handle_action(action);
38    });
39  }
40
41  /// Resizes the terminal.
42  pub fn set_size(&mut self, rows: u16, cols: u16) {
43    self.screen.set_size(rows, cols);
44  }
45
46  /// Scrolls to the given position in the scrollback.
47  ///
48  /// This position indicates the offset from the top of the screen, and
49  /// should be `0` to put the normal screen in view.
50  ///
51  /// This affects the return values of methods called on `parser.screen()`:
52  /// for instance, `parser.screen().cell(0, 0)` will return the top left
53  /// corner of the screen after taking the scrollback offset into account.
54  /// It does not affect `parser.process()` at all.
55  ///
56  /// The value given will be clamped to the actual size of the scrollback.
57  pub fn set_scrollback(&mut self, rows: usize) {
58    self.screen.set_scrollback(rows);
59  }
60
61  /// Returns a reference to a `Screen` object containing the terminal
62  /// state.
63  #[must_use]
64  pub fn screen(&self) -> &crate::screen::Screen<Reply> {
65    &self.screen
66  }
67}
68
69impl<Reply: TermReplySender + Clone> std::io::Write for Parser<Reply> {
70  fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
71    self.process(buf);
72    Ok(buf.len())
73  }
74
75  fn flush(&mut self) -> std::io::Result<()> {
76    Ok(())
77  }
78}