diff options
| author | Can Celik <ogulcancelik@gmail.com> | 2026-08-03 02:05:27 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-08-03 02:05:27 +0300 |
| commit | 10eb0bc744165ae91dfce9fd731fe170410b34ec (patch) | |
| tree | 8622d429d9453c2e8d06630322804a702973d94a /src/pane | |
| parent | cbc31d34a1fb3da64415737de57ad10fe6af5ba5 (diff) | |
fix: propagate host color scheme to pane apps (#2214)
refs #714
Diffstat (limited to 'src/pane')
| -rw-r--r-- | src/pane/terminal.rs | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/src/pane/terminal.rs b/src/pane/terminal.rs index e464554c..438c3037 100644 --- a/src/pane/terminal.rs +++ b/src/pane/terminal.rs @@ -120,6 +120,8 @@ pub struct InputState { pub mouse_alternate_scroll: bool, #[serde(default)] pub modify_other_keys: bool, + #[serde(default)] + pub color_scheme_reporting: bool, } impl InputState { @@ -458,6 +460,13 @@ impl PaneTerminal { self.ghostty.apply_host_terminal_theme(theme); } + pub fn apply_host_terminal_appearance( + &self, + appearance: Option<crate::terminal_theme::HostAppearance>, + ) -> Option<Bytes> { + self.ghostty.apply_host_terminal_appearance(appearance) + } + pub fn has_transient_default_color_override(&self) -> bool { self.ghostty.has_transient_default_color_override() } @@ -988,6 +997,32 @@ impl GhosttyPaneTerminal { } } + pub fn apply_host_terminal_appearance( + &self, + appearance: Option<crate::terminal_theme::HostAppearance>, + ) -> Option<Bytes> { + let mut core = self.core.lock().ok()?; + let color_scheme = appearance.map(|appearance| match appearance { + crate::terminal_theme::HostAppearance::Dark => crate::ghostty::ColorScheme::Dark, + crate::terminal_theme::HostAppearance::Light => crate::ghostty::ColorScheme::Light, + }); + let previous = core.terminal.set_color_scheme(color_scheme); + + let transitioned = matches!( + (previous, color_scheme), + (Some(previous), Some(current)) if previous != current + ); + if !transitioned + || !core + .terminal + .mode_get(crate::ghostty::MODE_COLOR_SCHEME_REPORT) + .unwrap_or(false) + { + return None; + } + appearance.map(|appearance| Bytes::from_static(appearance.color_scheme_report())) + } + pub fn has_transient_default_color_override(&self) -> bool { self.core .lock() @@ -1331,6 +1366,10 @@ impl GhosttyPaneTerminal { crate::ghostty::MODE_MOUSE_ALTERNATE_SCROLL, input_state.mouse_alternate_scroll, ); + let _ = core.terminal.mode_set( + crate::ghostty::MODE_COLOR_SCHEME_REPORT, + input_state.color_scheme_reporting, + ); for mode in [ MODE_MOUSE_X10, @@ -1585,6 +1624,10 @@ impl GhosttyPaneTerminal { .keyboard_state_ansi() .ok() .is_some_and(|ansi| !ansi.is_empty()), + color_scheme_reporting: core + .terminal + .mode_get(crate::ghostty::MODE_COLOR_SCHEME_REPORT) + .ok()?, }) } @@ -3907,6 +3950,7 @@ mod tests { mouse_protocol_encoding: crate::input::MouseProtocolEncoding::Sgr, mouse_alternate_scroll: true, modify_other_keys: true, + color_scheme_reporting: true, }); assert_eq!( @@ -3920,6 +3964,7 @@ mod tests { mouse_protocol_encoding: crate::input::MouseProtocolEncoding::Sgr, mouse_alternate_scroll: true, modify_other_keys: true, + color_scheme_reporting: true, }) ); @@ -5010,6 +5055,45 @@ mod tests { } #[test] + fn color_scheme_queries_and_live_updates_follow_terminal_mode() { + let (tx, mut rx) = mpsc::channel(4); + let terminal = crate::ghostty::Terminal::new(20, 5, 0).unwrap(); + let pane = GhosttyPaneTerminal::new(terminal, tx.clone()).unwrap(); + let pane_id = PaneId::from_raw(1); + + assert!(pane + .apply_host_terminal_appearance(Some(crate::terminal_theme::HostAppearance::Dark)) + .is_none()); + let query = pane.process_pty_bytes(pane_id, 0, b"\x1b[?996n", &tx); + assert_eq!( + query.terminal_responses, + vec![Bytes::from_static(b"\x1b[?997;1n")] + ); + + pane.process_pty_bytes(pane_id, 0, b"\x1b[?2031h", &tx); + assert!(pane + .apply_host_terminal_appearance(Some(crate::terminal_theme::HostAppearance::Dark)) + .is_none()); + assert_eq!( + pane.apply_host_terminal_appearance(Some(crate::terminal_theme::HostAppearance::Light)), + Some(Bytes::from_static(b"\x1b[?997;2n")) + ); + + assert!(pane.apply_host_terminal_appearance(None).is_none()); + let unknown_query = pane.process_pty_bytes(pane_id, 0, b"\x1b[?996n", &tx); + assert!(unknown_query.terminal_responses.is_empty()); + assert!(pane + .apply_host_terminal_appearance(Some(crate::terminal_theme::HostAppearance::Dark)) + .is_none()); + + pane.process_pty_bytes(pane_id, 0, b"\x1bc", &tx); + assert!(pane + .apply_host_terminal_appearance(Some(crate::terminal_theme::HostAppearance::Light)) + .is_none()); + assert!(rx.try_recv().is_err()); + } + + #[test] fn process_pty_bytes_returns_xtgettcap_truecolor_query_responses_without_queuing_input() { let (tx, mut rx) = mpsc::channel(8); let terminal = crate::ghostty::Terminal::new(20, 5, 0).unwrap(); |
