mobius_cli/frontend/
terminal.rs1use std::io;
2use std::time::Duration;
3
4use mobius::Result;
5use ratatui::crossterm::cursor::{Hide, Show};
6use ratatui::crossterm::event::{
7 self, DisableBracketedPaste, DisableMouseCapture, EnableBracketedPaste, EnableMouseCapture,
8 Event,
9};
10use ratatui::crossterm::execute;
11use ratatui::crossterm::terminal::{
12 EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode,
13};
14
15pub(super) const INPUT_POLL: Duration = Duration::from_millis(16);
16pub(super) const MAX_INPUT_BATCH: usize = 64;
17
18pub fn terminal_text(value: &str) -> String {
20 value
21 .chars()
22 .filter(|character| matches!(character, '\n' | '\t') || !character.is_control())
23 .collect()
24}
25
26pub(super) fn poll_event() -> Result<Option<Event>> {
27 event::poll(Duration::ZERO)?
28 .then(event::read)
29 .transpose()
30 .map_err(Into::into)
31}
32
33pub(super) struct TerminalGuard {
34 mouse_capture: bool,
35}
36
37impl TerminalGuard {
38 pub(super) fn alternate() -> Result<Self> {
39 enable_raw_mode()?;
40 let guard = Self {
41 mouse_capture: true,
42 };
43 execute!(
44 io::stdout(),
45 EnterAlternateScreen,
46 EnableMouseCapture,
47 EnableBracketedPaste,
48 Hide
49 )?;
50 Ok(guard)
51 }
52
53 pub(super) fn set_mouse_capture(&mut self, enabled: bool) -> Result<()> {
54 if self.mouse_capture == enabled {
55 return Ok(());
56 }
57 if enabled {
58 execute!(io::stdout(), EnableMouseCapture)?;
59 } else {
60 execute!(io::stdout(), DisableMouseCapture)?;
61 }
62 self.mouse_capture = enabled;
63 Ok(())
64 }
65}
66
67impl Drop for TerminalGuard {
68 fn drop(&mut self) {
69 let _ = disable_raw_mode();
70 let _ = execute!(
71 io::stdout(),
72 Show,
73 DisableMouseCapture,
74 DisableBracketedPaste,
75 LeaveAlternateScreen
76 );
77 }
78}