terminal_utils/
lib.rs

1//! # Usage
2//! This crate provides utilities for working with the terminal.
3//!
4//! ## Terminal size
5//!
6//! ```
7//! let size = terminal_utils::size().unwrap();
8//! println!("The terminal is {}x{} characters.", size.width, size.height);
9//! ```
10//!
11//! ## Raw mode
12//!
13//! ```
14//! let raw_mode_guard = terminal_utils::enable_raw_mode().unwrap();
15//! println!("Raw mode is enabled.");
16//!
17//! let is_raw_mode_enabled = terminal_utils::is_raw_mode_enabled().unwrap();
18//! assert!(is_raw_mode_enabled);
19//!
20//! // Previous terminal mode is restored when the guard is dropped.
21//! drop(raw_mode_guard);
22//! println!("Raw mode is disabled.");
23//! ```
24//!
25//! ## Resize signal
26//! This feature is only available with the `tokio` feature. It is enabled by default.
27//!
28//! ```no_run
29//! let mut resize_rx = terminal_utils::on_resize().unwrap();
30//! tokio::spawn(async move {
31//!     loop {
32//!         resize_rx.changed().await.unwrap();
33//!
34//!         let size = resize_rx.borrow();
35//!         println!("terminal size changed: {:?}", size);
36//!     }
37//! });
38//! ```
39
40#[cfg(unix)]
41mod unix;
42#[cfg(windows)]
43mod windows;
44
45use std::io;
46
47#[cfg(unix)]
48use unix as sys;
49#[cfg(windows)]
50use windows as sys;
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53pub struct TerminalSize {
54    pub width: u16,
55    pub height: u16,
56
57    pub pixel_width: u16,
58    pub pixel_height: u16,
59}
60
61/// Returns the size of the terminal.
62pub fn size() -> Result<TerminalSize, io::Error> {
63    sys::size()
64}
65
66/// Tells whether the raw mode is currently enabled.
67pub fn is_raw_mode_enabled() -> Result<bool, io::Error> {
68    sys::is_raw_mode_enabled()
69}
70
71/// Enables raw mode.
72/// Once the returned guard is dropped, the previous mode is restored.
73pub fn enable_raw_mode() -> Result<RawModeGuard, io::Error> {
74    RawModeGuard::new()
75}
76
77/// Returns a receiver that receives a signal when the terminal is resized.
78#[cfg(feature = "tokio")]
79pub fn on_resize() -> Result<tokio::sync::watch::Receiver<TerminalSize>, io::Error> {
80    let terminal_size = size()?;
81    let (tx, rx) = tokio::sync::watch::channel(terminal_size);
82
83    sys::spawn_on_resize_task(tx)?;
84
85    Ok(rx)
86}
87
88/// A guard that restores the previous terminal mode when dropped.
89pub struct RawModeGuard {
90    original_state: sys::TerminalState,
91}
92
93impl RawModeGuard {
94    fn new() -> Result<Self, io::Error> {
95        let original_state = sys::enable_raw_mode()?;
96
97        Ok(Self { original_state })
98    }
99}
100
101impl Drop for RawModeGuard {
102    /// Restores the previous mode.
103    fn drop(&mut self) {
104        let _ = sys::restore_mode(self.original_state);
105    }
106}