git_worktree_manager/tui/
raw_mode.rs1#![cfg(unix)]
9
10use std::io::Write;
11
12pub(crate) struct RawModeGuard {
13 fd: i32,
14 original_termios: libc::termios,
15 cursor_hidden: bool,
16}
17
18impl RawModeGuard {
19 pub(crate) fn enter(fd: i32, hide_cursor: bool) -> Option<Self> {
23 let mut original_termios: libc::termios = unsafe { std::mem::zeroed() };
24 if unsafe { libc::tcgetattr(fd, &mut original_termios) } != 0 {
25 return None;
26 }
27
28 let mut raw = original_termios;
29 unsafe { libc::cfmakeraw(&mut raw) };
30 if unsafe { libc::tcsetattr(fd, libc::TCSADRAIN, &raw) } != 0 {
31 return None;
32 }
33
34 if hide_cursor {
37 let stderr = std::io::stderr();
38 let mut handle = stderr.lock();
39 let _ = handle.write_all(b"\x1b[?25l");
40 let _ = handle.flush();
41 }
42
43 Some(Self {
44 fd,
45 original_termios,
46 cursor_hidden: hide_cursor,
47 })
48 }
49}
50
51impl Drop for RawModeGuard {
52 fn drop(&mut self) {
53 if self.cursor_hidden {
54 let stderr = std::io::stderr();
55 let mut handle = stderr.lock();
56 let _ = handle.write_all(b"\x1b[?25h");
57 let _ = handle.flush();
58 }
59 unsafe { libc::tcsetattr(self.fd, libc::TCSADRAIN, &self.original_termios) };
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67
68 #[test]
69 fn enter_returns_none_on_bad_fd() {
70 assert!(RawModeGuard::enter(-1, false).is_none());
72 assert!(RawModeGuard::enter(-1, true).is_none());
73 }
74}