aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2023-03-08 22:31:00 -0500
committerJesse Luehrs <doy@tozt.net>2023-03-09 00:27:25 -0500
commita705c1f07de2b8ec3ba4fe46377242f151b996c1 (patch)
treefcd415ca7390aa47b4c7af56948506fc15571fdf /src
parent939fd8bed87dd67de9d0e00ba151ef637ef1c16a (diff)
downloadvt100-rust-a705c1f07de2b8ec3ba4fe46377242f151b996c1.tar.gz
vt100-rust-a705c1f07de2b8ec3ba4fe46377242f151b996c1.zip
use callbacks for events rather than tracking counters
Diffstat (limited to 'src')
-rw-r--r--src/callbacks.rs13
-rw-r--r--src/lib.rs3
-rw-r--r--src/parser.rs14
-rw-r--r--src/screen.rs92
-rw-r--r--src/state.rs61
-rw-r--r--src/term.rs20
6 files changed, 95 insertions, 108 deletions
diff --git a/src/callbacks.rs b/src/callbacks.rs
new file mode 100644
index 0000000..256eb58
--- /dev/null
+++ b/src/callbacks.rs
@@ -0,0 +1,13 @@
+/// This trait is used with `Parser::process_cb` to handle extra escape
+/// sequences that don't have an impact on the terminal screen directly.
+pub trait Callbacks {
+ /// This callback is called when the terminal requests an audible bell
+ /// (typically with `^G`).
+ fn audible_bell(&mut self, _: &mut crate::Screen) {}
+ /// This callback is called when the terminal requests an visual bell
+ /// (typically with `\eg`).
+ fn visual_bell(&mut self, _: &mut crate::Screen) {}
+ /// This callback is called when the terminal receives invalid input
+ /// (such as an invalid UTF-8 character or an used control character).
+ fn error(&mut self, _: &mut crate::Screen) {}
+}
diff --git a/src/lib.rs b/src/lib.rs
index ddea0cd..92256f2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -47,14 +47,17 @@
#![allow(clippy::type_complexity)]
mod attrs;
+mod callbacks;
mod cell;
mod grid;
mod parser;
mod row;
mod screen;
+mod state;
mod term;
pub use attrs::Color;
+pub use callbacks::Callbacks;
pub use cell::Cell;
pub use parser::Parser;
pub use screen::{MouseProtocolEncoding, MouseProtocolMode, Screen};
diff --git a/src/parser.rs b/src/parser.rs
index 01ba019..10ebf10 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -27,6 +27,20 @@ impl Parser {
}
}
+ /// Processes the contents of the given byte string, and updates the
+ /// in-memory terminal state. Calls methods on the given `Callbacks`
+ /// object when relevant escape sequences are seen.
+ pub fn process_cb(
+ &mut self,
+ bytes: &[u8],
+ callbacks: &mut impl crate::callbacks::Callbacks,
+ ) {
+ let mut state = crate::state::State::new(&mut self.screen, callbacks);
+ for byte in bytes {
+ self.parser.advance(&mut state, *byte);
+ }
+ }
+
/// Returns a reference to a `Screen` object containing the terminal
/// state.
#[must_use]
diff --git a/src/screen.rs b/src/screen.rs
index fe4e5cc..9da62c7 100644
--- a/src/screen.rs
+++ b/src/screen.rs
@@ -75,11 +75,6 @@ pub struct Screen {
modes: u8,
mouse_protocol_mode: MouseProtocolMode,
mouse_protocol_encoding: MouseProtocolEncoding,
-
- audible_bell_count: usize,
- visual_bell_count: usize,
-
- errors: usize,
}
impl Screen {
@@ -102,11 +97,6 @@ impl Screen {
modes: 0,
mouse_protocol_mode: MouseProtocolMode::default(),
mouse_protocol_encoding: MouseProtocolEncoding::default(),
-
- audible_bell_count: 0,
- visual_bell_count: 0,
-
- errors: 0,
}
}
@@ -256,15 +246,13 @@ impl Screen {
/// Return escape codes sufficient to turn the terminal state of the
/// screen `prev` into the current terminal state. This is a convenience
- /// wrapper around `contents_diff`, `input_mode_diff`, `title_diff`, and
- /// `bells_diff`.
+ /// wrapper around `contents_diff`, `input_mode_diff`, and `title_diff`
#[must_use]
pub fn state_diff(&self, prev: &Self) -> Vec<u8> {
let mut contents = vec![];
self.write_contents_diff(&mut contents, prev);
self.write_input_mode_diff(&mut contents, prev);
self.write_title_diff(&mut contents, prev);
- self.write_bells_diff(&mut contents, prev);
contents
}
@@ -511,25 +499,6 @@ impl Screen {
.write_buf(contents);
}
- /// Returns terminal escape sequences sufficient to cause audible and
- /// visual bells to occur if they have been received since the terminal
- /// described by `prev`.
- #[must_use]
- pub fn bells_diff(&self, prev: &Self) -> Vec<u8> {
- let mut contents = vec![];
- self.write_bells_diff(&mut contents, prev);
- contents
- }
-
- fn write_bells_diff(&self, contents: &mut Vec<u8>, prev: &Self) {
- if self.audible_bell_count != prev.audible_bell_count {
- crate::term::AudibleBell::default().write_buf(contents);
- }
- if self.visual_bell_count != prev.visual_bell_count {
- crate::term::VisualBell::default().write_buf(contents);
- }
- }
-
/// Returns terminal escape sequences sufficient to set the current
/// terminal's drawing attributes.
///
@@ -632,42 +601,6 @@ impl Screen {
&self.icon_name
}
- /// Returns a value which changes every time an audible bell is received.
- ///
- /// Typically you would store this number after each call to `process`,
- /// and trigger an audible bell whenever it changes.
- ///
- /// You shouldn't rely on the exact value returned here, since the exact
- /// value will not be maintained by `contents_formatted` or
- /// `contents_diff`.
- #[must_use]
- pub fn audible_bell_count(&self) -> usize {
- self.audible_bell_count
- }
-
- /// Returns a value which changes every time an visual bell is received.
- ///
- /// Typically you would store this number after each call to `process`,
- /// and trigger an visual bell whenever it changes.
- ///
- /// You shouldn't rely on the exact value returned here, since the exact
- /// value will not be maintained by `contents_formatted` or
- /// `contents_diff`.
- #[must_use]
- pub fn visual_bell_count(&self) -> usize {
- self.visual_bell_count
- }
-
- /// Returns the number of parsing errors seen so far.
- ///
- /// Currently this only tracks invalid UTF-8 and control characters other
- /// than `0x07`-`0x0f`. This can give an idea of whether the input stream
- /// being fed to the parser is reasonable or not.
- #[must_use]
- pub fn errors(&self) -> usize {
- self.errors
- }
-
/// Returns whether the alternate screen is currently in use.
#[must_use]
pub fn alternate_screen(&self) -> bool {
@@ -1061,10 +994,6 @@ impl Screen {
// control codes
- fn bel(&mut self) {
- self.audible_bell_count += 1;
- }
-
fn bs(&mut self) {
self.grid_mut().col_dec(1);
}
@@ -1120,22 +1049,11 @@ impl Screen {
fn ris(&mut self) {
let title = self.title.clone();
let icon_name = self.icon_name.clone();
- let audible_bell_count = self.audible_bell_count;
- let visual_bell_count = self.visual_bell_count;
- let errors = self.errors;
*self = Self::new(self.grid.size(), self.grid.scrollback_len());
self.title = title;
self.icon_name = icon_name;
- self.audible_bell_count = audible_bell_count;
- self.visual_bell_count = visual_bell_count;
- self.errors = errors;
- }
-
- // ESC g
- fn vb(&mut self) {
- self.visual_bell_count += 1;
}
// csi codes
@@ -1552,14 +1470,13 @@ impl Screen {
impl vte::Perform for Screen {
fn print(&mut self, c: char) {
if c == '\u{fffd}' || ('\u{80}'..'\u{a0}').contains(&c) {
- self.errors = self.errors.saturating_add(1);
+ log::debug!("unhandled text character: {c}");
}
self.text(c);
}
fn execute(&mut self, b: u8) {
match b {
- 7 => self.bel(),
8 => self.bs(),
9 => self.tab(),
10 => self.lf(),
@@ -1568,9 +1485,8 @@ impl vte::Perform for Screen {
13 => self.cr(),
// we don't implement shift in/out alternate character sets, but
// it shouldn't count as an "error"
- 14 | 15 => {}
+ 7 | 14 | 15 => {}
_ => {
- self.errors = self.errors.saturating_add(1);
log::debug!("unhandled control character: {b}");
}
}
@@ -1585,7 +1501,7 @@ impl vte::Perform for Screen {
b'>' => self.deckpnm(),
b'M' => self.ri(),
b'c' => self.ris(),
- b'g' => self.vb(),
+ b'g' => {}
_ => {
log::debug!("unhandled escape code: ESC {b}");
}
diff --git a/src/state.rs b/src/state.rs
new file mode 100644
index 0000000..c84fa2b
--- /dev/null
+++ b/src/state.rs
@@ -0,0 +1,61 @@
+pub struct State<'a, T: crate::callbacks::Callbacks> {
+ screen: &'a mut crate::Screen,
+ callbacks: &'a mut T,
+}
+
+impl<'a, T: crate::callbacks::Callbacks> State<'a, T> {
+ pub fn new(screen: &'a mut crate::Screen, callbacks: &'a mut T) -> Self {
+ Self { screen, callbacks }
+ }
+}
+
+impl<'a, T: crate::callbacks::Callbacks> vte::Perform for State<'a, T> {
+ fn print(&mut self, c: char) {
+ if c == '\u{fffd}' || ('\u{80}'..'\u{a0}').contains(&c) {
+ self.callbacks.error(self.screen);
+ }
+ self.screen.print(c);
+ }
+
+ fn execute(&mut self, b: u8) {
+ match b {
+ 7 => self.callbacks.audible_bell(self.screen),
+ 8..=15 => {}
+ _ => {
+ self.callbacks.error(self.screen);
+ }
+ }
+ self.screen.execute(b);
+ }
+
+ fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, b: u8) {
+ if intermediates.is_empty() && b == b'g' {
+ self.callbacks.visual_bell(self.screen);
+ }
+ self.screen.esc_dispatch(intermediates, ignore, b);
+ }
+
+ fn csi_dispatch(
+ &mut self,
+ params: &vte::Params,
+ intermediates: &[u8],
+ ignore: bool,
+ c: char,
+ ) {
+ self.screen.csi_dispatch(params, intermediates, ignore, c);
+ }
+
+ fn osc_dispatch(&mut self, params: &[&[u8]], bel_terminated: bool) {
+ self.screen.osc_dispatch(params, bel_terminated);
+ }
+
+ fn hook(
+ &mut self,
+ params: &vte::Params,
+ intermediates: &[u8],
+ ignore: bool,
+ action: char,
+ ) {
+ self.screen.hook(params, intermediates, ignore, action);
+ }
+}
diff --git a/src/term.rs b/src/term.rs
index ffa3ecb..99ca266 100644
--- a/src/term.rs
+++ b/src/term.rs
@@ -376,26 +376,6 @@ impl BufWrite for MoveFromTo {
}
}
-#[derive(Default, Debug)]
-#[must_use = "this struct does nothing unless you call write_buf"]
-pub struct AudibleBell;
-
-impl BufWrite for AudibleBell {
- fn write_buf(&self, buf: &mut Vec<u8>) {
- buf.push(b'\x07');
- }
-}
-
-#[derive(Default, Debug)]
-#[must_use = "this struct does nothing unless you call write_buf"]
-pub struct VisualBell;
-
-impl BufWrite for VisualBell {
- fn write_buf(&self, buf: &mut Vec<u8>) {
- buf.extend_from_slice(b"\x1bg");
- }
-}
-
#[must_use = "this struct does nothing unless you call write_buf"]
pub struct ChangeTitle<'a> {
icon_name: &'a str,