aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/pane/terminal.rs54
1 files changed, 53 insertions, 1 deletions
diff --git a/src/pane/terminal.rs b/src/pane/terminal.rs
index de4781b4..c688dcc9 100644
--- a/src/pane/terminal.rs
+++ b/src/pane/terminal.rs
@@ -554,6 +554,7 @@ impl GhosttyPaneTerminal {
let colors = render_state.colors().ok();
let default_bg = colors.and_then(|c| ghostty_default_bg(c.background, host_theme));
let default_fg = colors.map(|c| ghostty_color(c.foreground));
+ let resolved_bg = colors.map(|c| ghostty_color(c.background));
let mut row_iterator = match crate::ghostty::RowIterator::new() {
Ok(iterator) => iterator,
@@ -580,7 +581,7 @@ impl GhosttyPaneTerminal {
let mut x = 0u16;
while x < area.width && cells.next() {
let wide = cells.wide().unwrap_or(crate::ghostty::CellWide::Narrow);
- let style = ghostty_cell_style(&cells, default_fg, default_bg);
+ let style = ghostty_cell_style(&cells, default_fg, default_bg, resolved_bg);
let symbol = match ghostty_buffer_symbol_into(
&cells,
wide,
@@ -836,6 +837,7 @@ fn ghostty_cell_style(
cells: &crate::ghostty::RowCellIter<'_>,
default_fg: Option<Color>,
default_bg: Option<Color>,
+ resolved_bg: Option<Color>,
) -> Style {
let style_data = cells.style().unwrap_or_default();
let mut fg = cells
@@ -854,6 +856,17 @@ fn ghostty_cell_style(
fg = bg.or(default_bg);
}
if style_data.inverse {
+ // When the background is transparent (None), resolve it to the
+ // actual terminal background color before swapping. Otherwise
+ // the swapped fg becomes None (Color::Reset) which the host
+ // terminal renders as its default foreground — the same hue as
+ // the new bg, making inverse text invisible.
+ if bg.is_none() {
+ bg = resolved_bg;
+ }
+ if fg.is_none() {
+ fg = default_fg;
+ }
std::mem::swap(&mut fg, &mut bg);
}
@@ -1440,6 +1453,45 @@ mod tests {
}
#[test]
+ fn render_inverse_text_swaps_fg_and_resolved_bg_when_bg_is_transparent() {
+ let (tx, _rx) = mpsc::channel(4);
+ let terminal = crate::ghostty::Terminal::new(20, 5, 0).unwrap();
+ let pane = GhosttyPaneTerminal::new(terminal, tx).unwrap();
+ let host_theme = crate::terminal_theme::TerminalTheme {
+ foreground: Some(crate::terminal_theme::RgbColor {
+ r: 0xaa,
+ g: 0xbb,
+ b: 0xcc,
+ }),
+ background: Some(crate::terminal_theme::RgbColor {
+ r: 0x11,
+ g: 0x22,
+ b: 0x33,
+ }),
+ };
+ pane.apply_host_terminal_theme(host_theme);
+ {
+ let mut core = pane.core.lock().unwrap();
+ // SGR 7 enables inverse/reverse video
+ core.terminal.write(b"\x1b[7mhi\x1b[27m");
+ }
+
+ let backend = ratatui::backend::TestBackend::new(20, 5);
+ let mut terminal = ratatui::Terminal::new(backend).unwrap();
+ terminal
+ .draw(|frame| pane.render(frame, Rect::new(0, 0, 20, 5), false))
+ .unwrap();
+
+ let buffer = terminal.backend().buffer();
+ let cell = &buffer[(0, 0)];
+ assert_eq!(cell.symbol(), "h");
+ // After inverse: fg should be the resolved bg, bg should be the original fg.
+ // fg must NOT be Color::Reset (which would be the same hue as bg).
+ assert_eq!(cell.style().fg, Some(Color::Rgb(0x11, 0x22, 0x33)));
+ assert_eq!(cell.style().bg, Some(Color::Rgb(0xaa, 0xbb, 0xcc)));
+ }
+
+ #[test]
fn trim_trailing_blank_rows_drops_empty_viewport_tail() {
let mut rows = vec!["hello".to_string(), "".to_string(), " ".to_string()];
trim_trailing_blank_rows(&mut rows);