mirror of
https://github.com/ratatui-org/ratatui
synced 2024-11-30 00:20:34 +00:00
feat: crossterm backend can use alternate screen
This commit is contained in:
parent
7290086fe9
commit
b30cae0473
1 changed files with 43 additions and 11 deletions
|
@ -8,12 +8,20 @@ use crossterm::error::ErrorKind;
|
||||||
|
|
||||||
pub struct CrosstermBackend {
|
pub struct CrosstermBackend {
|
||||||
screen: crossterm::Screen,
|
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<crossterm::AlternateScreen>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for CrosstermBackend {
|
impl Default for CrosstermBackend {
|
||||||
fn default() -> CrosstermBackend {
|
fn default() -> CrosstermBackend {
|
||||||
|
let screen = crossterm::Screen::default();
|
||||||
|
let crossterm = crossterm::Crossterm::from_screen(&screen);
|
||||||
CrosstermBackend {
|
CrosstermBackend {
|
||||||
screen: crossterm::Screen::default(),
|
screen,
|
||||||
|
crossterm,
|
||||||
|
alternate_screen: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,12 +32,38 @@ impl CrosstermBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_screen(screen: crossterm::Screen) -> 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<CrosstermBackend, io::Error> {
|
||||||
|
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 {
|
pub fn screen(&self) -> &crossterm::Screen {
|
||||||
&self.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
|
// 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 {
|
impl Backend for CrosstermBackend {
|
||||||
fn clear(&mut self) -> io::Result<()> {
|
fn clear(&mut self) -> io::Result<()> {
|
||||||
let terminal = crossterm::terminal();
|
let terminal = self.crossterm.terminal();
|
||||||
terminal
|
terminal
|
||||||
.clear(crossterm::ClearType::All)
|
.clear(crossterm::ClearType::All)
|
||||||
.map_err(convert_error)?;
|
.map_err(convert_error)?;
|
||||||
|
@ -58,13 +92,13 @@ impl Backend for CrosstermBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hide_cursor(&mut self) -> io::Result<()> {
|
fn hide_cursor(&mut self) -> io::Result<()> {
|
||||||
let cursor = crossterm::cursor();
|
let cursor = self.crossterm.cursor();
|
||||||
cursor.hide().map_err(convert_error)?;
|
cursor.hide().map_err(convert_error)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_cursor(&mut self) -> io::Result<()> {
|
fn show_cursor(&mut self) -> io::Result<()> {
|
||||||
let cursor = crossterm::cursor();
|
let cursor = self.crossterm.cursor();
|
||||||
cursor.show().map_err(convert_error)?;
|
cursor.show().map_err(convert_error)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -80,7 +114,7 @@ impl Backend for CrosstermBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size(&self) -> io::Result<Rect> {
|
fn size(&self) -> io::Result<Rect> {
|
||||||
let terminal = crossterm::terminal();
|
let terminal = self.crossterm.terminal();
|
||||||
let (width, height) = terminal.terminal_size();
|
let (width, height) = terminal.terminal_size();
|
||||||
Ok(Rect::new(0, 0, width, height))
|
Ok(Rect::new(0, 0, width, height))
|
||||||
}
|
}
|
||||||
|
@ -93,8 +127,7 @@ impl Backend for CrosstermBackend {
|
||||||
where
|
where
|
||||||
I: Iterator<Item = (u16, u16, &'a Cell)>,
|
I: Iterator<Item = (u16, u16, &'a Cell)>,
|
||||||
{
|
{
|
||||||
let cursor = crossterm::cursor();
|
let cursor = self.crossterm.cursor();
|
||||||
let crossterm = crossterm::Crossterm::from_screen(&self.screen);
|
|
||||||
let mut last_y = 0;
|
let mut last_y = 0;
|
||||||
let mut last_x = 0;
|
let mut last_x = 0;
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
|
@ -105,8 +138,7 @@ impl Backend for CrosstermBackend {
|
||||||
}
|
}
|
||||||
last_x = x;
|
last_x = x;
|
||||||
last_y = y;
|
last_y = y;
|
||||||
|
let mut s = self.crossterm.style(&cell.symbol);
|
||||||
let mut s = crossterm::style(&cell.symbol);
|
|
||||||
if let Some(color) = cell.style.fg.into() {
|
if let Some(color) = cell.style.fg.into() {
|
||||||
s = s.with(color)
|
s = s.with(color)
|
||||||
}
|
}
|
||||||
|
@ -116,7 +148,7 @@ impl Backend for CrosstermBackend {
|
||||||
if let Some(attr) = cell.style.modifier.into() {
|
if let Some(attr) = cell.style.modifier.into() {
|
||||||
s = s.attr(attr)
|
s = s.attr(attr)
|
||||||
}
|
}
|
||||||
crossterm.paint(s).map_err(convert_error)?;
|
self.crossterm.paint(s).map_err(convert_error)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue