From 28eea9f6a837dad5febfe9b021b7070e96b286f9 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Tue, 12 Nov 2019 05:47:32 -0500 Subject: remove parser.screen_mut it's easier to reason about if you are only able to get an immutable reference to the internal screen. this also required changing the api for bells. --- CHANGELOG.md | 10 ++++++++ src/parser.rs | 26 +++++++++++++++----- src/screen.rs | 74 ++++++++++++++++++++------------------------------------ tests/basic.rs | 14 +++++------ tests/control.rs | 11 ++++++--- tests/escape.rs | 24 ++++++++++-------- tests/init.rs | 6 ++--- tests/scroll.rs | 20 +++++++-------- 8 files changed, 98 insertions(+), 87 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd0dc9f..c268b6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,9 +8,19 @@ * `Default` impl for `Parser` which creates an 80x24 terminal with no scrollback. +### Removed + +* `Parser::screen_mut` (and the `pub` `&mut self` methods on `Screen`). The few + things you can do to change the screen state directly are now exposed as + methods on `Parser` itself. + ### Changed * `Cell::contents` now returns a `String` instead of a `&str`. +* `Screen::check_audible_bell` and `Screen::check_visual_bell` have been + replaced with `Screen::audible_bell_count` and `Screen::visual_bell_count`. + You should keep track of the "since the last method call" state yourself + instead of having the screen track it for you. ### Fixed diff --git a/src/parser.rs b/src/parser.rs index 07ee7c9..613e18e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -26,17 +26,31 @@ impl Parser { } } + /// Resizes the terminal. + pub fn set_size(&mut self, rows: u16, cols: u16) { + self.screen.set_size(rows, cols); + } + + /// Scrolls to the given position in the scrollback. + /// + /// This position indicates the offset from the top of the screen, and + /// should be `0` to put the normal screen in view. + /// + /// This affects the return values of methods called on `parser.screen()`: + /// for instance, `parser.screen().cell(0, 0)` will return the top left + /// corner of the screen after taking the scrollback offset into account. + /// It does not affect `parser.process()` at all. + /// + /// The value given will be clamped to the actual size of the scrollback. + pub fn set_scrollback(&mut self, rows: usize) { + self.screen.set_scrollback(rows); + } + /// Returns a reference to a `Screen` object containing the terminal /// state. pub fn screen(&self) -> &crate::screen::Screen { &self.screen } - - /// Returns a mutable reference to a `Screen` object containing the - /// terminal state. - pub fn screen_mut(&mut self) -> &mut crate::screen::Screen { - &mut self.screen - } } impl Default for Parser { diff --git a/src/screen.rs b/src/screen.rs index 36a47c4..c2eaf0e 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -4,12 +4,6 @@ use unicode_width::UnicodeWidthChar as _; const DEFAULT_MULTI_PARAMS: &[i64] = &[0]; -#[derive(enumset::EnumSetType, Debug)] -enum Output { - AudibleBell, - VisualBell, -} - #[derive(enumset::EnumSetType, Debug)] enum Mode { ApplicationKeypad, @@ -84,10 +78,12 @@ pub struct Screen { title: String, icon_name: String, - outputs: enumset::EnumSet, modes: enumset::EnumSet, mouse_protocol_mode: MouseProtocolMode, mouse_protocol_encoding: MouseProtocolEncoding, + + audible_bell_count: usize, + visual_bell_count: usize, } impl Screen { @@ -105,15 +101,16 @@ impl Screen { title: String::default(), icon_name: String::default(), - outputs: enumset::EnumSet::default(), modes: enumset::EnumSet::default(), mouse_protocol_mode: MouseProtocolMode::default(), mouse_protocol_encoding: MouseProtocolEncoding::default(), + + audible_bell_count: 0, + visual_bell_count: 0, } } - /// Resizes the terminal. - pub fn set_size(&mut self, rows: u16, cols: u16) { + pub(crate) fn set_size(&mut self, rows: u16, cols: u16) { self.grid.set_size(crate::grid::Size { rows, cols }); self.alternate_grid .set_size(crate::grid::Size { rows, cols }); @@ -135,18 +132,7 @@ impl Screen { self.grid().scrollback() } - /// Scrolls to the given position in the scrollback. - /// - /// This position indicates the offset from the top of the screen, and - /// should be `0` to put the normal screen in view. - /// - /// This affects the return values of methods called on `parser.screen()`: - /// for instance, `parser.screen().cell(0, 0)` will return the top left - /// corner of the screen after taking the scrollback offset into account. - /// It does not affect `parser.process()` at all. - /// - /// The value given will be clamped to the actual size of the scrollback. - pub fn set_scrollback(&mut self, rows: usize) { + pub(crate) fn set_scrollback(&mut self, rows: usize) { self.grid_mut().set_scrollback(rows); } @@ -321,16 +307,20 @@ impl Screen { &self.icon_name } - /// Returns whether an audible bell has occurred since the last time this - /// method was called. - pub fn check_audible_bell(&mut self) -> bool { - self.check_output(Output::AudibleBell) + /// Returns the total number of audible bells seen so far. + /// + /// Typically you would store this number after each call to `process`, + /// and trigger an audible bell whenever it changes. + pub fn audible_bell_count(&self) -> usize { + self.audible_bell_count } - /// Returns whether an visual bell has occurred since the last time this - /// method was called. - pub fn check_visual_bell(&mut self) -> bool { - self.check_output(Output::VisualBell) + /// Returns the total number of visual bells seen so far. + /// + /// Typically you would store this number after each call to `process`, + /// and trigger an visual bell whenever it changes. + pub fn visual_bell_count(&self) -> usize { + self.visual_bell_count } /// Returns whether the terminal should be in application keypad mode. @@ -413,20 +403,6 @@ impl Screen { self.attrs = self.saved_attrs; } - fn set_output(&mut self, output: Output) { - self.outputs.insert(output); - } - - fn clear_output(&mut self, output: Output) { - self.outputs.remove(output); - } - - fn check_output(&mut self, output: Output) -> bool { - let ret = self.outputs.contains(output); - self.clear_output(output); - ret - } - fn set_mode(&mut self, mode: Mode) { self.modes.insert(mode); } @@ -523,7 +499,7 @@ impl Screen { // control codes fn bel(&mut self) { - self.set_output(Output::AudibleBell); + self.audible_bell_count += 1; } fn bs(&mut self) { @@ -579,20 +555,22 @@ impl Screen { // ESC c fn ris(&mut self) { - let outputs = self.outputs; 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; *self = Self::new(self.grid.size(), self.grid.scrollback_len()); - self.outputs = outputs; self.title = title; self.icon_name = icon_name; + self.audible_bell_count = audible_bell_count; + self.visual_bell_count = visual_bell_count; } // ESC g fn vb(&mut self) { - self.set_output(Output::VisualBell); + self.visual_bell_count += 1; } // csi codes diff --git a/tests/basic.rs b/tests/basic.rs index 0f2da75..33a272d 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -20,18 +20,18 @@ fn set_size() { assert_eq!(parser.screen().size(), (24, 80)); assert_eq!(parser.screen().cursor_position(), (0, 0)); - parser.screen_mut().set_size(34, 8); + parser.set_size(34, 8); assert_eq!(parser.screen().size(), (34, 8)); assert_eq!(parser.screen().cursor_position(), (0, 0)); parser.process(b"\x1b[30;5H"); assert_eq!(parser.screen().cursor_position(), (29, 4)); - parser.screen_mut().set_size(24, 80); + parser.set_size(24, 80); assert_eq!(parser.screen().size(), (24, 80)); assert_eq!(parser.screen().cursor_position(), (23, 4)); - parser.screen_mut().set_size(34, 8); + parser.set_size(34, 8); assert_eq!(parser.screen().size(), (34, 8)); assert_eq!(parser.screen().cursor_position(), (23, 4)); @@ -39,7 +39,7 @@ fn set_size() { assert_eq!(parser.screen().size(), (34, 8)); assert_eq!(parser.screen().cursor_position(), (0, 0)); - parser.screen_mut().set_size(24, 80); + parser.set_size(24, 80); assert_eq!(parser.screen().size(), (24, 80)); assert_eq!(parser.screen().cursor_position(), (0, 0)); @@ -47,14 +47,14 @@ fn set_size() { assert_eq!(parser.screen().size(), (24, 80)); assert_eq!(parser.screen().cursor_position(), (23, 4)); - parser.screen_mut().set_size(34, 8); + parser.set_size(34, 8); parser.process(b"\x1bc01234567890123456789"); assert_eq!(parser.screen().contents(), "01234567890123456789"); - parser.screen_mut().set_size(24, 80); + parser.set_size(24, 80); assert_eq!(parser.screen().contents(), "01234567\n89012345\n6789"); - parser.screen_mut().set_size(34, 8); + parser.set_size(34, 8); assert_eq!(parser.screen().contents(), "01234567\n89012345\n6789"); } diff --git a/tests/control.rs b/tests/control.rs index 9392b5e..aba6915 100644 --- a/tests/control.rs +++ b/tests/control.rs @@ -3,12 +3,17 @@ #[test] fn bel() { let mut parser = vt100::Parser::default(); + assert_eq!(parser.screen().audible_bell_count(), 0); - assert!(!parser.screen_mut().check_audible_bell()); + parser.process(b"\x07"); + assert_eq!(parser.screen().audible_bell_count(), 1); + assert_eq!(parser.screen().audible_bell_count(), 1); parser.process(b"\x07"); - assert!(parser.screen_mut().check_audible_bell()); - assert!(!parser.screen_mut().check_audible_bell()); + assert_eq!(parser.screen().audible_bell_count(), 2); + + parser.process(b"\x07\x07\x07"); + assert_eq!(parser.screen().audible_bell_count(), 5); } #[test] diff --git a/tests/escape.rs b/tests/escape.rs index 43eb666..e08a402 100644 --- a/tests/escape.rs +++ b/tests/escape.rs @@ -40,8 +40,8 @@ fn ris() { assert_eq!(parser.screen().title(), ""); assert_eq!(parser.screen().icon_name(), ""); - assert!(!parser.screen_mut().check_visual_bell()); - assert!(!parser.screen_mut().check_audible_bell()); + assert_eq!(parser.screen().audible_bell_count(), 0); + assert_eq!(parser.screen().visual_bell_count(), 0); assert!(!parser.screen().application_keypad()); assert!(!parser.screen().application_cursor()); assert!(!parser.screen().hide_cursor()); @@ -72,8 +72,8 @@ fn ris() { assert_eq!(parser.screen().title(), "window title"); assert_eq!(parser.screen().icon_name(), "window icon name"); - assert!(parser.screen_mut().check_visual_bell()); - assert!(parser.screen_mut().check_audible_bell()); + assert_eq!(parser.screen().audible_bell_count(), 1); + assert_eq!(parser.screen().visual_bell_count(), 1); assert!(parser.screen().application_keypad()); assert!(parser.screen().application_cursor()); assert!(parser.screen().hide_cursor()); @@ -87,7 +87,7 @@ fn ris() { vt100::MouseProtocolEncoding::Sgr ); - parser.process(b"\x07\x1bg\x1bc"); + parser.process(b"\x1bc"); assert_eq!(parser.screen().cursor_position(), (0, 0)); let cell = parser.screen().cell(0, 0).unwrap(); @@ -104,8 +104,8 @@ fn ris() { assert_eq!(parser.screen().icon_name(), "window icon name"); // bell states don't change with reset - assert!(parser.screen_mut().check_visual_bell()); - assert!(parser.screen_mut().check_audible_bell()); + assert_eq!(parser.screen().audible_bell_count(), 1); + assert_eq!(parser.screen().visual_bell_count(), 1); assert!(!parser.screen().application_keypad()); assert!(!parser.screen().application_cursor()); @@ -124,10 +124,14 @@ fn ris() { #[test] fn vb() { let mut parser = vt100::Parser::default(); - assert!(!parser.screen_mut().check_visual_bell()); + assert_eq!(parser.screen().visual_bell_count(), 0); parser.process(b"\x1bg"); - assert!(parser.screen_mut().check_visual_bell()); - assert!(!parser.screen_mut().check_visual_bell()); + assert_eq!(parser.screen().visual_bell_count(), 1); + assert_eq!(parser.screen().visual_bell_count(), 1); + parser.process(b"\x1bg"); + assert_eq!(parser.screen().visual_bell_count(), 2); + parser.process(b"\x1bg\x1bg\x1bg"); + assert_eq!(parser.screen().visual_bell_count(), 5); } #[test] diff --git a/tests/init.rs b/tests/init.rs index ccb1c70..4e0cd66 100644 --- a/tests/init.rs +++ b/tests/init.rs @@ -2,7 +2,7 @@ #[test] fn init() { - let mut parser = vt100::Parser::default(); + let parser = vt100::Parser::default(); assert_eq!(parser.screen().size(), (24, 80)); assert_eq!(parser.screen().cursor_position(), (0, 0)); @@ -24,8 +24,8 @@ fn init() { assert_eq!(parser.screen().title(), ""); assert_eq!(parser.screen().icon_name(), ""); - assert!(!parser.screen_mut().check_visual_bell()); - assert!(!parser.screen_mut().check_audible_bell()); + assert_eq!(parser.screen().audible_bell_count(), 0); + assert_eq!(parser.screen().visual_bell_count(), 0); assert!(!parser.screen().application_keypad()); assert!(!parser.screen().application_cursor()); assert!(!parser.screen().hide_cursor()); diff --git a/tests/scroll.rs b/tests/scroll.rs index 32b7488..2b1117e 100644 --- a/tests/scroll.rs +++ b/tests/scroll.rs @@ -82,31 +82,31 @@ fn scrollback() { parser.process(b"\r\n25\r\n26\r\n27\r\n28\r\n29\r\n30"); assert_eq!(parser.screen().contents(), "7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30"); - parser.screen_mut().set_scrollback(0); + parser.set_scrollback(0); assert_eq!(parser.screen().scrollback(), 0); assert_eq!(parser.screen().contents(), "7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30"); - parser.screen_mut().set_scrollback(1); + parser.set_scrollback(1); assert_eq!(parser.screen().scrollback(), 1); assert_eq!(parser.screen().contents(), "6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29"); - parser.screen_mut().set_scrollback(3); + parser.set_scrollback(3); assert_eq!(parser.screen().scrollback(), 3); assert_eq!(parser.screen().contents(), "4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27"); - parser.screen_mut().set_scrollback(6); + parser.set_scrollback(6); assert_eq!(parser.screen().scrollback(), 6); assert_eq!(parser.screen().contents(), "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24"); - parser.screen_mut().set_scrollback(7); + parser.set_scrollback(7); assert_eq!(parser.screen().scrollback(), 6); assert_eq!(parser.screen().contents(), "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24"); - parser.screen_mut().set_scrollback(0); + parser.set_scrollback(0); assert_eq!(parser.screen().scrollback(), 0); assert_eq!(parser.screen().contents(), "7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30"); - parser.screen_mut().set_scrollback(7); + parser.set_scrollback(7); assert_eq!(parser.screen().scrollback(), 6); assert_eq!(parser.screen().contents(), "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24"); @@ -134,11 +134,11 @@ fn scrollback() { assert_eq!(parser.screen().scrollback(), 10); assert_eq!(parser.screen().contents(), "3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26"); - parser.screen_mut().set_scrollback(12); + parser.set_scrollback(12); assert_eq!(parser.screen().scrollback(), 10); assert_eq!(parser.screen().contents(), "3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26"); - parser.screen_mut().set_scrollback(0); + parser.set_scrollback(0); assert_eq!(parser.screen().scrollback(), 0); assert_eq!(parser.screen().contents(), "13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n35\n36"); @@ -146,7 +146,7 @@ fn scrollback() { assert_eq!(parser.screen().scrollback(), 0); assert_eq!(parser.screen().contents(), "15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n35\n36\n37\n38"); - parser.screen_mut().set_scrollback(5); + parser.set_scrollback(5); assert_eq!(parser.screen().scrollback(), 5); assert_eq!(parser.screen().contents(), "10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33"); -- cgit v1.2.3-54-g00ecf