Preserve ambiguous terminal input
ci / test (push) Canceled after 0s
ci / fuzz-smoke (push) Canceled after 0s
ci / macos-client (macos-aarch64, macos-14) (push) Canceled after 0s
ci / macos-client (macos-x86_64, macos-13) (push) Canceled after 0s
ci / windows-client (push) Canceled after 0s
ci / package-release (linux-x86_64, ubuntu-latest, , , ) (push) Canceled after 0s
ci / package-release (macos-aarch64, macos-14, , , ) (push) Canceled after 0s
ci / package-release (macos-x86_64, macos-13, , , ) (push) Canceled after 0s
ci / package-release (windows-aarch64, windows-latest, aarch64, windows, aarch64-pc-windows-msvc) (push) Canceled after 0s
ci / package-release (windows-x86_64, windows-latest, , , ) (push) Canceled after 0s
ci / remote-bench (push) Canceled after 0s
ci / publish-gitea-release (push) Canceled after 0s
ci / test (push) Canceled after 0s
ci / fuzz-smoke (push) Canceled after 0s
ci / macos-client (macos-aarch64, macos-14) (push) Canceled after 0s
ci / macos-client (macos-x86_64, macos-13) (push) Canceled after 0s
ci / windows-client (push) Canceled after 0s
ci / package-release (linux-x86_64, ubuntu-latest, , , ) (push) Canceled after 0s
ci / package-release (macos-aarch64, macos-14, , , ) (push) Canceled after 0s
ci / package-release (macos-x86_64, macos-13, , , ) (push) Canceled after 0s
ci / package-release (windows-aarch64, windows-latest, aarch64, windows, aarch64-pc-windows-msvc) (push) Canceled after 0s
ci / package-release (windows-x86_64, windows-latest, , , ) (push) Canceled after 0s
ci / remote-bench (push) Canceled after 0s
ci / publish-gitea-release (push) Canceled after 0s
This commit is contained in:
+76
-15
@@ -8436,7 +8436,7 @@ fn strip_unowned_terminal_reports(bytes: Vec<u8>, mouse_tracking: bool) -> (Vec<
|
|||||||
return (bytes, false);
|
return (bytes, false);
|
||||||
}
|
}
|
||||||
let before = bytes.len();
|
let before = bytes.len();
|
||||||
let stripped = strip_stale_mouse_reports(&bytes);
|
let stripped = strip_complete_terminal_mouse_reports(&bytes);
|
||||||
let changed = stripped.len() != before;
|
let changed = stripped.len() != before;
|
||||||
(stripped, changed)
|
(stripped, changed)
|
||||||
}
|
}
|
||||||
@@ -8572,6 +8572,42 @@ fn strip_stale_mouse_reports(bytes: &[u8]) -> Vec<u8> {
|
|||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn strip_complete_terminal_mouse_reports(bytes: &[u8]) -> Vec<u8> {
|
||||||
|
let mut out = Vec::with_capacity(bytes.len());
|
||||||
|
let mut offset = 0;
|
||||||
|
while offset < bytes.len() {
|
||||||
|
if let Some(len) = prefixed_mouse_report_len(bytes, offset) {
|
||||||
|
offset += len;
|
||||||
|
} else {
|
||||||
|
out.push(bytes[offset]);
|
||||||
|
offset += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prefixed_mouse_report_len(bytes: &[u8], offset: usize) -> Option<usize> {
|
||||||
|
match bytes.get(offset).copied()? {
|
||||||
|
0x1b if bytes.get(offset + 1) == Some(&b'[') => match bytes.get(offset + 2).copied() {
|
||||||
|
Some(b'M') if offset + 6 <= bytes.len() => Some(6),
|
||||||
|
Some(b'<') => mouse_report_params_len(bytes, offset + 3, 2).map(|len| len + 3),
|
||||||
|
Some(byte) if byte.is_ascii_digit() => {
|
||||||
|
mouse_report_params_len(bytes, offset + 2, 2).map(|len| len + 2)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
0x9b => match bytes.get(offset + 1).copied() {
|
||||||
|
Some(b'M') if offset + 5 <= bytes.len() => Some(5),
|
||||||
|
Some(b'<') => mouse_report_params_len(bytes, offset + 2, 2).map(|len| len + 2),
|
||||||
|
Some(byte) if byte.is_ascii_digit() => {
|
||||||
|
mouse_report_params_len(bytes, offset + 1, 2).map(|len| len + 1)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn stale_mouse_report_len(bytes: &[u8], offset: usize) -> Option<usize> {
|
fn stale_mouse_report_len(bytes: &[u8], offset: usize) -> Option<usize> {
|
||||||
match bytes.get(offset).copied()? {
|
match bytes.get(offset).copied()? {
|
||||||
0x1b if bytes.get(offset + 1) == Some(&b'[') => match bytes.get(offset + 2).copied() {
|
0x1b if bytes.get(offset + 1) == Some(&b'[') => match bytes.get(offset + 2).copied() {
|
||||||
@@ -8643,25 +8679,27 @@ fn stale_mouse_report_maybe_incomplete(bytes: &[u8], offset: usize) -> bool {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
match rest {
|
match rest {
|
||||||
[0x1b] | [0x1b, b'['] | [0x1b, b'[', b'<'] => true,
|
[0x1b, b'[', b'<'] => true,
|
||||||
[0x1b, b'[', b'M', ..] if rest.len() < 6 => true,
|
[0x1b, b'[', b'M', ..] if rest.len() < 6 => true,
|
||||||
[0x1b, b'[', b'<', params @ ..] | [0x1b, b'[', params @ ..]
|
[0x1b, b'[', b'<', params @ ..] if params_are_terminal_report_prefix(params) => true,
|
||||||
if params_are_mouse_prefix(params, 2) =>
|
[0x1b, b'[', params @ ..] if params_are_mouse_prefix(params, 2) => true,
|
||||||
{
|
[0x9b, b'<'] => true,
|
||||||
true
|
|
||||||
}
|
|
||||||
[0x9b] | [0x9b, b'<'] => true,
|
|
||||||
[0x9b, b'M', ..] if rest.len() < 5 => true,
|
[0x9b, b'M', ..] if rest.len() < 5 => true,
|
||||||
[0x9b, b'<', params @ ..] | [0x9b, params @ ..] if params_are_mouse_prefix(params, 2) => {
|
[0x9b, b'<', params @ ..] if params_are_terminal_report_prefix(params) => true,
|
||||||
true
|
[0x9b, params @ ..] if params_are_mouse_prefix(params, 2) => true,
|
||||||
}
|
|
||||||
params if params_are_mouse_prefix(params, 2) => true,
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn params_are_terminal_report_prefix(params: &[u8]) -> bool {
|
||||||
|
!params.is_empty()
|
||||||
|
&& params
|
||||||
|
.iter()
|
||||||
|
.all(|byte| byte.is_ascii_digit() || *byte == b';')
|
||||||
|
}
|
||||||
|
|
||||||
fn params_are_mouse_prefix(params: &[u8], min_semicolons: usize) -> bool {
|
fn params_are_mouse_prefix(params: &[u8], min_semicolons: usize) -> bool {
|
||||||
let mut semicolons = 0usize;
|
let mut semicolons = 0;
|
||||||
let mut saw_digit = false;
|
let mut saw_digit = false;
|
||||||
for byte in params {
|
for byte in params {
|
||||||
match byte {
|
match byte {
|
||||||
@@ -13969,6 +14007,22 @@ mod tests {
|
|||||||
assert_eq!(preserved, b"\x1b[<35;10;1M");
|
assert_eq!(preserved, b"\x1b[<35;10;1M");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn live_unowned_filter_preserves_ambiguous_user_input() {
|
||||||
|
for input in [
|
||||||
|
b"\x1b".as_slice(),
|
||||||
|
b"\x1b[".as_slice(),
|
||||||
|
b"\x1b[A".as_slice(),
|
||||||
|
b"\x1b[200~paste\x1b[201~".as_slice(),
|
||||||
|
b"35;152;1M".as_slice(),
|
||||||
|
b"printf 35;152;1M\r".as_slice(),
|
||||||
|
] {
|
||||||
|
let (preserved, changed) = strip_unowned_terminal_reports(input.to_vec(), false);
|
||||||
|
assert!(!changed, "live filter changed {input:?}");
|
||||||
|
assert_eq!(preserved, input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn transient_udp_send_errors_are_not_terminal_fatal() {
|
fn transient_udp_send_errors_are_not_terminal_fatal() {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
@@ -14059,12 +14113,19 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn incomplete_three_field_mouse_prefix_is_suppressed() {
|
fn only_explicit_incomplete_mouse_prefixes_are_suppressed() {
|
||||||
assert_eq!(strip_stale_mouse_reports(b"35;152;"), b"");
|
assert_eq!(strip_stale_mouse_reports(b"35;152;"), b"35;152;");
|
||||||
assert_eq!(strip_stale_mouse_reports(b"\x1b[<35;152;"), b"");
|
assert_eq!(strip_stale_mouse_reports(b"\x1b[<35;152;"), b"");
|
||||||
assert_eq!(strip_stale_mouse_reports(b"\x9b35;152;"), b"");
|
assert_eq!(strip_stale_mouse_reports(b"\x9b35;152;"), b"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lone_escape_survives_stale_reconnect_filter() {
|
||||||
|
assert_eq!(strip_stale_mouse_reports(b"\x1b"), b"\x1b");
|
||||||
|
assert_eq!(strip_stale_mouse_reports(b"\x1b["), b"\x1b[");
|
||||||
|
assert_eq!(strip_stale_mouse_reports(b"\x1b[A"), b"\x1b[A");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn stale_focus_reports_are_stripped_from_pending_input() {
|
fn stale_focus_reports_are_stripped_from_pending_input() {
|
||||||
assert_eq!(strip_stale_mouse_reports(b"\x1b[Ihello\x1b[O"), b"hello");
|
assert_eq!(strip_stale_mouse_reports(b"\x1b[Ihello\x1b[O"), b"hello");
|
||||||
|
|||||||
Reference in New Issue
Block a user