Skip to main content

tui/runtime/
terminal.rs

1use crossterm::event::{
2    DisableBracketedPaste, DisableMouseCapture, EnableBracketedPaste, EnableMouseCapture, KeyboardEnhancementFlags,
3    PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags,
4};
5use crossterm::execute;
6use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
7use std::io;
8
9pub fn terminal_size() -> io::Result<(u16, u16)> {
10    crossterm::terminal::size()
11}
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum MouseCapture {
15    Disabled,
16    Enabled,
17}
18
19#[doc = include_str!("../docs/terminal_session.md")]
20pub struct TerminalSession {
21    enable_bracketed_paste: bool,
22    keyboard_enhancement_enabled: bool,
23}
24
25impl TerminalSession {
26    pub fn new(enable_bracketed_paste: bool, mouse_capture: MouseCapture) -> io::Result<Self> {
27        enable_raw_mode()?;
28        let mut stdout = io::stdout();
29        let keyboard_enhancement_enabled =
30            execute!(stdout, PushKeyboardEnhancementFlags(KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES)).is_ok();
31
32        if enable_bracketed_paste {
33            execute!(stdout, EnableBracketedPaste)?;
34        }
35        if mouse_capture == MouseCapture::Enabled {
36            execute!(stdout, EnableMouseCapture)?;
37        }
38
39        Ok(Self { enable_bracketed_paste, keyboard_enhancement_enabled })
40    }
41}
42
43impl Drop for TerminalSession {
44    fn drop(&mut self) {
45        let mut stdout = io::stdout();
46        // Always attempt to disable mouse capture defensively: callers may
47        // toggle capture via RendererCommand after session creation, so the
48        // initial `mouse_capture` field may no longer reflect terminal state.
49        let _ = execute!(stdout, DisableMouseCapture);
50        if self.keyboard_enhancement_enabled {
51            let _ = execute!(stdout, PopKeyboardEnhancementFlags);
52        }
53        if self.enable_bracketed_paste {
54            let _ = execute!(stdout, DisableBracketedPaste);
55        }
56        let _ = disable_raw_mode();
57    }
58}