From 9ee0b23ef7020c1288eec655b7bbc606f1755355 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 25 Mar 2024 09:42:05 -0700 Subject: [PATCH] terminal: clear spacer heads on growing cols w/o reflow --- src/terminal/PageList.zig | 72 +++++++++++++++++++++++++++++++++++++++ src/terminal/page.zig | 44 ++++++++++++++---------- 2 files changed, 98 insertions(+), 18 deletions(-) diff --git a/src/terminal/PageList.zig b/src/terminal/PageList.zig index 9479a847f..6ed34328d 100644 --- a/src/terminal/PageList.zig +++ b/src/terminal/PageList.zig @@ -4826,6 +4826,78 @@ test "PageList resize (no reflow) more cols" { } } +test "PageList resize (no reflow) more cols with spacer head" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try init(alloc, 2, 3, 0); + defer s.deinit(); + { + try testing.expect(s.pages.first == s.pages.last); + const page = &s.pages.first.?.data; + + { + const rac = page.getRowAndCell(0, 0); + rac.row.wrap = true; + rac.cell.* = .{ + .content_tag = .codepoint, + .content = .{ .codepoint = 'x' }, + }; + } + { + const rac = page.getRowAndCell(1, 0); + rac.cell.* = .{ + .content_tag = .codepoint, + .content = .{ .codepoint = ' ' }, + .wide = .spacer_head, + }; + } + { + const rac = page.getRowAndCell(0, 1); + rac.cell.* = .{ + .content_tag = .codepoint, + .content = .{ .codepoint = '😀' }, + .wide = .wide, + }; + } + { + const rac = page.getRowAndCell(1, 1); + rac.cell.* = .{ + .content_tag = .codepoint, + .content = .{ .codepoint = ' ' }, + .wide = .spacer_tail, + }; + } + } + + // Resize + try s.resize(.{ .cols = 3, .reflow = false }); + try testing.expectEqual(@as(usize, 3), s.cols); + try testing.expectEqual(@as(usize, 3), s.totalRows()); + + { + try testing.expect(s.pages.first == s.pages.last); + const page = &s.pages.first.?.data; + + { + const rac = page.getRowAndCell(0, 0); + try testing.expectEqual(@as(u21, 'x'), rac.cell.content.codepoint); + try testing.expectEqual(pagepkg.Cell.Wide.narrow, rac.cell.wide); + // try testing.expect(!rac.row.wrap); + } + { + const rac = page.getRowAndCell(1, 0); + try testing.expectEqual(@as(u21, ' '), rac.cell.content.codepoint); + try testing.expectEqual(pagepkg.Cell.Wide.narrow, rac.cell.wide); + } + { + const rac = page.getRowAndCell(2, 0); + try testing.expectEqual(@as(u21, 0), rac.cell.content.codepoint); + try testing.expectEqual(pagepkg.Cell.Wide.narrow, rac.cell.wide); + } + } +} + // This test is a bit convoluted so I want to explain: what we are trying // to verify here is that when we increase cols such that our rows per page // shrinks, we don't fragment our rows across many pages because this ends diff --git a/src/terminal/page.zig b/src/terminal/page.zig index e09a646e8..58f30730c 100644 --- a/src/terminal/page.zig +++ b/src/terminal/page.zig @@ -494,26 +494,34 @@ pub const Page = struct { // If we have no managed memory in the row, we can just copy. if (!dst_row.grapheme and !dst_row.styled) { fastmem.copy(Cell, cells, other_cells); - return; + } else { + // We have managed memory, so we have to do a slower copy to + // get all of that right. + for (cells, other_cells) |*dst_cell, *src_cell| { + dst_cell.* = src_cell.*; + if (src_cell.hasGrapheme()) { + // To prevent integrity checks flipping + if (comptime std.debug.runtime_safety) dst_cell.style_id = style.default_id; + + dst_cell.content_tag = .codepoint; // required for appendGrapheme + const cps = other.lookupGrapheme(src_cell).?; + for (cps) |cp| try self.appendGrapheme(dst_row, dst_cell, cp); + } + if (src_cell.style_id != style.default_id) { + const other_style = other.styles.lookupId(other.memory, src_cell.style_id).?.*; + const md = try self.styles.upsert(self.memory, other_style); + md.ref += 1; + dst_cell.style_id = md.id; + } + } } - // We have managed memory, so we have to do a slower copy to - // get all of that right. - for (cells, other_cells) |*dst_cell, *src_cell| { - dst_cell.* = src_cell.*; - if (src_cell.hasGrapheme()) { - // To prevent integrity checks flipping - if (comptime std.debug.runtime_safety) dst_cell.style_id = style.default_id; - - dst_cell.content_tag = .codepoint; // required for appendGrapheme - const cps = other.lookupGrapheme(src_cell).?; - for (cps) |cp| try self.appendGrapheme(dst_row, dst_cell, cp); - } - if (src_cell.style_id != style.default_id) { - const other_style = other.styles.lookupId(other.memory, src_cell.style_id).?.*; - const md = try self.styles.upsert(self.memory, other_style); - md.ref += 1; - dst_cell.style_id = md.id; + // If we are growing columns, then we need to ensure spacer heads + // are cleared. + if (self.size.cols > other.size.cols) { + const last = &cells[other.size.cols - 1]; + if (last.wide == .spacer_head) { + last.wide = .narrow; } }