Lines
0 %
Functions
Branches
100 %
//! Local PTY transport.
//!
//! Owns `enable_raw_mode`/`EnterAlternateScreen` in its constructor and
//! tears them down in [`LocalTransport::finish`]. Polls crossterm for
//! key and resize events.
use super::{RawEvent, Transport};
use crossterm::event::{self as xevent, DisableMouseCapture, EnableMouseCapture, Event};
use crossterm::execute;
use crossterm::terminal::{
EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode,
};
use ratatui::Terminal;
use ratatui::backend::CrosstermBackend;
use std::env;
use std::io::{self, Stdout, Write};
use std::time::Duration;
pub struct LocalTransport {
terminal: Terminal<CrosstermBackend<Stdout>>,
term: Option<String>,
}
impl LocalTransport {
/// Enter raw mode + alternate screen and return a transport bound
/// to stdout.
///
/// # Errors
/// Returns `Err` if stdout is not a terminal or the kernel rejects
/// the `TCSETATTR` / escape-sequence writes that raw-mode setup
/// needs.
pub fn new() -> io::Result<Self> {
enable_raw_mode()?;
let mut stdout = io::stdout();
execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
let terminal = Terminal::new(CrosstermBackend::new(stdout))?;
Ok(Self {
terminal,
term: env::var("TERM").ok(),
})
impl Transport for LocalTransport {
type Backend = CrosstermBackend<Stdout>;
fn terminal_mut(&mut self) -> &mut Terminal<Self::Backend> {
&mut self.terminal
fn poll(&mut self, timeout: Duration) -> io::Result<Option<RawEvent>> {
if !xevent::poll(timeout)? {
return Ok(None);
match xevent::read()? {
Event::Key(key) => Ok(Some(RawEvent::Key(key))),
Event::Resize(w, h) => Ok(Some(RawEvent::Resize(w, h))),
_ => Ok(None),
fn finish(mut self) -> io::Result<()> {
disable_raw_mode()?;
execute!(
self.terminal.backend_mut(),
LeaveAlternateScreen,
DisableMouseCapture
)?;
self.terminal.show_cursor()?;
Ok(())
fn write_passthrough(&mut self, bytes: &[u8]) -> io::Result<()> {
let mut stdout = io::stdout().lock();
stdout.write_all(bytes)?;
stdout.flush()
fn client_term(&self) -> Option<&str> {
self.term.as_deref()