termwiz/terminal/mod.rs
1//! An abstraction over a terminal device
2
3use crate::caps::probed::ProbeCapabilities;
4use crate::caps::Capabilities;
5use crate::input::InputEvent;
6use crate::surface::Change;
7use crate::{format_err, Result};
8use num_traits::NumCast;
9use std::fmt::Display;
10use std::time::Duration;
11
12#[cfg(unix)]
13pub mod unix;
14#[cfg(windows)]
15pub mod windows;
16
17pub mod buffered;
18
19#[cfg(unix)]
20pub use self::unix::{UnixTerminal, UnixTerminalWaker as TerminalWaker};
21#[cfg(windows)]
22pub use self::windows::{WindowsTerminal, WindowsTerminalWaker as TerminalWaker};
23
24/// Represents the size of the terminal screen.
25/// The number of rows and columns of character cells are expressed.
26/// Some implementations populate the size of those cells in pixels.
27// On Windows, GetConsoleFontSize() can return the size of a cell in
28// logical units and we can probably use this to populate xpixel, ypixel.
29// GetConsoleScreenBufferInfo() can return the rows and cols.
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub struct ScreenSize {
32 /// The number of rows of text
33 pub rows: usize,
34 /// The number of columns per row
35 pub cols: usize,
36 /// The width of a cell in pixels. Some implementations never
37 /// set this to anything other than zero.
38 pub xpixel: usize,
39 /// The height of a cell in pixels. Some implementations never
40 /// set this to anything other than zero.
41 pub ypixel: usize,
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub enum Blocking {
46 DoNotWait,
47 Wait,
48}
49
50/// `Terminal` abstracts over some basic terminal capabilities.
51/// If the `set_raw_mode` or `set_cooked_mode` functions are used in
52/// any combination, the implementation is required to restore the
53/// terminal mode that was in effect when it was created.
54pub trait Terminal {
55 /// Raw mode disables input line buffering, allowing data to be
56 /// read as the user presses keys, disables local echo, so keys
57 /// pressed by the user do not implicitly render to the terminal
58 /// output, and disables canonicalization of unix newlines to CRLF.
59 fn set_raw_mode(&mut self) -> Result<()>;
60 fn set_cooked_mode(&mut self) -> Result<()>;
61
62 /// Enter the alternate screen. The alternate screen will be left
63 /// automatically when the `Terminal` is dropped.
64 fn enter_alternate_screen(&mut self) -> Result<()>;
65
66 /// Exit the alternate screen.
67 fn exit_alternate_screen(&mut self) -> Result<()>;
68
69 /// Queries the current screen size, returning width, height.
70 fn get_screen_size(&mut self) -> Result<ScreenSize>;
71
72 /// Returns a capability probing helper that will use escape
73 /// sequences to attempt to probe information from the terminal
74 fn probe_capabilities(&mut self) -> Option<ProbeCapabilities> {
75 None
76 }
77
78 /// Sets the current screen size
79 fn set_screen_size(&mut self, size: ScreenSize) -> Result<()>;
80
81 /// Render a series of changes to the terminal output
82 fn render(&mut self, changes: &[Change]) -> Result<()>;
83
84 /// Flush any buffered output
85 fn flush(&mut self) -> Result<()>;
86
87 /// Check for a parsed input event.
88 /// `wait` indicates the behavior in the case that no input is
89 /// immediately available. If wait is `None` then `poll_input`
90 /// will not return until an event is available. If wait is
91 /// `Some(duration)` then `poll_input` will wait up to the given
92 /// duration for an event before returning with a value of
93 /// `Ok(None)`. If wait is `Some(Duration::ZERO)` then the
94 /// poll is non-blocking.
95 ///
96 /// The possible values returned as `InputEvent`s depend on the
97 /// mode of the terminal. Most values are not returned unless
98 /// the terminal is set to raw mode.
99 fn poll_input(&mut self, wait: Option<Duration>) -> Result<Option<InputEvent>>;
100
101 fn waker(&self) -> TerminalWaker;
102}
103
104/// `SystemTerminal` is a concrete implementation of `Terminal`.
105/// Ideally you wouldn't reference `SystemTerminal` in consuming
106/// code. This type is exposed for convenience if you are doing
107/// something unusual and want easier access to the constructors.
108#[cfg(unix)]
109pub type SystemTerminal = UnixTerminal;
110#[cfg(windows)]
111pub type SystemTerminal = WindowsTerminal;
112
113/// Construct a new instance of Terminal.
114/// The terminal will have a renderer that is influenced by the configuration
115/// in the provided `Capabilities` instance.
116/// The terminal will explicitly open `/dev/tty` on Unix systems and
117/// `CONIN$` and `CONOUT$` on Windows systems, so that it should yield a
118/// functioning console with minimal headaches.
119/// If you have a more advanced use case you will want to look to the
120/// constructors for `UnixTerminal` and `WindowsTerminal` and call whichever
121/// one is most suitable for your needs.
122pub fn new_terminal(caps: Capabilities) -> Result<impl Terminal> {
123 SystemTerminal::new(caps)
124}
125
126pub(crate) fn cast<T: NumCast + Display + Copy, U: NumCast>(n: T) -> Result<U> {
127 num_traits::cast(n).ok_or_else(|| format_err!("{} is out of bounds for this system", n))
128}