terminal: mark old/new rows as dirty when moving the cursor absolute

This commit is contained in:
Mitchell Hashimoto
2024-06-07 14:55:02 -07:00
parent 5092cb55ad
commit c2b0bb6395
2 changed files with 20 additions and 5 deletions

View File

@ -481,6 +481,10 @@ pub fn cursorAbsolute(self: *Screen, x: size.CellCountInt, y: size.CellCountInt)
assert(y < self.pages.rows); assert(y < self.pages.rows);
defer self.assertIntegrity(); defer self.assertIntegrity();
// Moving the cursor affects text run splitting (ligatures) so
// we must mark the old and new page dirty.
self.cursor.page_pin.markDirty();
var page_pin = if (y < self.cursor.y) var page_pin = if (y < self.cursor.y)
self.cursor.page_pin.up(self.cursor.y - y).? self.cursor.page_pin.up(self.cursor.y - y).?
else if (y > self.cursor.y) else if (y > self.cursor.y)
@ -494,6 +498,11 @@ pub fn cursorAbsolute(self: *Screen, x: size.CellCountInt, y: size.CellCountInt)
const page_rac = page_pin.rowAndCell(); const page_rac = page_pin.rowAndCell();
self.cursor.page_row = page_rac.row; self.cursor.page_row = page_rac.row;
self.cursor.page_cell = page_rac.cell; self.cursor.page_cell = page_rac.cell;
// Mark the new page dirty. This might be the same page as the old
// but this is a fairly cheap operation and cursor movement isn't
// super common.
self.cursor.page_pin.markDirty();
} }
/// Reloads the cursor pointer information into the screen. This is expensive /// Reloads the cursor pointer information into the screen. This is expensive

View File

@ -4242,7 +4242,8 @@ test "Terminal: setTopAndBottomMargin top only" {
t.clearDirty(); t.clearDirty();
t.scrollDown(1); t.scrollDown(1);
try testing.expect(!t.isDirty(.{ .active = .{ .x = 0, .y = 0 } })); // This is dirty because the cursor moves from this row
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 = 1 } }));
try testing.expect(t.isDirty(.{ .active = .{ .x = 0, .y = 2 } })); 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 = 3 } }));
@ -4907,7 +4908,8 @@ test "Terminal: scrollUp top/bottom scroll region" {
t.clearDirty(); t.clearDirty();
t.scrollUp(1); t.scrollUp(1);
try testing.expect(!t.isDirty(.{ .active = .{ .x = 0, .y = 0 } })); // This is dirty because the cursor moves from this row
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 = 1 } }));
try testing.expect(t.isDirty(.{ .active = .{ .x = 0, .y = 2 } })); try testing.expect(t.isDirty(.{ .active = .{ .x = 0, .y = 2 } }));
@ -4985,7 +4987,8 @@ test "Terminal: scrollUp full top/bottom region" {
t.clearDirty(); t.clearDirty();
t.scrollUp(4); t.scrollUp(4);
try testing.expect(!t.isDirty(.{ .active = .{ .x = 0, .y = 0 } })); // This is dirty because the cursor moves from this row
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 = 1 } }));
{ {
@ -5010,7 +5013,8 @@ test "Terminal: scrollUp full top/bottomleft/right scroll region" {
t.clearDirty(); t.clearDirty();
t.scrollUp(4); t.scrollUp(4);
try testing.expect(!t.isDirty(.{ .active = .{ .x = 0, .y = 0 } })); // This is dirty because the cursor moves from this row
try testing.expect(t.isDirty(.{ .active = .{ .x = 0, .y = 0 } }));
for (1..5) |y| try testing.expect(t.isDirty(.{ .active = .{ for (1..5) |y| try testing.expect(t.isDirty(.{ .active = .{
.x = 0, .x = 0,
.y = @intCast(y), .y = @intCast(y),
@ -5077,7 +5081,9 @@ test "Terminal: scrollDown outside of scroll region" {
try testing.expectEqual(cursor.y, t.screen.cursor.y); try testing.expectEqual(cursor.y, t.screen.cursor.y);
try testing.expect(!t.isDirty(.{ .active = .{ .x = 0, .y = 0 } })); try testing.expect(!t.isDirty(.{ .active = .{ .x = 0, .y = 0 } }));
try testing.expect(!t.isDirty(.{ .active = .{ .x = 0, .y = 1 } }));
// This is dirty because the cursor moves from this row
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 = 2 } }));
try testing.expect(t.isDirty(.{ .active = .{ .x = 0, .y = 3 } })); try testing.expect(t.isDirty(.{ .active = .{ .x = 0, .y = 3 } }));