terminal: eraseRowBounded dirty tracking

This commit is contained in:
Mitchell Hashimoto
2024-04-16 14:20:18 -07:00
parent 0749b67832
commit 19ddbbc7d6
2 changed files with 48 additions and 5 deletions

View File

@ -2102,6 +2102,10 @@ pub fn eraseRowBounded(
page.data.clearCells(&rows[pn.y], 0, page.data.size.cols);
fastmem.rotateOnce(Row, rows[pn.y..][0 .. limit + 1]);
// Set all the rows as dirty
var dirty = page.data.dirtyBitSet();
dirty.setRangeValue(.{ .start = pn.y, .end = pn.y + limit }, true);
// Update pins in the shifted region.
var pin_it = self.tracked_pins.keyIterator();
while (pin_it.next()) |p_ptr| {
@ -2123,6 +2127,12 @@ pub fn eraseRowBounded(
fastmem.rotateOnce(Row, rows[pn.y..page.data.size.rows]);
// All the rows in the page are dirty below the erased row.
{
var dirty = page.data.dirtyBitSet();
dirty.setRangeValue(.{ .start = pn.y, .end = page.data.size.rows }, true);
}
// We need to keep track of how many rows we've shifted so that we can
// determine at what point we need to do a partial shift on subsequent
// pages.
@ -2165,6 +2175,10 @@ pub fn eraseRowBounded(
page.data.clearCells(&rows[0], 0, page.data.size.cols);
fastmem.rotateOnce(Row, rows[0 .. shifted_limit + 1]);
// Set all the rows as dirty
var dirty = page.data.dirtyBitSet();
dirty.setRangeValue(.{ .start = 0, .end = shifted_limit }, true);
// Update pins in the shifted region.
var pin_it = self.tracked_pins.keyIterator();
while (pin_it.next()) |p_ptr| {
@ -2183,6 +2197,10 @@ pub fn eraseRowBounded(
fastmem.rotateOnce(Row, rows[0..page.data.size.rows]);
// Set all the rows as dirty
var dirty = page.data.dirtyBitSet();
dirty.setRangeValue(.{ .start = 0, .end = page.data.size.rows }, true);
// Account for the rows shifted in this page.
shifted += page.data.size.rows;
@ -2939,6 +2957,11 @@ pub fn clearDirty(self: *PageList) void {
}
}
/// Returns true if the point is dirty, used for testing.
pub fn isDirty(self: *const PageList, pt: point.Point) bool {
return self.getCell(pt).?.isDirty();
}
/// 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
@ -4513,6 +4536,13 @@ test "PageList eraseRowBounded less than full row" {
try s.eraseRowBounded(.{ .active = .{ .y = 5 } }, 3);
try testing.expectEqual(s.rows, s.totalRows());
// The erased rows should be dirty
try testing.expect(!s.isDirty(.{ .active = .{ .x = 0, .y = 4 } }));
try testing.expect(s.isDirty(.{ .active = .{ .x = 0, .y = 5 } }));
try testing.expect(s.isDirty(.{ .active = .{ .x = 0, .y = 6 } }));
try testing.expect(s.isDirty(.{ .active = .{ .x = 0, .y = 7 } }));
try testing.expect(!s.isDirty(.{ .active = .{ .x = 0, .y = 8 } }));
try testing.expectEqual(s.pages.first.?, p_top.page);
try testing.expectEqual(@as(usize, 4), p_top.y);
try testing.expectEqual(@as(usize, 0), p_top.x);
@ -4541,6 +4571,12 @@ test "PageList eraseRowBounded with pin at top" {
try s.eraseRowBounded(.{ .active = .{ .y = 0 } }, 3);
try testing.expectEqual(s.rows, s.totalRows());
// The erased rows should be dirty
try testing.expect(s.isDirty(.{ .active = .{ .x = 0, .y = 0 } }));
try testing.expect(s.isDirty(.{ .active = .{ .x = 0, .y = 1 } }));
try testing.expect(s.isDirty(.{ .active = .{ .x = 0, .y = 2 } }));
try testing.expect(!s.isDirty(.{ .active = .{ .x = 0, .y = 3 } }));
try testing.expectEqual(s.pages.first.?, p_top.page);
try testing.expectEqual(@as(usize, 0), p_top.y);
try testing.expectEqual(@as(usize, 0), p_top.x);
@ -4563,6 +4599,10 @@ test "PageList eraseRowBounded full rows single page" {
try s.eraseRowBounded(.{ .active = .{ .y = 5 } }, 10);
try testing.expectEqual(s.rows, s.totalRows());
// The erased rows should be dirty
try testing.expect(!s.isDirty(.{ .active = .{ .x = 0, .y = 4 } }));
for (5..10) |y| try testing.expect(s.isDirty(.{ .active = .{ .x = 0, .y = y } }));
// Our pin should move to the first page
try testing.expectEqual(s.pages.first.?, p_in.page);
try testing.expectEqual(@as(usize, 6), p_in.y);
@ -4620,6 +4660,10 @@ test "PageList eraseRowBounded full rows two pages" {
// Erase only a few rows in our active
try s.eraseRowBounded(.{ .active = .{ .y = 4 } }, 4);
// The erased rows should be dirty
try testing.expect(!s.isDirty(.{ .active = .{ .x = 0, .y = 3 } }));
for (4..8) |y| try testing.expect(s.isDirty(.{ .active = .{ .x = 0, .y = y } }));
// In page in first page is shifted
try testing.expectEqual(s.pages.last.?.prev.?, p_first.page);
try testing.expectEqual(@as(usize, p_first.page.data.size.rows - 2), p_first.y);

View File

@ -5881,11 +5881,10 @@ test "Terminal: index bottom of scroll region" {
try t.index();
try t.print('X');
// TODO(dirty)
// try testing.expect(t.isDirty(.{ .active = .{ .x = 0, .y = 0 } }));
// try testing.expect(t.isDirty(.{ .active = .{ .x = 0, .y = 1 } }));
// try testing.expect(t.isDirty(.{ .active = .{ .x = 0, .y = 2 } }));
// try testing.expect(!t.isDirty(.{ .active = .{ .x = 0, .y = 3 } }));
try testing.expect(t.isDirty(.{ .active = .{ .x = 0, .y = 0 } }));
try testing.expect(t.isDirty(.{ .active = .{ .x = 0, .y = 1 } }));
try testing.expect(t.isDirty(.{ .active = .{ .x = 0, .y = 2 } }));
try testing.expect(!t.isDirty(.{ .active = .{ .x = 0, .y = 3 } }));
{
const str = try t.plainString(testing.allocator);