use crate::tmux::{RefTmuxRemotePane, TmuxCmdQueue, TmuxDomainState}; use crate::tmux_commands::SendKeys; use crate::DomainId; use filedescriptor::FileDescriptor; use portable_pty::{Child, ChildKiller, ExitStatus, MasterPty}; use std::io::{Read, Write}; use std::sync::{Arc, Condvar, Mutex}; /// A local tmux pane(tab) based on a tmux pty #[derive(Debug)] pub(crate) struct TmuxPty { pub domain_id: DomainId, pub master_pane: RefTmuxRemotePane, pub reader: FileDescriptor, pub cmd_queue: Arc>, } struct TmuxPtyWriter { domain_id: DomainId, master_pane: RefTmuxRemotePane, cmd_queue: Arc>, } impl Write for TmuxPtyWriter { fn write(&mut self, buf: &[u8]) -> std::io::Result { let pane_id = { let pane_lock = self.master_pane.lock().unwrap(); pane_lock.pane_id }; log::trace!("pane:{}, content:{:?}", &pane_id, buf); let mut cmd_queue = self.cmd_queue.lock().unwrap(); cmd_queue.push_back(Box::new(SendKeys { pane: pane_id, keys: buf.to_vec(), })); TmuxDomainState::schedule_send_next_command(self.domain_id); Ok(0) } fn flush(&mut self) -> std::io::Result<()> { Ok(()) } } impl Write for TmuxPty { fn write(&mut self, buf: &[u8]) -> std::io::Result { let pane_id = { let pane_lock = self.master_pane.lock().unwrap(); pane_lock.pane_id }; log::trace!("pane:{}, content:{:?}", &pane_id, buf); let mut cmd_queue = self.cmd_queue.lock().unwrap(); cmd_queue.push_back(Box::new(SendKeys { pane: pane_id, keys: buf.to_vec(), })); TmuxDomainState::schedule_send_next_command(self.domain_id); Ok(0) } fn flush(&mut self) -> std::io::Result<()> { Ok(()) } } #[derive(Clone, Debug)] pub(crate) struct TmuxChild { pub active_lock: Arc<(Mutex, Condvar)>, } impl Child for TmuxChild { fn try_wait(&mut self) -> std::io::Result> { todo!() } fn wait(&mut self) -> std::io::Result { let (lock, var) = &*self.active_lock; let mut released = lock.lock().unwrap(); while !*released { released = var.wait(released).unwrap(); } return Ok(ExitStatus::with_exit_code(0)); } fn process_id(&self) -> Option { Some(0) } #[cfg(windows)] fn as_raw_handle(&self) -> Option { None } } #[derive(Clone, Debug)] struct TmuxChildKiller {} impl ChildKiller for TmuxChildKiller { fn kill(&mut self) -> std::io::Result<()> { Err(std::io::Error::new( std::io::ErrorKind::Other, "TmuxChildKiller: kill not implemented!", )) } fn clone_killer(&self) -> Box { Box::new(self.clone()) } } impl ChildKiller for TmuxChild { fn kill(&mut self) -> std::io::Result<()> { Err(std::io::Error::new( std::io::ErrorKind::Other, "TmuxPty: kill not implemented!", )) } fn clone_killer(&self) -> Box { Box::new(TmuxChildKiller {}) } } impl MasterPty for TmuxPty { fn resize(&self, size: portable_pty::PtySize) -> Result<(), anyhow::Error> { log::warn!("TODO: perform pane resize"); Ok(()) } fn get_size(&self) -> Result { let pane = self.master_pane.lock().unwrap(); Ok(portable_pty::PtySize { rows: pane.pane_height as u16, cols: pane.pane_width as u16, pixel_width: 0, pixel_height: 0, }) } fn try_clone_reader(&self) -> Result, anyhow::Error> { Ok(Box::new(self.reader.try_clone()?)) } fn try_clone_writer(&self) -> Result, anyhow::Error> { Ok(Box::new(TmuxPtyWriter { domain_id: self.domain_id, master_pane: self.master_pane.clone(), cmd_queue: self.cmd_queue.clone(), })) } #[cfg(unix)] fn process_group_leader(&self) -> Option { return None; } }