muster/adapter/tui/
terminal.rs1use std::io::{self, Stdout};
2
3use crossterm::{
4 clipboard::CopyToClipboard,
5 event::{DisableMouseCapture, EnableMouseCapture},
6 execute,
7 style::Print,
8 terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode},
9};
10use getset::MutGetters;
11use ratatui::{Terminal, backend::CrosstermBackend};
12
13use super::pointer_shape::PointerShape;
14use crate::{adapter::clipboard, error::Result};
15
16const POINTER_SHAPE_PREFIX: &str = "\x1b]22;";
18const OSC_TERMINATOR: &str = "\x1b\\";
20
21pub type Tui = Terminal<CrosstermBackend<Stdout>>;
23
24#[derive(MutGetters)]
27pub struct TerminalGuard {
28 #[getset(get_mut = "pub")]
29 terminal: Tui,
30}
31
32impl TerminalGuard {
33 pub fn new() -> Result<Self> {
40 enable_raw_mode()?;
41 let mut stdout = io::stdout();
42 if let Err(error) = execute!(stdout, EnterAlternateScreen, EnableMouseCapture) {
43 let _ = Self::restore();
44 return Err(error.into());
45 }
46 match Terminal::new(CrosstermBackend::new(stdout)) {
47 Ok(terminal) => Ok(Self { terminal }),
48 Err(error) => {
49 let _ = Self::restore();
50 Err(error.into())
51 },
52 }
53 }
54
55 pub fn copy_to_clipboard(&mut self, text: &str) -> io::Result<()> {
62 if clipboard::write_native(text) {
63 return Ok(());
64 }
65 execute!(io::stdout(), CopyToClipboard::to_clipboard_from(text))
66 }
67
68 pub fn set_pointer_shape(&mut self, shape: PointerShape) -> io::Result<()> {
73 execute!(
74 io::stdout(),
75 Print(format!("{POINTER_SHAPE_PREFIX}{shape}{OSC_TERMINATOR}"))
76 )
77 }
78
79 pub fn restore() -> io::Result<()> {
86 let raw = disable_raw_mode();
87 let mouse = execute!(io::stdout(), DisableMouseCapture);
88 let pointer = execute!(
89 io::stdout(),
90 Print(format!(
91 "{POINTER_SHAPE_PREFIX}{}{OSC_TERMINATOR}",
92 PointerShape::Default
93 ))
94 );
95 let screen = execute!(io::stdout(), LeaveAlternateScreen);
96 raw.and(mouse).and(pointer).and(screen)
97 }
98}
99
100impl Drop for TerminalGuard {
101 fn drop(&mut self) {
102 let _ = Self::restore();
103 }
104}