diff options
Diffstat (limited to 'third_party/rust/termion/src/raw.rs')
-rw-r--r-- | third_party/rust/termion/src/raw.rs | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/third_party/rust/termion/src/raw.rs b/third_party/rust/termion/src/raw.rs new file mode 100644 index 0000000000..5421d56591 --- /dev/null +++ b/third_party/rust/termion/src/raw.rs @@ -0,0 +1,117 @@ +//! Managing raw mode. +//! +//! Raw mode is a particular state a TTY can have. It signifies that: +//! +//! 1. No line buffering (the input is given byte-by-byte). +//! 2. The input is not written out, instead it has to be done manually by the programmer. +//! 3. The output is not canonicalized (for example, `\n` means "go one line down", not "line +//! break"). +//! +//! It is essential to design terminal programs. +//! +//! # Example +//! +//! ```rust,no_run +//! use termion::raw::IntoRawMode; +//! use std::io::{Write, stdout}; +//! +//! fn main() { +//! let mut stdout = stdout().into_raw_mode().unwrap(); +//! +//! write!(stdout, "Hey there.").unwrap(); +//! } +//! ``` + +use std::io::{self, Write}; +use std::ops; + +use sys::Termios; +use sys::attr::{get_terminal_attr, raw_terminal_attr, set_terminal_attr}; + +/// The timeout of an escape code control sequence, in milliseconds. +pub const CONTROL_SEQUENCE_TIMEOUT: u64 = 100; + +/// A terminal restorer, which keeps the previous state of the terminal, and restores it, when +/// dropped. +/// +/// Restoring will entirely bring back the old TTY state. +pub struct RawTerminal<W: Write> { + prev_ios: Termios, + output: W, +} + +impl<W: Write> Drop for RawTerminal<W> { + fn drop(&mut self) { + set_terminal_attr(&self.prev_ios).unwrap(); + } +} + +impl<W: Write> ops::Deref for RawTerminal<W> { + type Target = W; + + fn deref(&self) -> &W { + &self.output + } +} + +impl<W: Write> ops::DerefMut for RawTerminal<W> { + fn deref_mut(&mut self) -> &mut W { + &mut self.output + } +} + +impl<W: Write> Write for RawTerminal<W> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.output.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.output.flush() + } +} + +/// Types which can be converted into "raw mode". +/// +/// # Why is this type defined on writers and not readers? +/// +/// TTYs has their state controlled by the writer, not the reader. You use the writer to clear the +/// screen, move the cursor and so on, so naturally you use the writer to change the mode as well. +pub trait IntoRawMode: Write + Sized { + /// Switch to raw mode. + /// + /// Raw mode means that stdin won't be printed (it will instead have to be written manually by + /// the program). Furthermore, the input isn't canonicalised or buffered (that is, you can + /// read from stdin one byte of a time). The output is neither modified in any way. + fn into_raw_mode(self) -> io::Result<RawTerminal<Self>>; +} + +impl<W: Write> IntoRawMode for W { + fn into_raw_mode(self) -> io::Result<RawTerminal<W>> { + let mut ios = get_terminal_attr()?; + let prev_ios = ios; + + raw_terminal_attr(&mut ios); + + set_terminal_attr(&ios)?; + + Ok(RawTerminal { + prev_ios: prev_ios, + output: self, + }) + } +} + +#[cfg(test)] +mod test { + use super::*; + use std::io::{Write, stdout}; + + #[test] + fn test_into_raw_mode() { + let mut out = stdout().into_raw_mode().unwrap(); + + out.write_all(b"this is a test, muahhahahah\r\n").unwrap(); + + drop(out); + } +} |