mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-14 19:45:49 +00:00
chore: write page vt test bg color with trailing row
The issue is in ghostty_src/src/terminal/formatter.zig#L1117-L1129:
- Cells without text are treated as "blank" (line 1117-1119) - this includes cells that only have background colors
- When blank cells are emitted, they're plain spaces (line 1129) - writer.splatByteAll(' ', blank_cells) outputs spaces without any SGR styling
- Background-only cells (bg_color_palette, bg_color_rgb) are marked unreachable (lines 1233-1235) because the code assumes hasText() already filtered them
This means when htop draws a row like:
`[green bg]CPU: 45%[red bg] [default]`
The trailing cells with red background but no text get accumulated as blanks and emitted as plain spaces - losing the background color.
This commit is contained in:
@@ -5819,3 +5819,57 @@ test "Page codepoint_map empty map" {
|
||||
const output = builder.writer.buffered();
|
||||
try testing.expectEqualStrings("hello world", output);
|
||||
}
|
||||
|
||||
test "Page VT background color on trailing blank cells" {
|
||||
// This test reproduces a bug where trailing cells with background color
|
||||
// but no text are emitted as plain spaces without SGR sequences.
|
||||
// This causes TUIs like htop to lose background colors on rehydration.
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var builder: std.Io.Writer.Allocating = .init(alloc);
|
||||
defer builder.deinit();
|
||||
|
||||
var t = try Terminal.init(alloc, .{
|
||||
.cols = 20,
|
||||
.rows = 5,
|
||||
});
|
||||
defer t.deinit(alloc);
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
|
||||
// Simulate a TUI row: "CPU:" with text, then trailing cells with red background
|
||||
// to end of line (no text after the colored region).
|
||||
// \x1b[41m sets red background, then EL fills rest of row with that bg.
|
||||
try s.nextSlice("CPU:\x1b[41m\x1b[K");
|
||||
// Reset colors and move to next line with different content
|
||||
try s.nextSlice("\x1b[0m\r\nline2");
|
||||
|
||||
const pages = &t.screens.active.pages;
|
||||
const page = &pages.pages.last.?.data;
|
||||
|
||||
var formatter: PageFormatter = .init(page, .vt);
|
||||
formatter.opts.trim = false; // Don't trim so we can see the trailing behavior
|
||||
|
||||
try formatter.format(&builder.writer);
|
||||
const output = builder.writer.buffered();
|
||||
|
||||
// The output should preserve the red background SGR for trailing cells on line 1.
|
||||
// Bug: the first row outputs "CPU:\r\n" only - losing the background color fill.
|
||||
// The red background should appear BEFORE the newline, not after.
|
||||
|
||||
// Find position of CRLF
|
||||
const crlf_pos = std.mem.indexOf(u8, output, "\r\n") orelse {
|
||||
// No CRLF found, fail the test
|
||||
return error.TestUnexpectedResult;
|
||||
};
|
||||
|
||||
// Check that red background (48;5;1) appears BEFORE the newline (on line 1)
|
||||
const line1 = output[0..crlf_pos];
|
||||
const has_red_bg_line1 = std.mem.indexOf(u8, line1, "\x1b[41m") != null or
|
||||
std.mem.indexOf(u8, line1, "\x1b[48;5;1m") != null;
|
||||
|
||||
// This should be true but currently fails due to the bug
|
||||
try testing.expect(has_red_bg_line1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user