hh_cli/cli/tui/
terminal.rs1use std::io::{self, Stdout};
2
3use crossterm::{
4 event::{
5 DisableBracketedPaste, DisableMouseCapture, EnableBracketedPaste, EnableMouseCapture,
6 KeyboardEnhancementFlags, PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags,
7 },
8 execute,
9 terminal::{
10 Clear, ClearType, EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode,
11 enable_raw_mode,
12 },
13};
14use ratatui::{Terminal, backend::CrosstermBackend};
15
16pub type Tui = Terminal<CrosstermBackend<Stdout>>;
17
18fn keyboard_enhancement_flags() -> KeyboardEnhancementFlags {
19 KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES
20}
21
22pub fn setup_terminal() -> io::Result<Tui> {
24 enable_raw_mode()?;
25 let mut stdout = io::stdout();
26 execute!(
27 stdout,
28 EnterAlternateScreen,
29 EnableMouseCapture,
30 EnableBracketedPaste,
31 Clear(ClearType::All)
32 )?;
33 let _ = execute!(
34 stdout,
35 PushKeyboardEnhancementFlags(keyboard_enhancement_flags())
36 );
37 let backend = CrosstermBackend::new(stdout);
38 Terminal::new(backend)
39}
40
41pub fn restore_terminal(terminal: &mut Tui) -> io::Result<()> {
43 disable_raw_mode()?;
44 let _ = execute!(terminal.backend_mut(), PopKeyboardEnhancementFlags);
45 execute!(
46 terminal.backend_mut(),
47 LeaveAlternateScreen,
48 DisableMouseCapture,
49 DisableBracketedPaste
50 )?;
51 terminal.show_cursor()?;
52 Ok(())
53}
54
55pub struct TuiGuard {
57 terminal: Tui,
58}
59
60impl TuiGuard {
61 pub fn new(terminal: Tui) -> Self {
62 Self { terminal }
63 }
64
65 pub fn get(&mut self) -> &mut Tui {
66 &mut self.terminal
67 }
68}
69
70impl Drop for TuiGuard {
71 fn drop(&mut self) {
72 let _ = restore_terminal(&mut self.terminal);
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn keyboard_enhancements_enable_escape_disambiguation() {
82 assert!(
83 keyboard_enhancement_flags()
84 .contains(KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES)
85 );
86 }
87}