/// Helper functions, especially to reproduce C std/posix functions use nix::errno::*; use nix::sys::termios; use nix::sys::termios::{ ControlFlags, InputFlags, LocalFlags, OutputFlags, SpecialCharacterIndices, Termios, }; use nix::Error as NixError; use std::io::Error; use std::os::unix::io::RawFd; use std::process::exit; // Redefine the posix constants for rust land /// The value of the raw file descriptor for STDIN pub const STDIN_FILENO: i32 = 0; // pub const STDOUT_FILENO: i32 = 1; // pub const STDERR_FILENO: i32 = 2; /// Convert Ctrl+letter chords to their /// ASCII table equivalents #[inline] pub fn ctrl_key(c: char) -> char { let key = c as u8; if !c.is_ascii() { panic!("CTRL_KEY only accepts ASCII characters"); } // Intentionally "overflow" u8 to wrap around to the // beginning of the ASCII table. Ctrl+a is 1, Ctrl+b is 2, etc. (key & 0x1f) as char } pub fn die(code: &Errno, msg: &str) -> ! { eprintln!("{:?} ({})", code, msg); exit(1) } /// Get a `Termios` struct, for getting/setting terminal flags pub fn get_termios(fd: RawFd) -> Termios { termios::tcgetattr(fd).unwrap() } /// Put terminal into raw mode so there is full control of terminal output pub fn enable_raw_mode() { let mut raw = get_termios(STDIN_FILENO); raw.input_flags.remove( InputFlags::BRKINT | InputFlags::IGNCR | InputFlags::IGNBRK | InputFlags::ICRNL | InputFlags::INLCR | InputFlags::INPCK | InputFlags::ISTRIP | InputFlags::IXON | InputFlags::PARMRK, ); raw.output_flags.remove(OutputFlags::OPOST); raw.local_flags.remove( LocalFlags::ECHO | LocalFlags::ECHONL | LocalFlags::ICANON | LocalFlags::IEXTEN | LocalFlags::ISIG, ); raw.control_flags .remove(ControlFlags::CSIZE | ControlFlags::PARENB); // 8 bit characters raw.control_flags |= termios::ControlFlags::CS8; raw.control_chars[SpecialCharacterIndices::VMIN as usize] = 0; raw.control_chars[SpecialCharacterIndices::VTIME as usize] = 1; // Raw mode or bust! termios::tcsetattr(STDIN_FILENO, termios::SetArg::TCSAFLUSH, &raw).unwrap(); } /// Restore terminal to "cooked"/canonical mode pub fn disable_raw_mode(original: &Termios) { termios::tcsetattr(STDIN_FILENO, termios::SetArg::TCSAFLUSH, original).unwrap(); }