use portable_pty::{native_pty_system, CommandBuilder, MasterPty, PtySize};
use std::io::{Read, Write};
use std::sync::{Arc, Mutex};
pub struct Pty {
pub writer: Arc<Mutex<Box<dyn Write + Send>>>,
master: Arc<Mutex<Box<dyn MasterPty + Send>>>,
child: Arc<Mutex<Box<dyn portable_pty::Child + Send + Sync>>>,
}
impl Pty {
pub fn spawn(cols: u16, rows: u16) -> anyhow::Result<Self> {
let pty_system = native_pty_system();
let pair = pty_system.openpty(PtySize {
rows,
cols,
pixel_width: 0,
pixel_height: 0,
})?;
let mut cmd = CommandBuilder::new_default_prog();
cmd.env("TERM", "xterm-256color");
let child = pair.slave.spawn_command(cmd)?;
let writer = pair.master.take_writer()?;
Ok(Self {
writer: Arc::new(Mutex::new(writer)),
master: Arc::new(Mutex::new(pair.master)),
child: Arc::new(Mutex::new(child)),
})
}
pub fn child_arc(&self) -> Arc<Mutex<Box<dyn portable_pty::Child + Send + Sync>>> {
self.child.clone()
}
pub fn master_arc(&self) -> Arc<Mutex<Box<dyn MasterPty + Send>>> {
self.master.clone()
}
pub fn clone_reader(&self) -> anyhow::Result<Box<dyn Read + Send>> {
let master = self.master.lock()
.map_err(|e| anyhow::anyhow!("master mutex poisoned: {}", e))?;
master.try_clone_reader().map_err(|e| anyhow::anyhow!("{}", e))
}
}