From d47f14f86a78aac22595e9c00eecbb3f253bb8a2 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 28 Apr 2024 10:46:39 -0700 Subject: [PATCH] terminal: dirty tracking on screen clone --- src/terminal/PageList.zig | 37 ++++++++++++++++++++++++++++++++++++- src/terminal/page.zig | 15 ++++++++++----- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/src/terminal/PageList.zig b/src/terminal/PageList.zig index 53533f8c1..02f9d0272 100644 --- a/src/terminal/PageList.zig +++ b/src/terminal/PageList.zig @@ -2962,6 +2962,11 @@ pub fn isDirty(self: *const PageList, pt: point.Point) bool { return self.getCell(pt).?.isDirty(); } +/// Mark a point as dirty, used for testing. +fn markDirty(self: *PageList, pt: point.Point) void { + self.pin(pt).?.markDirty(); +} + /// Represents an exact x/y coordinate within the screen. This is called /// a "pin" because it is a fixed point within the pagelist direct to /// a specific page pointer and memory offset. The benefit is that this @@ -3020,8 +3025,12 @@ pub const Pin = struct { ).?.*; } + /// Check if this pin is dirty. + pub fn isDirty(self: Pin) bool { + return self.page.data.isRowDirty(self.y); + } + /// Mark this pin location as dirty. - /// TODO: test pub fn markDirty(self: Pin) void { var set = self.page.data.dirtyBitSet(); set.set(self.y); @@ -4830,6 +4839,32 @@ test "PageList clone remap tracked pin not in cloned area" { try testing.expect(pin_remap.get(p) == null); } +test "PageList clone full dirty" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try init(alloc, 80, 24, null); + defer s.deinit(); + try testing.expectEqual(@as(usize, s.rows), s.totalRows()); + + // Mark a row as dirty + s.markDirty(.{ .active = .{ .x = 0, .y = 0 } }); + s.markDirty(.{ .active = .{ .x = 0, .y = 12 } }); + s.markDirty(.{ .active = .{ .x = 0, .y = 23 } }); + + var s2 = try s.clone(.{ + .top = .{ .screen = .{} }, + .memory = .{ .alloc = alloc }, + }); + defer s2.deinit(); + try testing.expectEqual(@as(usize, s.rows), s2.totalRows()); + + // Should still be dirty + try testing.expect(s2.isDirty(.{ .active = .{ .x = 0, .y = 0 } })); + try testing.expect(s2.isDirty(.{ .active = .{ .x = 0, .y = 12 } })); + try testing.expect(s2.isDirty(.{ .active = .{ .x = 0, .y = 23 } })); +} + test "PageList resize (no reflow) more rows" { const testing = std.testing; const alloc = testing.allocator; diff --git a/src/terminal/page.zig b/src/terminal/page.zig index 1b134a4eb..4d3c0b1fd 100644 --- a/src/terminal/page.zig +++ b/src/terminal/page.zig @@ -500,11 +500,16 @@ pub const Page = struct { const other_rows = other.rows.ptr(other.memory)[y_start..y_end]; const rows = self.rows.ptr(self.memory)[0 .. y_end - y_start]; - for (rows, other_rows) |*dst_row, *src_row| try self.cloneRowFrom( - other, - dst_row, - src_row, - ); + for (rows, other_rows) |*dst_row, *src_row| { + try self.cloneRowFrom(other, dst_row, src_row); + } + + // Set our dirty range for all the rows we copied + var dirty_set = self.dirtyBitSet(); + dirty_set.setRangeValue(.{ + .start = 0, + .end = y_end - y_start, + }, true); // We should remain consistent self.assertIntegrity();