//! # Helpers //! //! Various functions calling C wrappers to get/set terminal functionality use nix::libc::ioctl; use nix::libc::{c_ushort, STDIN_FILENO, STDOUT_FILENO, TIOCGWINSZ}; use nix::sys::termios; use nix::sys::termios::{ ControlFlags, InputFlags, LocalFlags, OutputFlags, SpecialCharacterIndices, Termios, }; use std::os::unix::io::RawFd; use std::sync::Arc; #[derive(Debug)] pub struct TermSize { /// number of rows pub rows: u16, /// number of columns pub cols: u16, } /// 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() { // 'Access' the saved termios instance, to make sure it is set // before you enable raw mode. let mutex = Arc::clone(&super::ORIGINAL_TERMIOS); mutex.lock().unwrap(); let mut raw = get_termios(STDOUT_FILENO); raw.input_flags.remove( InputFlags::BRKINT | InputFlags::ICRNL | InputFlags::INPCK | InputFlags::ISTRIP | InputFlags::IXON, ); raw.output_flags.remove(OutputFlags::OPOST); // 8 bit characters raw.control_flags |= ControlFlags::CS8; raw.local_flags .remove(LocalFlags::ECHO | LocalFlags::ICANON | LocalFlags::IEXTEN | LocalFlags::ISIG); 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() { let mutex = Arc::clone(&super::ORIGINAL_TERMIOS); let termios = mutex.lock().unwrap(); // First attempt to reset terminal settings via a terminal code print!("\x1bc"); // Restore previous terminal settings termios::tcsetattr(STDIN_FILENO, termios::SetArg::TCSAFLUSH, &termios).unwrap(); } /// Attempt to get the size of the terminal (in rows and columns) from an `ioctl` call #[inline] pub fn get_term_size() -> Option { #[repr(C)] #[derive(Debug)] struct UnixTermSize { /// number of rows pub rows: c_ushort, /// number of columns pub cols: c_ushort, x: c_ushort, y: c_ushort, } let raw = UnixTermSize { rows: 0, cols: 0, x: 0, y: 0, }; let r = unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ.into(), &raw) }; if r == 0 { Some(TermSize { rows: raw.rows, cols: raw.cols, }) } else { None } }