tvscreener/tui/
terminal.rs1use std::env;
7use std::io::{self, stdout, Write};
8use std::sync::atomic::{AtomicBool, Ordering};
9
10use crossterm::cursor;
11use crossterm::event::{KeyCode, KeyModifiers};
12use crossterm::terminal::{
13 disable_raw_mode, enable_raw_mode, Clear, ClearType, EnterAlternateScreen, LeaveAlternateScreen,
14};
15use crossterm::ExecutableCommand;
16
17pub static STOP: AtomicBool = AtomicBool::new(false);
19
20pub struct TerminalGuard {
22 use_alt: bool,
23}
24
25impl TerminalGuard {
26 pub fn enter(use_alt: bool) -> io::Result<Self> {
32 enable_raw_mode()?;
33 let mut out = stdout();
34 if use_alt {
35 out.execute(EnterAlternateScreen)?;
36 }
37 hard_reset_tty();
38 out.execute(cursor::Hide)?;
39 out.flush()?;
40 Ok(Self { use_alt })
41 }
42}
43
44impl Drop for TerminalGuard {
45 fn drop(&mut self) {
46 restore_terminal(self.use_alt);
47 }
48}
49
50#[must_use]
52pub fn inside_gnu_screen() -> bool {
53 env::var_os("STY").is_some()
54}
55
56#[must_use]
58pub const fn is_quit_key(code: KeyCode, modifiers: KeyModifiers) -> bool {
59 matches!(code, KeyCode::Char('q') | KeyCode::Esc)
60 || (matches!(code, KeyCode::Char('c')) && modifiers.contains(KeyModifiers::CONTROL))
61}
62
63pub fn install_signal_handlers() {
65 let _ = ctrlc::set_handler(|| {
66 STOP.store(true, Ordering::SeqCst);
67 });
68}
69
70pub fn install_panic_hook() {
72 let use_alt = !inside_gnu_screen();
73 let prior = std::panic::take_hook();
74 std::panic::set_hook(Box::new(move |info| {
75 restore_terminal(use_alt);
76 prior(info);
77 }));
78}
79
80pub fn hard_reset_tty() {
82 let mut out = stdout();
83 let _ = write!(
84 out,
85 "\x1b[0m\x1b[?25h\x1b[?1049l\x1b[?47l\x1b[2J\x1b[3J\x1b[H"
86 );
87 let _ = out.execute(Clear(ClearType::All));
88 let _ = out.execute(Clear(ClearType::Purge));
89 let _ = out.execute(cursor::Show);
90 let _ = out.flush();
91}
92
93fn restore_terminal(use_alt: bool) {
94 let _ = disable_raw_mode();
95 let mut out = stdout();
96 if use_alt {
97 let _ = out.execute(LeaveAlternateScreen);
98 }
99 let _ = out.flush();
100 hard_reset_tty();
101}