aboutsummaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
Diffstat (limited to 'src/client')
-rw-r--r--src/client/input.rs117
-rw-r--r--src/client/mod.rs5
2 files changed, 98 insertions, 24 deletions
diff --git a/src/client/input.rs b/src/client/input.rs
index c37a15c7..28d38bda 100644
--- a/src/client/input.rs
+++ b/src/client/input.rs
@@ -71,18 +71,18 @@ fn unix_stdin_reader_loop(
framer.host_color_query_sent();
framer.enable_host_color_scheme_change_tracking();
}
+ let mut pending_palette = Vec::new();
while !should_quit.load(Ordering::Acquire) {
match reader.read(&mut scratch) {
Ok(0) => break,
Ok(n) => {
- for data in framer.push(&scratch[..n]) {
- if event_tx
- .blocking_send(ClientLoopEvent::StdinInput(data))
- .is_err()
- {
- return;
- }
+ if !send_unix_input_chunks(
+ framer.push(&scratch[..n]),
+ &event_tx,
+ &mut pending_palette,
+ ) {
+ return;
}
let timeout_ms = idle_flush_timeout_ms(
@@ -93,28 +93,23 @@ fn unix_stdin_reader_loop(
let had_pending = framer.has_pending_input();
let chunks = framer.flush_timeout();
let held_escape = had_pending && chunks.is_empty();
- for data in chunks {
- if event_tx
- .blocking_send(ClientLoopEvent::StdinInput(data))
- .is_err()
- {
- return;
- }
+ if !send_unix_input_chunks(chunks, &event_tx, &mut pending_palette)
+ || !flush_unix_palette_input(&event_tx, &mut pending_palette)
+ {
+ return;
}
if held_escape
&& stdin_read_ready(
&reader,
crate::raw_input::RAW_INPUT_IDLE_FLUSH_TIMEOUT_MS,
) == Some(false)
+ && !send_unix_input_chunks(
+ framer.flush_timeout(),
+ &event_tx,
+ &mut pending_palette,
+ )
{
- for data in framer.flush_timeout() {
- if event_tx
- .blocking_send(ClientLoopEvent::StdinInput(data))
- .is_err()
- {
- return;
- }
- }
+ return;
}
}
}
@@ -129,6 +124,56 @@ fn unix_stdin_reader_loop(
}
#[cfg(unix)]
+fn send_unix_input_chunks(
+ chunks: Vec<Vec<u8>>,
+ event_tx: &mpsc::Sender<ClientLoopEvent>,
+ pending_palette: &mut Vec<Vec<u8>>,
+) -> bool {
+ for data in chunks {
+ let palette_response = std::str::from_utf8(&data)
+ .ok()
+ .and_then(crate::terminal_theme::parse_palette_color_response)
+ .is_some();
+ if palette_response {
+ pending_palette.push(data);
+ if pending_palette.len() == 256 && !flush_unix_palette_input(event_tx, pending_palette)
+ {
+ return false;
+ }
+ continue;
+ }
+ let default_color_response = std::str::from_utf8(&data)
+ .ok()
+ .and_then(crate::terminal_theme::parse_default_color_response)
+ .is_some();
+ if !default_color_response && !flush_unix_palette_input(event_tx, pending_palette) {
+ return false;
+ }
+ if event_tx
+ .blocking_send(ClientLoopEvent::StdinInput(data))
+ .is_err()
+ {
+ return false;
+ }
+ }
+ true
+}
+
+#[cfg(unix)]
+fn flush_unix_palette_input(
+ event_tx: &mpsc::Sender<ClientLoopEvent>,
+ pending_palette: &mut Vec<Vec<u8>>,
+) -> bool {
+ if pending_palette.is_empty() {
+ return true;
+ }
+ let data = std::mem::take(pending_palette).concat();
+ event_tx
+ .blocking_send(ClientLoopEvent::StdinInput(data))
+ .is_ok()
+}
+
+#[cfg(unix)]
fn idle_flush_timeout_ms(
framer: &crate::raw_input::RawInputByteFramer,
host_mouse_capture_active: bool,
@@ -357,6 +402,7 @@ fn windows_client_input_event_from_raw(
Some(crate::protocol::ClientInputEvent::FocusLost)
}
crate::raw_input::RawInputEvent::HostDefaultColor { .. }
+ | crate::raw_input::RawInputEvent::HostPaletteColors { .. }
| crate::raw_input::RawInputEvent::HostColorSchemeChanged(_)
| crate::raw_input::RawInputEvent::Unsupported => None,
}
@@ -420,6 +466,33 @@ mod tests {
}
#[test]
+ fn palette_replies_are_forwarded_as_one_input_batch() {
+ let (tx, mut rx) = mpsc::channel(4);
+ let mut pending = Vec::new();
+ assert!(send_unix_input_chunks(
+ vec![
+ b"\x1b]4;0;rgb:1111/2222/3333\x1b\\".to_vec(),
+ b"\x1b]4;1;rgb:4444/5555/6666\x1b\\".to_vec(),
+ ],
+ &tx,
+ &mut pending,
+ ));
+ assert!(rx.try_recv().is_err());
+
+ assert!(flush_unix_palette_input(&tx, &mut pending));
+ let ClientLoopEvent::StdinInput(data) = rx.try_recv().unwrap() else {
+ panic!("expected palette input batch");
+ };
+ assert_eq!(
+ data.windows(4)
+ .filter(|window| *window == b"\x1b]4;")
+ .count(),
+ 2
+ );
+ assert!(pending.is_empty());
+ }
+
+ #[test]
fn raw_input_idle_flush_timeout_keeps_escape_responsive() {
let timeout_ms = std::hint::black_box(crate::raw_input::RAW_INPUT_IDLE_FLUSH_TIMEOUT_MS);
assert!(timeout_ms <= 20);
diff --git a/src/client/mod.rs b/src/client/mod.rs
index a22fd227..b1c363f2 100644
--- a/src/client/mod.rs
+++ b/src/client/mod.rs
@@ -2135,7 +2135,8 @@ fn should_query_host_terminal_theme() -> bool {
}
fn write_host_terminal_theme_query(mut writer: impl io::Write) -> io::Result<()> {
- writer.write_all(crate::terminal_theme::HOST_COLOR_QUERY_SEQUENCE.as_bytes())?;
+ let query = crate::terminal_theme::host_terminal_theme_query_sequence();
+ writer.write_all(query.as_bytes())?;
writer.flush()
}
@@ -2412,7 +2413,7 @@ mod tests {
write_host_terminal_theme_query(&mut output).unwrap();
assert_eq!(
output,
- crate::terminal_theme::HOST_COLOR_QUERY_SEQUENCE.as_bytes()
+ crate::terminal_theme::host_terminal_theme_query_sequence().as_bytes()
);
}