feat(terminal): add unstable api to use a fixed viewport

There was now way to avoid the autoresize behavior of `Terminal`. While it was fine for most users,
it made the testing experience painful as it was impossible to avoid the calls to `Backend::size()`.
Indeed they trigger the following error: "Inappropriate ioctl for device" since we are not running
the tests in a real terminal (at least in the CI).

This commit introduces a new api to create a `Terminal` with a fixed viewport.
pull/347/head
Florian Dehau 4 years ago
parent dc26f7ba9f
commit 641f391137

@ -154,4 +154,4 @@ pub mod terminal;
pub mod text; pub mod text;
pub mod widgets; pub mod widgets;
pub use self::terminal::{Frame, Terminal}; pub use self::terminal::{Frame, Terminal, TerminalOptions, Viewport};

@ -1,9 +1,41 @@
use crate::{
backend::Backend,
buffer::Buffer,
layout::Rect,
widgets::{StatefulWidget, Widget},
};
use std::io; use std::io;
use crate::backend::Backend; #[derive(Debug, Clone, PartialEq)]
use crate::buffer::Buffer; /// UNSTABLE
use crate::layout::Rect; enum ResizeBehavior {
use crate::widgets::{StatefulWidget, Widget}; Fixed,
Auto,
}
#[derive(Debug, Clone, PartialEq)]
/// UNSTABLE
pub struct Viewport {
area: Rect,
resize_behavior: ResizeBehavior,
}
impl Viewport {
/// UNSTABLE
pub fn fixed(area: Rect) -> Viewport {
Viewport {
area,
resize_behavior: ResizeBehavior::Fixed,
}
}
}
#[derive(Debug, Clone, PartialEq)]
/// Options to pass to [`Terminal::draw_with_options`]
pub struct TerminalOptions {
/// Viewport used to draw to the terminal
pub viewport: Viewport,
}
/// Interface to the terminal backed by Termion /// Interface to the terminal backed by Termion
#[derive(Debug)] #[derive(Debug)]
@ -19,8 +51,8 @@ where
current: usize, current: usize,
/// Whether the cursor is currently hidden /// Whether the cursor is currently hidden
hidden_cursor: bool, hidden_cursor: bool,
/// Terminal size used for rendering. /// Viewport
known_size: Rect, viewport: Viewport,
} }
/// Represents a consistent terminal interface for rendering. /// Represents a consistent terminal interface for rendering.
@ -43,7 +75,7 @@ where
{ {
/// Terminal size, guaranteed not to change when rendering. /// Terminal size, guaranteed not to change when rendering.
pub fn size(&self) -> Rect { pub fn size(&self) -> Rect {
self.terminal.known_size self.terminal.viewport.area
} }
/// Render a [`Widget`] to the current buffer using [`Widget::render`]. /// Render a [`Widget`] to the current buffer using [`Widget::render`].
@ -138,12 +170,28 @@ where
/// default colors for the foreground and the background /// default colors for the foreground and the background
pub fn new(backend: B) -> io::Result<Terminal<B>> { pub fn new(backend: B) -> io::Result<Terminal<B>> {
let size = backend.size()?; let size = backend.size()?;
Terminal::with_options(
backend,
TerminalOptions {
viewport: Viewport {
area: size,
resize_behavior: ResizeBehavior::Auto,
},
},
)
}
/// UNSTABLE
pub fn with_options(backend: B, options: TerminalOptions) -> io::Result<Terminal<B>> {
Ok(Terminal { Ok(Terminal {
backend, backend,
buffers: [Buffer::empty(size), Buffer::empty(size)], buffers: [
Buffer::empty(options.viewport.area),
Buffer::empty(options.viewport.area),
],
current: 0, current: 0,
hidden_cursor: false, hidden_cursor: false,
known_size: size, viewport: options.viewport,
}) })
} }
@ -183,16 +231,18 @@ where
self.buffers[self.current].resize(area); self.buffers[self.current].resize(area);
self.buffers[1 - self.current].reset(); self.buffers[1 - self.current].reset();
self.buffers[1 - self.current].resize(area); self.buffers[1 - self.current].resize(area);
self.known_size = area; self.viewport.area = area;
self.backend.clear() self.backend.clear()
} }
/// Queries the backend for size and resizes if it doesn't match the previous size. /// Queries the backend for size and resizes if it doesn't match the previous size.
pub fn autoresize(&mut self) -> io::Result<()> { pub fn autoresize(&mut self) -> io::Result<()> {
let size = self.size()?; if self.viewport.resize_behavior == ResizeBehavior::Auto {
if self.known_size != size { let size = self.size()?;
self.resize(size)?; if size != self.viewport.area {
} self.resize(size)?;
}
};
Ok(()) Ok(())
} }
@ -238,20 +288,25 @@ where
self.hidden_cursor = true; self.hidden_cursor = true;
Ok(()) Ok(())
} }
pub fn show_cursor(&mut self) -> io::Result<()> { pub fn show_cursor(&mut self) -> io::Result<()> {
self.backend.show_cursor()?; self.backend.show_cursor()?;
self.hidden_cursor = false; self.hidden_cursor = false;
Ok(()) Ok(())
} }
pub fn get_cursor(&mut self) -> io::Result<(u16, u16)> { pub fn get_cursor(&mut self) -> io::Result<(u16, u16)> {
self.backend.get_cursor() self.backend.get_cursor()
} }
pub fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> { pub fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> {
self.backend.set_cursor(x, y) self.backend.set_cursor(x, y)
} }
pub fn clear(&mut self) -> io::Result<()> { pub fn clear(&mut self) -> io::Result<()> {
self.backend.clear() self.backend.clear()
} }
/// Queries the real size of the backend. /// Queries the real size of the backend.
pub fn size(&self) -> io::Result<Rect> { pub fn size(&self) -> io::Result<Rect> {
self.backend.size() self.backend.size()

Loading…
Cancel
Save