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()) {
break;
}
let saw_focus_in = input_contains_focus_in(&bytes);
if !forward_only
&& input_contains_focus_in(&bytes)
&& saw_focus_in
&& last_focus_repaint_at.elapsed() >= FOCUS_REPAINT_COOLDOWN
{
last_focus_repaint_at = Instant::now();
@@ -4436,6 +4437,10 @@ async fn run_terminal(
.await?;
}
}
bytes = strip_terminal_focus_reports(&bytes);
if bytes.is_empty() {
continue;
}
if should_strip_stale_terminal_reports(
last_packet_at.elapsed(),
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")
}
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(
alternate_screen: bool,
last_terminal_frame_at: Instant,
@@ -7347,8 +7372,8 @@ mod tests {
should_hold_during_startup_gate, should_hold_post_submit_input,
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,
toml_bare_key_or_quoted, update_check_requested, update_version_status,
upsert_managed_block, valid_forward_host, vscode_safe_alias,
strip_terminal_focus_reports, toml_bare_key_or_quoted, update_check_requested,
update_version_status, upsert_managed_block, valid_forward_host, vscode_safe_alias,
};
use dosh::config::{ClientConfig, CommandExtension, HostConfig};
use dosh::native::EnvVar;
@@ -8661,6 +8686,17 @@ mod tests {
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]
fn idle_repaint_only_runs_for_stale_alternate_screen() {
let now = Instant::now();