1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use lazy_static::lazy_static;
use libc::{cfmakeraw, tcgetattr, tcsetattr, termios as Termios, STDIN_FILENO, TCSANOW};
use std::{io, sync::Mutex};
pub use termion::cursor::Goto;
pub use termion::cursor::Hide as HideCursor;
pub use termion::cursor::Show as ShowCursor;
pub use termion::screen::ToAlternateScreen;
pub use termion::screen::ToMainScreen;
pub use termion::clear::AfterCursor as ClearAfterCursor;
pub use termion::clear::All as ClearAll;
pub use termion::clear::CurrentLine as ClearCurrentLine;
pub use termion::clear::UntilNewline as ClearUntilNewline;
type Result<T> = std::result::Result<T, io::Error>;
lazy_static! {
static ref TERMINAL_MODE_PRIOR_RAW_MODE: Mutex<Option<Termios>> = Mutex::new(None);
}
pub fn is_raw_mode_enabled() -> bool {
TERMINAL_MODE_PRIOR_RAW_MODE.lock().unwrap().is_some()
}
pub fn enable_raw_mode() -> Result<()> {
let mut original_mode = TERMINAL_MODE_PRIOR_RAW_MODE.lock().unwrap();
if original_mode.is_some() {
return Ok(());
}
let mut ios = get_terminal_attr()?;
let original_mode_ios = ios;
raw_terminal_attr(&mut ios);
set_terminal_attr(&ios)?;
*original_mode = Some(original_mode_ios);
Ok(())
}
pub fn disable_raw_mode() -> Result<()> {
let mut original_mode = TERMINAL_MODE_PRIOR_RAW_MODE.lock().unwrap();
if let Some(original_mode_ios) = original_mode.as_ref() {
set_terminal_attr(original_mode_ios)?;
*original_mode = None;
}
Ok(())
}
fn raw_terminal_attr(termios: &mut Termios) {
unsafe { cfmakeraw(termios) }
}
fn get_terminal_attr() -> Result<Termios> {
unsafe {
let mut termios = std::mem::zeroed();
wrap_with_result(tcgetattr(STDIN_FILENO, &mut termios))?;
Ok(termios)
}
}
fn set_terminal_attr(termios: &Termios) -> Result<bool> {
wrap_with_result(unsafe { tcsetattr(STDIN_FILENO, TCSANOW, termios) })
}
fn wrap_with_result(result: i32) -> Result<bool> {
if result == -1 {
Err(io::Error::last_os_error())
} else {
Ok(true)
}
}