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 {
19 value
20 .chars()
21 .filter(|character| matches!(character, '\n' | '\t') || !character.is_control())
22 .collect()
23}
24
25pub(super) fn poll_event() -> Result<Option<Event>> {
26 event::poll(Duration::ZERO)?
27 .then(event::read)
28 .transpose()
29 .map_err(Into::into)
30}
31
32pub(super) struct TerminalGuard {
33 mouse_capture: bool,
34}
35
36impl TerminalGuard {
37 pub(super) fn alternate() -> Result<Self> {
38 enable_raw_mode()?;
39 let guard = Self {
40 mouse_capture: true,
41 };
42 execute!(
43 io::stdout(),
44 EnterAlternateScreen,
45 EnableMouseCapture,
46 EnableBracketedPaste,
47 Hide
48 )?;
49 Ok(guard)
50 }
51
52 pub(super) fn set_mouse_capture(&mut self, enabled: bool) -> Result<()> {
53 if self.mouse_capture == enabled {
54 return Ok(());
55 }
56 if enabled {
57 execute!(io::stdout(), EnableMouseCapture)?;
58 } else {
59 execute!(io::stdout(), DisableMouseCapture)?;
60 }
61 self.mouse_capture = enabled;
62 Ok(())
63 }
64}
65
66impl Drop for TerminalGuard {
67 fn drop(&mut self) {
68 let _ = disable_raw_mode();
69 let _ = execute!(
70 io::stdout(),
71 Show,
72 DisableMouseCapture,
73 DisableBracketedPaste,
74 LeaveAlternateScreen
75 );
76 }
77}