1use super::{RawEvent, Transport};
8use crossterm::event::{self as xevent, DisableMouseCapture, EnableMouseCapture, Event};
9use crossterm::execute;
10use crossterm::terminal::{
11 EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode,
12};
13use ratatui::Terminal;
14use ratatui::backend::CrosstermBackend;
15use std::env;
16use std::io::{self, Stdout, Write};
17use std::time::Duration;
18
19pub struct LocalTransport {
20 terminal: Terminal<CrosstermBackend<Stdout>>,
21 term: Option<String>,
22}
23
24impl LocalTransport {
25 pub fn new() -> io::Result<Self> {
34 enable_raw_mode()?;
35 let mut stdout = io::stdout();
36 execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
37 let terminal = Terminal::new(CrosstermBackend::new(stdout))?;
38 Ok(Self {
39 terminal,
40 term: env::var("TERM").ok(),
41 })
42 }
43}
44
45impl Transport for LocalTransport {
46 type Backend = CrosstermBackend<Stdout>;
47
48 fn terminal_mut(&mut self) -> &mut Terminal<Self::Backend> {
49 &mut self.terminal
50 }
51
52 fn poll(&mut self, timeout: Duration) -> io::Result<Option<RawEvent>> {
53 if !xevent::poll(timeout)? {
54 return Ok(None);
55 }
56 match xevent::read()? {
57 Event::Key(key) => Ok(Some(RawEvent::Key(key))),
58 Event::Resize(w, h) => Ok(Some(RawEvent::Resize(w, h))),
59 _ => Ok(None),
60 }
61 }
62
63 fn finish(mut self) -> io::Result<()> {
64 disable_raw_mode()?;
65 execute!(
66 self.terminal.backend_mut(),
67 LeaveAlternateScreen,
68 DisableMouseCapture
69 )?;
70 self.terminal.show_cursor()?;
71 Ok(())
72 }
73
74 fn write_passthrough(&mut self, bytes: &[u8]) -> io::Result<()> {
75 let mut stdout = io::stdout().lock();
76 stdout.write_all(bytes)?;
77 stdout.flush()
78 }
79
80 fn client_term(&self) -> Option<&str> {
81 self.term.as_deref()
82 }
83}