termion_temporary_zellij_fork/
raw.rs

1//! Managing raw mode.
2//!
3//! Raw mode is a particular state a TTY can have. It signifies that:
4//!
5//! 1. No line buffering (the input is given byte-by-byte).
6//! 2. The input is not written out, instead it has to be done manually by the programmer.
7//! 3. The output is not canonicalized (for example, `\n` means "go one line down", not "line
8//!    break").
9//!
10//! It is essential to design terminal programs.
11//!
12//! # Example
13//!
14//! ```rust,no_run
15//! use termion::raw::IntoRawMode;
16//! use std::io::{Write, stdout};
17//!
18//! fn main() {
19//!     let mut stdout = stdout().into_raw_mode().unwrap();
20//!
21//!     write!(stdout, "Hey there.").unwrap();
22//! }
23//! ```
24
25use std::io::{self, Write};
26use std::ops;
27
28use sys::attr::{get_terminal_attr, raw_terminal_attr, set_terminal_attr};
29use sys::Termios;
30
31/// The timeout of an escape code control sequence, in milliseconds.
32pub const CONTROL_SEQUENCE_TIMEOUT: u64 = 100;
33
34/// A terminal restorer, which keeps the previous state of the terminal, and restores it, when
35/// dropped.
36///
37/// Restoring will entirely bring back the old TTY state.
38pub struct RawTerminal<W: Write> {
39    prev_ios: Termios,
40    output: W,
41}
42
43impl<W: Write> Drop for RawTerminal<W> {
44    fn drop(&mut self) {
45        set_terminal_attr(&self.prev_ios).unwrap();
46    }
47}
48
49impl<W: Write> ops::Deref for RawTerminal<W> {
50    type Target = W;
51
52    fn deref(&self) -> &W {
53        &self.output
54    }
55}
56
57impl<W: Write> ops::DerefMut for RawTerminal<W> {
58    fn deref_mut(&mut self) -> &mut W {
59        &mut self.output
60    }
61}
62
63impl<W: Write> Write for RawTerminal<W> {
64    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
65        self.output.write(buf)
66    }
67
68    fn flush(&mut self) -> io::Result<()> {
69        self.output.flush()
70    }
71}
72
73#[cfg(unix)]
74mod unix_impl {
75    use super::*;
76    use std::os::unix::io::{AsRawFd, RawFd};
77
78    impl<W: Write + AsRawFd> AsRawFd for RawTerminal<W> {
79        fn as_raw_fd(&self) -> RawFd {
80            self.output.as_raw_fd()
81        }
82    }
83}
84
85/// Types which can be converted into "raw mode".
86///
87/// # Why is this type defined on writers and not readers?
88///
89/// TTYs has their state controlled by the writer, not the reader. You use the writer to clear the
90/// screen, move the cursor and so on, so naturally you use the writer to change the mode as well.
91pub trait IntoRawMode: Write + Sized {
92    /// Switch to raw mode.
93    ///
94    /// Raw mode means that stdin won't be printed (it will instead have to be written manually by
95    /// the program). Furthermore, the input isn't canonicalised or buffered (that is, you can
96    /// read from stdin one byte of a time). The output is neither modified in any way.
97    fn into_raw_mode(self) -> io::Result<RawTerminal<Self>>;
98}
99
100impl<W: Write> IntoRawMode for W {
101    fn into_raw_mode(self) -> io::Result<RawTerminal<W>> {
102        let mut ios = get_terminal_attr()?;
103        let prev_ios = ios;
104
105        raw_terminal_attr(&mut ios);
106
107        set_terminal_attr(&ios)?;
108
109        Ok(RawTerminal {
110            prev_ios: prev_ios,
111            output: self,
112        })
113    }
114}
115
116impl<W: Write> RawTerminal<W> {
117    /// Temporarily switch to original mode
118    pub fn suspend_raw_mode(&self) -> io::Result<()> {
119        set_terminal_attr(&self.prev_ios)?;
120        Ok(())
121    }
122
123    /// Temporarily switch to raw mode
124    pub fn activate_raw_mode(&self) -> io::Result<()> {
125        let mut ios = get_terminal_attr()?;
126        raw_terminal_attr(&mut ios);
127        set_terminal_attr(&ios)?;
128        Ok(())
129    }
130}
131
132#[cfg(test)]
133mod test {
134    use super::*;
135    use std::io::{stdout, Write};
136
137    #[test]
138    fn test_into_raw_mode() {
139        let mut out = stdout().into_raw_mode().unwrap();
140
141        out.write_all(b"this is a test, muahhahahah\r\n").unwrap();
142
143        drop(out);
144    }
145}