1// devela::sys::os::linux::terminal
2//
3//! Linux terminal related items.
4//
56use super::{LinuxTerminalSize, LinuxTermios};
78#[cfg(all(feature = "dep_atomic", feature = "dep_bytemuck"))]
9use crate::_dep::atomic::{Atomic, Ordering as AtomicOrdering};
1011/// State of the terminal saved globally, that can be restored from anywhere.
12///
13/// This allows to restore the initial terminal state from a panic handler. E.g.:
14///
15/// ```ignore
16/// # use devela::LinuxTerminal;
17/// #[panic_handler]
18/// fn panic(_info: &core::panic::PanicInfo) -> ! {
19/// LinuxTerminal::restore_saved_state().unwrap();
20/// }
21/// ```
22///
23/// # Features
24/// Makes use of [`atomic`] and [`bytemuck`] dependencies to save the
25/// terminal state in an [`Atomic`].
26///
27/// [`atomic`]: crate::_dep::atomic
28/// [`bytemuck`]: crate::_dep::bytemuck
29#[cfg_attr(
30 feature = "nightly_doc",
31 doc(cfg(all(feature = "dep_atomic", feature = "dep_bytemuck")))
32)]
33#[cfg(all(feature = "dep_atomic", feature = "dep_bytemuck"))]
34pub static LINUX_TERMINAL_STATE: Atomic<LinuxTermios> = Atomic::new(LinuxTermios::new());
3536/// Linux terminal manager.
37///
38/// # Features
39/// With `atomic` and `bytemuck` enabled,
40/// the terminal state is saved in [`LINUX_TERMINAL_STATE`] and restored on drop.
41#[allow(rustdoc::broken_intra_doc_links, reason = "LINUX_TERMINAL_STATE")]
42#[derive(Debug, Default)]
43pub struct LinuxTerminal;
4445#[cfg_attr(
46 feature = "nightly_doc",
47 doc(cfg(all(feature = "dep_atomic", feature = "dep_bytemuck")))
48)]
49#[cfg(all(feature = "dep_atomic", feature = "dep_bytemuck"))]
50impl Drop for LinuxTerminal {
51fn drop(&mut self) {
52// If we are here, this should work
53Self::restore_saved_state().unwrap();
54 }
55}
5657#[allow(rustdoc::broken_intra_doc_links, reason = "LINUX_TERMINAL_STATE")]
58impl LinuxTerminal {
59/// Returns a new linux terminal configured in canonical (cooked) mode.
60 ///
61 /// # Features
62 /// With `atomic` and `bytemuck` enabled,
63 /// it saves the initial terminal state in [`LINUX_TERMINAL_STATE`].
64pub fn new() -> Result<Self, isize> {
65#[cfg(all(feature = "dep_atomic", feature = "dep_bytemuck"))]
66Self::save_state()?;
67Ok(Self)
68 }
6970/// Returns a new linux terminal configured in raw mode.
71 ///
72 /// *Raw* mode is a mode where the terminal's input is processed character
73 /// by character, rather than line by line.
74 ///
75 /// # Features
76 /// With `atomic` and `bytemuck` enabled,
77 /// it saves the initial terminal state in [`LINUX_TERMINAL_STATE`].
78pub fn new_raw() -> Result<Self, isize> {
79#[cfg(all(feature = "dep_atomic", feature = "dep_bytemuck"))]
80Self::save_state()?;
8182let new = Self::new()?;
83 new.enable_raw_mode()?;
84Ok(new)
85 }
8687/// Saves the current terminal state into [`LINUX_TERMINAL_STATE`].
88#[cfg_attr(
89 feature = "nightly_doc",
90 doc(cfg(all(feature = "dep_bytemuck", feature = "dep_atomic")))
91 )]
92 #[cfg(all(feature = "dep_atomic", feature = "dep_bytemuck"))]
93pub fn save_state() -> Result<(), isize> {
94 LINUX_TERMINAL_STATE.store(LinuxTermios::get_state()?, AtomicOrdering::Relaxed);
95Ok(())
96 }
9798/// Restores the current terminal state into [`LINUX_TERMINAL_STATE`].
99#[cfg_attr(
100 feature = "nightly_doc",
101 doc(cfg(all(feature = "dep_bytemuck", feature = "dep_atomic")))
102 )]
103 #[cfg(all(feature = "dep_atomic", feature = "dep_bytemuck"))]
104pub fn restore_saved_state() -> Result<(), isize> {
105 LinuxTermios::set_state(LINUX_TERMINAL_STATE.load(AtomicOrdering::Relaxed))
106 }
107108/// Returns `true` if we are in a terminal context.
109#[must_use]
110pub fn is_terminal(&self) -> bool {
111 LinuxTermios::is_terminal()
112 }
113114/// Returns the terminal dimensions.
115pub fn size(&self) -> Result<LinuxTerminalSize, isize> {
116 LinuxTermios::get_winsize()
117 }
118119/// Enables raw mode.
120 ///
121 /// Raw mode is a way to configure the terminal so that it does not process or
122 /// interpret any of the input but instead passes it directly to the program.
123pub fn enable_raw_mode(&self) -> Result<(), isize> {
124 LinuxTermios::enable_raw_mode()
125 }
126127/// Disables raw mode.
128pub fn disable_raw_mode(&self) -> Result<(), isize> {
129 LinuxTermios::disable_raw_mode()
130 }
131}