use zellij_utils::errors::{prelude::*, ContextType, PtyWriteContext}; use crate::thread_bus::Bus; // we separate these instruction to a different thread because some programs get deadlocked if // you write into their STDIN while reading from their STDOUT (I'm looking at you, vim) // while the same has not been observed to happen with resizes, it could conceivably happen and we have this // here anyway, so #[derive(Debug, Clone, Eq, PartialEq)] pub enum PtyWriteInstruction { Write(Vec, u32), ResizePty(u32, u16, u16, Option, Option), // terminal_id, columns, rows, pixel width, pixel height StartCachingResizes, ApplyCachedResizes, Exit, } impl From<&PtyWriteInstruction> for PtyWriteContext { fn from(tty_write_instruction: &PtyWriteInstruction) -> Self { match *tty_write_instruction { PtyWriteInstruction::Write(..) => PtyWriteContext::Write, PtyWriteInstruction::ResizePty(..) => PtyWriteContext::ResizePty, PtyWriteInstruction::ApplyCachedResizes => PtyWriteContext::ApplyCachedResizes, PtyWriteInstruction::StartCachingResizes => PtyWriteContext::StartCachingResizes, PtyWriteInstruction::Exit => PtyWriteContext::Exit, } } } pub(crate) fn pty_writer_main(bus: Bus) -> Result<()> { let err_context = || "failed to write to pty".to_string(); loop { let (event, mut err_ctx) = bus.recv().with_context(err_context)?; err_ctx.add_call(ContextType::PtyWrite((&event).into())); let mut os_input = bus .os_input .clone() .context("no OS input API found") .with_context(err_context)?; match event { PtyWriteInstruction::Write(bytes, terminal_id) => { os_input .write_to_tty_stdin(terminal_id, &bytes) .with_context(err_context) .non_fatal(); os_input .tcdrain(terminal_id) .with_context(err_context) .non_fatal(); }, PtyWriteInstruction::ResizePty( terminal_id, columns, rows, width_in_pixels, height_in_pixels, ) => { os_input .set_terminal_size_using_terminal_id( terminal_id, columns, rows, width_in_pixels, height_in_pixels, ) .with_context(err_context) .non_fatal(); }, PtyWriteInstruction::StartCachingResizes => { // we do this because there are some logic traps inside the screen/tab/layout code // the cause multiple resizes to be sent to the pty - while the last one is always // the correct one, many programs and shells debounce those (I guess due to the // trauma of dealing with GUI resizes of the controlling terminal window), and this // then causes glitches and missing redraws // so we do this to play nice and always only send the last resize instruction to // each pane // the logic for this happens in the main Screen event loop os_input.cache_resizes(); }, PtyWriteInstruction::ApplyCachedResizes => { os_input.apply_cached_resizes(); }, PtyWriteInstruction::Exit => { return Ok(()); }, } } }