aboutsummaryrefslogtreecommitdiff
path: root/src/pane.rs
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-05-28 04:11:56 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-05-28 04:12:53 +0300
commitbf9cc201244946496b4d950046bf7edcc4892994 (patch)
tree920c866e67783cf31d2feff9642457204999c8eb /src/pane.rs
parent789738cada5afaa20bbd77a0d479fb689c455bfe (diff)
fix: preserve live handoff terminal state
Diffstat (limited to 'src/pane.rs')
-rw-r--r--src/pane.rs76
1 files changed, 55 insertions, 21 deletions
diff --git a/src/pane.rs b/src/pane.rs
index 77249de8..11d6e03c 100644
--- a/src/pane.rs
+++ b/src/pane.rs
@@ -16,6 +16,7 @@ use crate::events::AppEvent;
use crate::layout::PaneId;
mod input;
+mod kitty_keyboard;
mod osc;
mod state;
mod terminal;
@@ -493,19 +494,6 @@ pub struct PaneRuntime {
detect_handle: tokio::task::AbortHandle,
}
-#[cfg(unix)]
-#[derive(Debug)]
-pub struct PaneRuntimeImport {
- pub pane_id: PaneId,
- pub master_fd: std::os::fd::RawFd,
- pub child_pid: u32,
- pub rows: u16,
- pub cols: u16,
- pub cell_width_px: u32,
- pub cell_height_px: u32,
- pub initial_history_ansi: Option<String>,
-}
-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WheelRouting {
HostScroll,
@@ -835,16 +823,25 @@ impl PaneRuntime {
}
#[cfg(unix)]
- pub fn handoff_pane(&self, pane_id: u32) -> crate::server::handoff::HandoffPane {
+ pub fn handoff_runtime_state(
+ &self,
+ pane_id: u32,
+ ) -> crate::handoff_runtime::HandoffRuntimeState {
let child_pid = self.child_pid.load(Ordering::Acquire);
let (rows, cols, cell_width_px, cell_height_px) = self.current_size.get();
- crate::server::handoff::HandoffPane {
+ crate::handoff_runtime::HandoffRuntimeState {
pane_id,
child_pid,
rows,
cols,
cell_width_px,
cell_height_px,
+ keyboard_protocol_flags: match self.keyboard_protocol() {
+ crate::input::KeyboardProtocol::Legacy => 0,
+ crate::input::KeyboardProtocol::Kitty { flags } => flags,
+ },
+ keyboard_protocol_ansi: self.terminal.kitty_keyboard_state_ansi(),
+ input_state: self.input_state(),
initial_history_ansi: None,
}
}
@@ -1057,23 +1054,27 @@ impl PaneRuntime {
#[cfg(unix)]
pub fn from_handoff_fd(
- import: PaneRuntimeImport,
+ import: crate::handoff_runtime::ImportedHandoffRuntime,
scrollback_limit_bytes: usize,
host_terminal_theme: crate::terminal_theme::TerminalTheme,
events: mpsc::Sender<AppEvent>,
render_notify: Arc<Notify>,
render_dirty: Arc<AtomicBool>,
) -> std::io::Result<Self> {
- let PaneRuntimeImport {
+ let crate::handoff_runtime::ImportedHandoffRuntime { master_fd, state } = import;
+ let crate::handoff_runtime::HandoffRuntimeState {
pane_id,
- master_fd,
child_pid,
rows,
cols,
cell_width_px,
cell_height_px,
+ keyboard_protocol_flags,
+ keyboard_protocol_ansi,
+ input_state,
initial_history_ansi,
- } = import;
+ } = state;
+ let pane_id = PaneId::from_raw(pane_id);
use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd};
let master_fd = unsafe { std::os::fd::OwnedFd::from_raw_fd(master_fd) };
@@ -1099,12 +1100,20 @@ impl PaneRuntime {
}
let pane_terminal = GhosttyPaneTerminal::new(terminal, input_tx.clone())?;
pane_terminal.apply_host_terminal_theme(host_terminal_theme);
+ if let Some(input_state) = input_state {
+ pane_terminal.seed_handoff_input_state(input_state);
+ }
+ if let Some(ansi) = keyboard_protocol_ansi.as_deref() {
+ pane_terminal.seed_keyboard_protocol_ansi(ansi);
+ } else {
+ pane_terminal.seed_keyboard_protocol_flags(keyboard_protocol_flags);
+ }
if let Some(ansi) = initial_history_ansi.as_deref() {
pane_terminal.seed_history_ansi(ansi);
}
let terminal = Arc::new(PaneTerminal::new(pane_terminal));
let child_pid = Arc::new(AtomicU32::new(child_pid));
- let kitty_keyboard_flags = Arc::new(AtomicU16::new(0));
+ let kitty_keyboard_flags = Arc::new(AtomicU16::new(keyboard_protocol_flags));
let (reader_stopped_tx, reader_stopped_rx) = std::sync::mpsc::channel();
{
@@ -1790,7 +1799,6 @@ impl PaneRuntime {
self.detect_reset_notify.notify_one();
}
- #[cfg(test)]
pub(crate) fn current_size(&self) -> (u16, u16) {
let (rows, cols, _, _) = self.current_size.get();
(rows, cols)
@@ -2220,6 +2228,32 @@ mod tests {
assert!(runtime.handoff_history_ansi().is_none());
}
+ #[tokio::test]
+ async fn handoff_runtime_state_captures_terminal_input_state() {
+ let runtime = PaneRuntime::test_with_screen_bytes(
+ 80,
+ 24,
+ b"\x1b[>5u\x1b[>4;2m\x1b[?1h\x1b[?2004h\x1b[?1004h\x1b[?1002h\x1b[?1006h",
+ );
+
+ let pane = runtime.handoff_runtime_state(12);
+
+ assert_eq!(pane.keyboard_protocol_flags, 5);
+ assert_eq!(
+ pane.input_state,
+ Some(InputState {
+ alternate_screen: false,
+ application_cursor: true,
+ bracketed_paste: true,
+ focus_reporting: true,
+ mouse_protocol_mode: crate::input::MouseProtocolMode::ButtonMotion,
+ mouse_protocol_encoding: crate::input::MouseProtocolEncoding::Sgr,
+ mouse_alternate_scroll: true,
+ modify_other_keys: true,
+ })
+ );
+ }
+
#[test]
fn truncate_handoff_history_keeps_recent_utf8_boundary() {
let history = format!("old\n{}\nrecent\n", "é".repeat(8));