diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/screen.rs | 153 | ||||
-rw-r--r-- | src/term.rs | 220 |
2 files changed, 344 insertions, 29 deletions
diff --git a/src/screen.rs b/src/screen.rs index d4613f0..3128f78 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -169,14 +169,11 @@ impl Screen { }) } - /// Returns the formatted contents of the terminal. + /// Returns the formatted visible contents of the terminal. /// /// Formatting information will be included inline as terminal escape /// codes. The result will be suitable for feeding directly to a raw - /// terminal parser, and will result in the same visual output. Internal - /// terminal modes (such as application keypad mode or alternate screen - /// mode) will not be included here, but modes that affect the visible - /// output (such as hidden cursor mode) will. + /// terminal parser, and will result in the same visual output. pub fn contents_formatted(&self) -> Vec<u8> { let mut contents = vec![]; self.write_contents_formatted(&mut contents); @@ -189,16 +186,16 @@ impl Screen { self.attrs.write_escape_code_diff(contents, &prev_attrs); } - /// Returns the formatted contents of the terminal by row, restricted to - /// the given subset of columns. + /// Returns the formatted visible contents of the terminal by row, + /// restricted to the given subset of columns. /// /// Formatting information will be included inline as terminal escape /// codes. The result will be suitable for feeding directly to a raw - /// terminal parser, and will result in the same visual output. Internal - /// terminal modes (such as application keypad mode or alternate screen - /// mode) will not be included here. + /// terminal parser, and will result in the same visual output. /// - /// CRLF at the end of lines will not be included. + /// You are responsible for positioning the cursor before printing each + /// row, and final cursor position after displaying each row is + /// unspecified. pub fn rows_formatted( &self, start: u16, @@ -220,8 +217,9 @@ impl Screen { }) } - /// Returns a terminal byte stream sufficient to turn the screen described - /// by `prev` into the screen described by `self`. + /// Returns a terminal byte stream sufficient to turn the visible contents + /// of the screen described by `prev` into the visible contents of the + /// screen described by `self`. /// /// The result of rendering `prev.contents_formatted()` followed by /// `self.contents_diff(prev)` should be equivalent to the result of @@ -246,22 +244,16 @@ impl Screen { prev.attrs, ); self.attrs.write_escape_code_diff(contents, &prev_attrs); - 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 a sequence of terminal byte streams sufficient to turn the - /// subset of each row from `prev` (as described by `start` and `width`) - /// into the corresponding row subset in `self`. + /// visible contents of the subset of each row from `prev` (as described + /// by `start` and `width`) into the visible contents of the corresponding + /// row subset in `self`. /// - /// You must handle the initial row positioning yourself - each row diff - /// expects to start out positioned at the start of that row. Internal - /// terminal modes (such as application keypad mode or alternate screen - /// mode) will not be included here. + /// You are responsible for positioning the cursor before printing each + /// row, and final cursor position after displaying each row is + /// unspecified. pub fn rows_diff<'a>( &'a self, prev: &'a Self, @@ -289,6 +281,117 @@ impl Screen { }) } + pub fn input_mode_formatted(&self) -> Vec<u8> { + let mut contents = vec![]; + self.write_input_mode_formatted(&mut contents); + contents + } + + fn write_input_mode_formatted(&self, contents: &mut Vec<u8>) { + crate::term::ApplicationKeypad::new( + self.mode(Mode::ApplicationKeypad), + ) + .write_buf(contents); + crate::term::ApplicationCursor::new( + self.mode(Mode::ApplicationCursor), + ) + .write_buf(contents); + crate::term::BracketedPaste::new(self.mode(Mode::BracketedPaste)) + .write_buf(contents); + crate::term::MouseProtocolMode::new( + self.mouse_protocol_mode, + MouseProtocolMode::None, + ) + .write_buf(contents); + crate::term::MouseProtocolEncoding::new( + self.mouse_protocol_encoding, + MouseProtocolEncoding::Default, + ) + .write_buf(contents); + } + + pub fn input_mode_diff(&self, prev: &Self) -> Vec<u8> { + let mut contents = vec![]; + self.write_input_mode_diff(&mut contents, prev); + contents + } + + fn write_input_mode_diff(&self, contents: &mut Vec<u8>, prev: &Self) { + if self.mode(Mode::ApplicationKeypad) + != prev.mode(Mode::ApplicationKeypad) + { + crate::term::ApplicationKeypad::new( + self.mode(Mode::ApplicationKeypad), + ) + .write_buf(contents); + } + if self.mode(Mode::ApplicationCursor) + != prev.mode(Mode::ApplicationCursor) + { + crate::term::ApplicationCursor::new( + self.mode(Mode::ApplicationCursor), + ) + .write_buf(contents); + } + if self.mode(Mode::BracketedPaste) != prev.mode(Mode::BracketedPaste) + { + crate::term::BracketedPaste::new(self.mode(Mode::BracketedPaste)) + .write_buf(contents); + } + crate::term::MouseProtocolMode::new( + self.mouse_protocol_mode, + prev.mouse_protocol_mode, + ) + .write_buf(contents); + crate::term::MouseProtocolEncoding::new( + self.mouse_protocol_encoding, + prev.mouse_protocol_encoding, + ) + .write_buf(contents); + } + + pub fn title_formatted(&self) -> Vec<u8> { + let mut contents = vec![]; + self.write_title_formatted(&mut contents); + contents + } + + fn write_title_formatted(&self, contents: &mut Vec<u8>) { + crate::term::ChangeTitle::new(&self.icon_name, &self.title, "", "") + .write_buf(contents); + } + + pub fn title_diff(&self, prev: &Self) -> Vec<u8> { + let mut contents = vec![]; + self.write_title_diff(&mut contents, prev); + contents + } + + fn write_title_diff(&self, contents: &mut Vec<u8>, prev: &Self) { + crate::term::ChangeTitle::new( + &self.icon_name, + &self.title, + &prev.icon_name, + &prev.title, + ) + .write_buf(contents); + } + + 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 the `Cell` object at the given location in the terminal, if it /// exists. pub fn cell(&self, row: u16, col: u16) -> Option<&crate::cell::Cell> { diff --git a/src/term.rs b/src/term.rs index c988702..d2f7c9b 100644 --- a/src/term.rs +++ b/src/term.rs @@ -299,18 +299,18 @@ impl BufWrite for EraseChar { #[derive(Default, Debug)] #[must_use = "this struct does nothing unless you call write_buf"] pub struct HideCursor { - hide: bool, + state: bool, } impl HideCursor { - pub fn new(hide: bool) -> Self { - Self { hide } + pub fn new(state: bool) -> Self { + Self { state } } } impl BufWrite for HideCursor { fn write_buf(&self, buf: &mut Vec<u8>) { - if self.hide { + if self.state { buf.extend_from_slice(b"\x1b[?25l") } else { buf.extend_from_slice(b"\x1b[?25h") @@ -364,3 +364,215 @@ impl BufWrite for VisualBell { 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, + title: &'a str, + prev_icon_name: &'a str, + prev_title: &'a str, +} + +impl<'a> ChangeTitle<'a> { + pub fn new( + icon_name: &'a str, + title: &'a str, + prev_icon_name: &'a str, + prev_title: &'a str, + ) -> Self { + Self { + icon_name, + title, + prev_icon_name, + prev_title, + } + } +} + +impl<'a> BufWrite for ChangeTitle<'a> { + fn write_buf(&self, buf: &mut Vec<u8>) { + if self.icon_name == self.title + && (self.icon_name != self.prev_icon_name + || self.title != self.prev_title) + { + buf.extend_from_slice(b"\x1b]0;"); + buf.extend_from_slice(self.icon_name.as_bytes()); + buf.push(b'\x07'); + } else { + if self.icon_name != self.prev_icon_name { + buf.extend_from_slice(b"\x1b]1;"); + buf.extend_from_slice(self.icon_name.as_bytes()); + buf.push(b'\x07'); + } + if self.title != self.prev_title { + buf.extend_from_slice(b"\x1b]2;"); + buf.extend_from_slice(self.title.as_bytes()); + buf.push(b'\x07'); + } + } + } +} + +#[derive(Default, Debug)] +#[must_use = "this struct does nothing unless you call write_buf"] +pub struct ApplicationKeypad { + state: bool, +} + +impl ApplicationKeypad { + pub fn new(state: bool) -> Self { + Self { state } + } +} + +impl BufWrite for ApplicationKeypad { + fn write_buf(&self, buf: &mut Vec<u8>) { + if self.state { + buf.extend_from_slice(b"\x1b=") + } else { + buf.extend_from_slice(b"\x1b>") + } + } +} + +#[derive(Default, Debug)] +#[must_use = "this struct does nothing unless you call write_buf"] +pub struct ApplicationCursor { + state: bool, +} + +impl ApplicationCursor { + pub fn new(state: bool) -> Self { + Self { state } + } +} + +impl BufWrite for ApplicationCursor { + fn write_buf(&self, buf: &mut Vec<u8>) { + if self.state { + buf.extend_from_slice(b"\x1b[?1h") + } else { + buf.extend_from_slice(b"\x1b[?1l") + } + } +} + +#[derive(Default, Debug)] +#[must_use = "this struct does nothing unless you call write_buf"] +pub struct BracketedPaste { + state: bool, +} + +impl BracketedPaste { + pub fn new(state: bool) -> Self { + Self { state } + } +} + +impl BufWrite for BracketedPaste { + fn write_buf(&self, buf: &mut Vec<u8>) { + if self.state { + buf.extend_from_slice(b"\x1b[?2004h") + } else { + buf.extend_from_slice(b"\x1b[?2004l") + } + } +} + +#[derive(Default, Debug)] +#[must_use = "this struct does nothing unless you call write_buf"] +pub struct MouseProtocolMode { + mode: crate::screen::MouseProtocolMode, + prev: crate::screen::MouseProtocolMode, +} + +impl MouseProtocolMode { + pub fn new( + mode: crate::screen::MouseProtocolMode, + prev: crate::screen::MouseProtocolMode, + ) -> Self { + Self { mode, prev } + } +} + +impl BufWrite for MouseProtocolMode { + fn write_buf(&self, buf: &mut Vec<u8>) { + if self.mode == self.prev { + return; + } + + match self.mode { + crate::screen::MouseProtocolMode::None => match self.prev { + crate::screen::MouseProtocolMode::None => {} + crate::screen::MouseProtocolMode::Press => { + buf.extend_from_slice(b"\x1b[?9l"); + } + crate::screen::MouseProtocolMode::PressRelease => { + buf.extend_from_slice(b"\x1b[?1000l"); + } + crate::screen::MouseProtocolMode::ButtonMotion => { + buf.extend_from_slice(b"\x1b[?1002l"); + } + crate::screen::MouseProtocolMode::AnyMotion => { + buf.extend_from_slice(b"\x1b[?1003l"); + } + }, + crate::screen::MouseProtocolMode::Press => { + buf.extend_from_slice(b"\x1b[?9h"); + } + crate::screen::MouseProtocolMode::PressRelease => { + buf.extend_from_slice(b"\x1b[?1000h"); + } + crate::screen::MouseProtocolMode::ButtonMotion => { + buf.extend_from_slice(b"\x1b[?1002h"); + } + crate::screen::MouseProtocolMode::AnyMotion => { + buf.extend_from_slice(b"\x1b[?1003h"); + } + } + } +} + +#[derive(Default, Debug)] +#[must_use = "this struct does nothing unless you call write_buf"] +pub struct MouseProtocolEncoding { + encoding: crate::screen::MouseProtocolEncoding, + prev: crate::screen::MouseProtocolEncoding, +} + +impl MouseProtocolEncoding { + pub fn new( + encoding: crate::screen::MouseProtocolEncoding, + prev: crate::screen::MouseProtocolEncoding, + ) -> Self { + Self { encoding, prev } + } +} + +impl BufWrite for MouseProtocolEncoding { + fn write_buf(&self, buf: &mut Vec<u8>) { + if self.encoding == self.prev { + return; + } + + match self.encoding { + crate::screen::MouseProtocolEncoding::Default => { + match self.prev { + crate::screen::MouseProtocolEncoding::Default => {} + crate::screen::MouseProtocolEncoding::Utf8 => { + buf.extend_from_slice(b"\x1b[?1005l"); + } + crate::screen::MouseProtocolEncoding::Sgr => { + buf.extend_from_slice(b"\x1b[?1006l"); + } + } + } + crate::screen::MouseProtocolEncoding::Utf8 => { + buf.extend_from_slice(b"\x1b[?1005h"); + } + crate::screen::MouseProtocolEncoding::Sgr => { + buf.extend_from_slice(b"\x1b[?1006h"); + } + } + } +} |