From 7bde20a43d4f56d854d40d1904e95de1c5863cd5 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 13 Sep 2022 10:12:44 -0700 Subject: [PATCH] a cell is empty only if it also has no styling Previously we only checked if it had no character. With text shaping, this was causing runs of only empty backgrounds to not render. --- src/Grid.zig | 4 ++-- src/font/Shaper.zig | 36 ++++++++++++++++++++++++++++++++++++ src/terminal/Screen.zig | 9 ++++++++- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/Grid.zig b/src/Grid.zig index 69387a33c..8daca2b1d 100644 --- a/src/Grid.zig +++ b/src/Grid.zig @@ -579,8 +579,8 @@ pub fn updateCell( }); } - // If the cell is empty then we draw nothing in the box. - if (!cell.empty()) { + // If the cell has a character, draw it + if (cell.char > 0) { // Render const face = self.font_group.group.faceFromIndex(shaper_run.font_index); const glyph = try self.font_group.renderGlyph( diff --git a/src/font/Shaper.zig b/src/font/Shaper.zig index 1e41f5c69..9063ae45b 100644 --- a/src/font/Shaper.zig +++ b/src/font/Shaper.zig @@ -276,6 +276,42 @@ test "run iterator" { } } +test "run iterator: empty cells with background set" { + const testing = std.testing; + const alloc = testing.allocator; + + var testdata = try testShaper(alloc); + defer testdata.deinit(); + + { + // Make a screen with some data + var screen = try terminal.Screen.init(alloc, 3, 5, 0); + defer screen.deinit(); + try screen.testWriteString("A"); + + // Get our first row + const row = screen.getRow(.{ .active = 0 }); + row.getCellPtr(1).bg = try terminal.color.Name.cyan.default(); + row.getCellPtr(1).attrs.has_bg = true; + row.getCellPtr(2).fg = try terminal.color.Name.yellow.default(); + row.getCellPtr(2).attrs.has_fg = true; + + // Get our run iterator + var shaper = testdata.shaper; + var it = shaper.runIterator(testdata.cache, screen.getRow(.{ .screen = 0 })); + var count: usize = 0; + while (try it.next(alloc)) |run| { + count += 1; + + // The run should have length 3 because of the two background + // cells. + try testing.expectEqual(@as(u32, 3), shaper.hb_buf.getLength()); + const cells = try shaper.shape(run); + try testing.expectEqual(@as(usize, 3), cells.len); + } + try testing.expectEqual(@as(usize, 1), count); + } +} test "shape" { const testing = std.testing; const alloc = testing.allocator; diff --git a/src/terminal/Screen.zig b/src/terminal/Screen.zig index 821d64215..7652a7546 100644 --- a/src/terminal/Screen.zig +++ b/src/terminal/Screen.zig @@ -183,7 +183,14 @@ pub const Cell = struct { /// True if the cell should be skipped for drawing pub fn empty(self: Cell) bool { - return self.char == 0; + // Get our backing integer for our packed struct of attributes + const AttrInt = @Type(.{ .Int = .{ + .signedness = .unsigned, + .bits = @bitSizeOf(@TypeOf(self.attrs)), + } }); + + // We're empty if we have no char AND we have no styling + return self.char == 0 and @bitCast(AttrInt, self.attrs) == 0; } /// The width of the cell.