terminal/new: pagelist doesn't actively maintain active offset

This commit is contained in:
Mitchell Hashimoto
2024-02-23 13:17:52 -08:00
parent de3d1e4df7
commit 21c6026922
3 changed files with 42 additions and 28 deletions

View File

@ -57,7 +57,6 @@ pages: List,
/// - history: active row minus one
///
viewport: Viewport,
active: RowOffset,
/// The current desired screen dimensions. I say "desired" because individual
/// pages may still be a different size and not yet reflowed since we lazily
@ -120,7 +119,6 @@ pub fn init(
.page_pool = page_pool,
.pages = page_list,
.viewport = .{ .active = {} },
.active = .{ .page = page },
};
}
@ -224,10 +222,30 @@ pub fn rowIterator(
/// Get the top-left of the screen for the given tag.
fn getTopLeft(self: *const PageList, tag: point.Tag) RowOffset {
return switch (tag) {
.active => self.active,
// The full screen or history is always just the first page.
.screen, .history => .{ .page = self.pages.first.? },
.viewport => switch (self.viewport) {
.active => self.active,
// If the viewport is in the active area then its the same as active.
.active => self.getTopLeft(.active),
},
// The active area is calculated backwards from the last page.
// This makes getting the active top left slower but makes scrolling
// much faster because we don't need to update the top left. Under
// heavy load this makes a measurable difference.
.active => active: {
var page = self.pages.last.?;
var rem = self.rows;
while (rem > page.data.size.rows) {
rem -= page.data.size.rows;
page = page.prev.?; // assertion: we always have enough rows for active
}
break :active .{
.page = page,
.row_offset = page.data.size.rows - rem,
};
},
};
}
@ -311,12 +329,12 @@ test "PageList" {
var s = try init(alloc, 80, 24, 1000);
defer s.deinit();
// Viewport is setup
try testing.expect(s.viewport == .active);
try testing.expect(s.active.page == s.pages.first);
try testing.expect(s.active.page.next == null);
try testing.expect(s.active.row_offset == 0);
try testing.expect(s.active.page.data.size.cols == 80);
try testing.expect(s.active.page.data.size.rows == 24);
try testing.expect(s.pages.first != null);
// Active area should be the top
try testing.expectEqual(RowOffset{
.page = s.pages.first.?,
.row_offset = 0,
}, s.getTopLeft(.active));
}

View File

@ -51,13 +51,17 @@ pub fn init(
rows: size.CellCountInt,
max_scrollback: usize,
) !Screen {
// Initialize our backing pages. This will initialize the viewport.
// Initialize our backing pages.
var pages = try PageList.init(alloc, cols, rows, max_scrollback);
errdefer pages.deinit();
// The viewport is guaranteed to exist, so grab it so we can setup
// our initial cursor.
const page_offset = pages.rowOffset(.{ .active = .{ .x = 0, .y = 0 } });
// The active area is guaranteed to be allocated and the first
// page in the list after init. This lets us quickly setup the cursor.
// This is MUCH faster than pages.rowOffset.
const page_offset: PageList.RowOffset = .{
.page = pages.pages.first.?,
.row_offset = 0,
};
const page_rac = page_offset.rowAndCell(0);
return .{
@ -146,13 +150,6 @@ pub fn cursorDownScroll(self: *Screen) !void {
self.cursor.page_offset = page_offset;
self.cursor.page_row = page_rac.row;
self.cursor.page_cell = page_rac.cell;
// try self.pages.scrollActive(1);
// const page_offset = self.pages.active.forward(self.cursor.y).?;
// const page_rac = page_offset.rowAndCell(self.cursor.x);
// self.cursor.page_offset = page_offset;
// self.cursor.page_row = page_rac.row;
// self.cursor.page_cell = page_rac.cell;
}
/// Dump the screen to a string. The writer given should be buffered;

View File

@ -461,12 +461,11 @@ test "Terminal: input that forces scroll" {
for ("abcdef") |c| try t.print(c);
try testing.expectEqual(@as(usize, 4), t.screen.cursor.y);
try testing.expectEqual(@as(usize, 0), t.screen.cursor.x);
// TODO once viewport is moved
// {
// const str = try t.plainString(alloc);
// defer alloc.free(str);
// try testing.expectEqualStrings("b\nc\nd\ne\nf", str);
// }
{
const str = try t.plainString(alloc);
defer alloc.free(str);
try testing.expectEqualStrings("b\nc\nd\ne\nf", str);
}
}
test "Terminal: zero-width character at start" {