Keep terminal focus reports local

This commit is contained in:
DuProcess
2026-07-07 14:57:53 -04:00
parent 37ec9fc520
commit f4879090f6
+39 -3
View File
@@ -4401,8 +4401,9 @@ async fn run_terminal(
if input_matches_escape(&bytes, escape_key.as_deref()) { if input_matches_escape(&bytes, escape_key.as_deref()) {
break; break;
} }
let saw_focus_in = input_contains_focus_in(&bytes);
if !forward_only if !forward_only
&& input_contains_focus_in(&bytes) && saw_focus_in
&& last_focus_repaint_at.elapsed() >= FOCUS_REPAINT_COOLDOWN && last_focus_repaint_at.elapsed() >= FOCUS_REPAINT_COOLDOWN
{ {
last_focus_repaint_at = Instant::now(); last_focus_repaint_at = Instant::now();
@@ -4436,6 +4437,10 @@ async fn run_terminal(
.await?; .await?;
} }
} }
bytes = strip_terminal_focus_reports(&bytes);
if bytes.is_empty() {
continue;
}
if should_strip_stale_terminal_reports( if should_strip_stale_terminal_reports(
last_packet_at.elapsed(), last_packet_at.elapsed(),
stale_terminal_input_suppress_until, stale_terminal_input_suppress_until,
@@ -5641,6 +5646,26 @@ fn input_contains_focus_in(bytes: &[u8]) -> bool {
contains_bytes(bytes, b"\x1b[I") || contains_bytes(bytes, b"\x9bI") contains_bytes(bytes, b"\x1b[I") || contains_bytes(bytes, b"\x9bI")
} }
fn strip_terminal_focus_reports(bytes: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(bytes.len());
let mut offset = 0;
while offset < bytes.len() {
match bytes.get(offset..) {
Some([0x1b, b'[', b'I' | b'O', ..]) => {
offset += 3;
}
Some([0x9b, b'I' | b'O', ..]) => {
offset += 2;
}
_ => {
out.push(bytes[offset]);
offset += 1;
}
}
}
out
}
fn should_repaint_idle_alternate_screen( fn should_repaint_idle_alternate_screen(
alternate_screen: bool, alternate_screen: bool,
last_terminal_frame_at: Instant, last_terminal_frame_at: Instant,
@@ -7347,8 +7372,8 @@ mod tests {
should_hold_during_startup_gate, should_hold_post_submit_input, should_hold_during_startup_gate, should_hold_post_submit_input,
should_repaint_idle_alternate_screen, split_after_command_submit, ssh_destination_host, should_repaint_idle_alternate_screen, split_after_command_submit, ssh_destination_host,
ssh_username, ssh_with_user, startup_command, status_ssh_target, strip_stale_mouse_reports, ssh_username, ssh_with_user, startup_command, status_ssh_target, strip_stale_mouse_reports,
toml_bare_key_or_quoted, update_check_requested, update_version_status, strip_terminal_focus_reports, toml_bare_key_or_quoted, update_check_requested,
upsert_managed_block, valid_forward_host, vscode_safe_alias, update_version_status, upsert_managed_block, valid_forward_host, vscode_safe_alias,
}; };
use dosh::config::{ClientConfig, CommandExtension, HostConfig}; use dosh::config::{ClientConfig, CommandExtension, HostConfig};
use dosh::native::EnvVar; use dosh::native::EnvVar;
@@ -8661,6 +8686,17 @@ mod tests {
assert!(!input_contains_focus_in(b"\x1b[A")); assert!(!input_contains_focus_in(b"\x1b[A"));
} }
#[test]
fn focus_reports_are_never_forwarded_as_user_input() {
assert_eq!(strip_terminal_focus_reports(b"\x1b[Ihello\x1b[O"), b"hello");
assert_eq!(strip_terminal_focus_reports(b"\x9bIhello\x9bO"), b"hello");
assert_eq!(strip_terminal_focus_reports(b"\x1b[A"), b"\x1b[A");
assert_eq!(
strip_terminal_focus_reports(b"before\x1b[Iafter"),
b"beforeafter"
);
}
#[test] #[test]
fn idle_repaint_only_runs_for_stale_alternate_screen() { fn idle_repaint_only_runs_for_stale_alternate_screen() {
let now = Instant::now(); let now = Instant::now();