89 lines
3.6 KiB
Rust
89 lines
3.6 KiB
Rust
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<u8>, u32),
|
|
ResizePty(u32, u16, u16, Option<u16>, Option<u16>), // 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<PtyWriteInstruction>) -> 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(());
|
|
},
|
|
}
|
|
}
|
|
}
|