From b30cae0473a64d2a47b9441d59bdf822a4c40992 Mon Sep 17 00:00:00 2001 From: defiori <46789010+defiori@users.noreply.github.com> Date: Fri, 8 Feb 2019 13:03:18 +0000 Subject: [PATCH] feat: crossterm backend can use alternate screen --- src/backend/crossterm.rs | 54 ++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/src/backend/crossterm.rs b/src/backend/crossterm.rs index 1f147a8a..2f490a65 100644 --- a/src/backend/crossterm.rs +++ b/src/backend/crossterm.rs @@ -8,12 +8,20 @@ use crossterm::error::ErrorKind; pub struct CrosstermBackend { screen: crossterm::Screen, + crossterm: crossterm::Crossterm, + // Need to keep the AlternateScreen around even when not using it directly, + // see https://github.com/TimonPost/crossterm/issues/88 + alternate_screen: Option, } impl Default for CrosstermBackend { fn default() -> CrosstermBackend { + let screen = crossterm::Screen::default(); + let crossterm = crossterm::Crossterm::from_screen(&screen); CrosstermBackend { - screen: crossterm::Screen::default(), + screen, + crossterm, + alternate_screen: None, } } } @@ -24,12 +32,38 @@ impl CrosstermBackend { } pub fn with_screen(screen: crossterm::Screen) -> CrosstermBackend { - CrosstermBackend { screen: screen } + let crossterm = crossterm::Crossterm::from_screen(&screen); + CrosstermBackend { + screen, + crossterm, + alternate_screen: None, + } + } + + pub fn with_alternate_screen(screen: crossterm::Screen, raw_mode: bool) -> Result { + let alternate_screen = screen.enable_alternate_modes(raw_mode)?; + let crossterm = crossterm::Crossterm::from_screen(&alternate_screen.screen); + Ok(CrosstermBackend { + screen, + crossterm, + alternate_screen: Some(alternate_screen), + }) } pub fn screen(&self) -> &crossterm::Screen { &self.screen } + + pub fn alternate_screen(&self) -> Option<&crossterm::AlternateScreen> { + match &self.alternate_screen { + Some(alt_screen) => Some(&alt_screen), + None => None, + } + } + + pub fn crossterm(&self) -> &crossterm::Crossterm { + &self.crossterm + } } // TODO: consider associated Error type on Backend to allow custom error types @@ -50,7 +84,7 @@ fn convert_error(error: ErrorKind) -> io::Error { impl Backend for CrosstermBackend { fn clear(&mut self) -> io::Result<()> { - let terminal = crossterm::terminal(); + let terminal = self.crossterm.terminal(); terminal .clear(crossterm::ClearType::All) .map_err(convert_error)?; @@ -58,13 +92,13 @@ impl Backend for CrosstermBackend { } fn hide_cursor(&mut self) -> io::Result<()> { - let cursor = crossterm::cursor(); + let cursor = self.crossterm.cursor(); cursor.hide().map_err(convert_error)?; Ok(()) } fn show_cursor(&mut self) -> io::Result<()> { - let cursor = crossterm::cursor(); + let cursor = self.crossterm.cursor(); cursor.show().map_err(convert_error)?; Ok(()) } @@ -80,7 +114,7 @@ impl Backend for CrosstermBackend { } fn size(&self) -> io::Result { - let terminal = crossterm::terminal(); + let terminal = self.crossterm.terminal(); let (width, height) = terminal.terminal_size(); Ok(Rect::new(0, 0, width, height)) } @@ -93,8 +127,7 @@ impl Backend for CrosstermBackend { where I: Iterator, { - let cursor = crossterm::cursor(); - let crossterm = crossterm::Crossterm::from_screen(&self.screen); + let cursor = self.crossterm.cursor(); let mut last_y = 0; let mut last_x = 0; let mut first = true; @@ -105,8 +138,7 @@ impl Backend for CrosstermBackend { } last_x = x; last_y = y; - - let mut s = crossterm::style(&cell.symbol); + let mut s = self.crossterm.style(&cell.symbol); if let Some(color) = cell.style.fg.into() { s = s.with(color) } @@ -116,7 +148,7 @@ impl Backend for CrosstermBackend { if let Some(attr) = cell.style.modifier.into() { s = s.attr(attr) } - crossterm.paint(s).map_err(convert_error)?; + self.crossterm.paint(s).map_err(convert_error)?; } Ok(()) }