aboutsummaryrefslogtreecommitdiff
path: root/src/raw_input.rs
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-04-05 03:46:16 +0300
committerCan Celik <ogulcancelik@gmail.com>2026-04-05 03:46:16 +0300
commit8525503dba9029d0a5f24990e026d8164f0bf39c (patch)
tree43b902dfab49603c667ae016baa97aee27724073 /src/raw_input.rs
parenta08dfaef2f13873fc85dc9e1357235b8b0703a46 (diff)
fix: match ghostty pane default colors to host terminal theme
Diffstat (limited to 'src/raw_input.rs')
-rw-r--r--src/raw_input.rs65
1 files changed, 63 insertions, 2 deletions
diff --git a/src/raw_input.rs b/src/raw_input.rs
index 77aaecdb..059791ea 100644
--- a/src/raw_input.rs
+++ b/src/raw_input.rs
@@ -7,6 +7,7 @@ use std::os::fd::AsRawFd;
use tokio::sync::mpsc;
use crate::input::{parse_terminal_key_sequence, TerminalKey};
+use crate::terminal_theme::{parse_default_color_response, DefaultColorKind, RgbColor};
const ESC: u8 = 0x1b;
const BRACKETED_PASTE_START: &[u8] = b"\x1b[200~";
@@ -17,6 +18,10 @@ pub enum RawInputEvent {
Key(TerminalKey),
Paste(String),
Mouse(MouseEvent),
+ HostDefaultColor {
+ kind: DefaultColorKind,
+ color: RgbColor,
+ },
Unsupported,
}
@@ -161,6 +166,10 @@ fn extract_one_event(buffer: &[u8]) -> Option<(RawInputEvent, usize)> {
let seq_len = complete_escape_sequence_len(buffer)?;
let seq = std::str::from_utf8(&buffer[..seq_len]).ok()?;
+ if let Some((kind, color)) = parse_default_color_response(seq) {
+ return Some((RawInputEvent::HostDefaultColor { kind, color }, seq_len));
+ }
+
if let Some(mouse) = parse_sgr_mouse(seq) {
return Some((RawInputEvent::Mouse(mouse), seq_len));
}
@@ -200,8 +209,11 @@ fn complete_escape_sequence_len(buffer: &[u8]) -> Option<usize> {
);
}
- if buffer.starts_with(b"\x1b]") || buffer.starts_with(b"\x1bP") || buffer.starts_with(b"\x1b_")
- {
+ if buffer.starts_with(b"\x1b]") {
+ return find_osc_terminator(buffer);
+ }
+
+ if buffer.starts_with(b"\x1bP") || buffer.starts_with(b"\x1b_") {
return find_subsequence(buffer, b"\x1b\\").map(|idx| idx + 2);
}
@@ -212,6 +224,17 @@ fn complete_escape_sequence_len(buffer: &[u8]) -> Option<usize> {
Some(2)
}
+fn find_osc_terminator(buffer: &[u8]) -> Option<usize> {
+ find_subsequence(buffer, b"\x1b\\")
+ .map(|idx| idx + 2)
+ .or_else(|| {
+ buffer
+ .iter()
+ .position(|byte| *byte == b'\x07')
+ .map(|idx| idx + 1)
+ })
+}
+
fn find_csi_final(buffer: &[u8], finals: &[u8]) -> Option<usize> {
for (idx, byte) in buffer.iter().enumerate().skip(2) {
if finals.contains(byte) {
@@ -407,6 +430,44 @@ mod tests {
}
#[test]
+ fn parses_host_default_color_response_with_st() {
+ let (RawInputEvent::HostDefaultColor { kind, color }, consumed) =
+ extract_one_event(b"\x1b]10;rgb:cccc/dddd/eeee\x1b\\").unwrap()
+ else {
+ panic!("expected host color response");
+ };
+ assert_eq!(consumed, 25);
+ assert_eq!(kind, DefaultColorKind::Foreground);
+ assert_eq!(
+ color,
+ RgbColor {
+ r: 0xcc,
+ g: 0xdd,
+ b: 0xee
+ }
+ );
+ }
+
+ #[test]
+ fn parses_host_default_color_response_with_bel() {
+ let (RawInputEvent::HostDefaultColor { kind, color }, consumed) =
+ extract_one_event(b"\x1b]11;#112233\x07").unwrap()
+ else {
+ panic!("expected host color response");
+ };
+ assert_eq!(consumed, 13);
+ assert_eq!(kind, DefaultColorKind::Background);
+ assert_eq!(
+ color,
+ RgbColor {
+ r: 0x11,
+ g: 0x22,
+ b: 0x33
+ }
+ );
+ }
+
+ #[test]
fn parses_legacy_up_arrow() {
let (RawInputEvent::Key(key), consumed) = extract_one_event(b"\x1b[A").unwrap() else {
panic!("expected key");