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 /// - history: active row minus one
/// ///
viewport: Viewport, viewport: Viewport,
active: RowOffset,
/// The current desired screen dimensions. I say "desired" because individual /// The current desired screen dimensions. I say "desired" because individual
/// pages may still be a different size and not yet reflowed since we lazily /// 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, .page_pool = page_pool,
.pages = page_list, .pages = page_list,
.viewport = .{ .active = {} }, .viewport = .{ .active = {} },
.active = .{ .page = page },
}; };
} }
@ -224,10 +222,30 @@ pub fn rowIterator(
/// Get the top-left of the screen for the given tag. /// Get the top-left of the screen for the given tag.
fn getTopLeft(self: *const PageList, tag: point.Tag) RowOffset { fn getTopLeft(self: *const PageList, tag: point.Tag) RowOffset {
return switch (tag) { return switch (tag) {
.active => self.active, // The full screen or history is always just the first page.
.screen, .history => .{ .page = self.pages.first.? }, .screen, .history => .{ .page = self.pages.first.? },
.viewport => switch (self.viewport) { .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); var s = try init(alloc, 80, 24, 1000);
defer s.deinit(); defer s.deinit();
// Viewport is setup
try testing.expect(s.viewport == .active); try testing.expect(s.viewport == .active);
try testing.expect(s.active.page == s.pages.first); try testing.expect(s.pages.first != null);
try testing.expect(s.active.page.next == null);
try testing.expect(s.active.row_offset == 0); // Active area should be the top
try testing.expect(s.active.page.data.size.cols == 80); try testing.expectEqual(RowOffset{
try testing.expect(s.active.page.data.size.rows == 24); .page = s.pages.first.?,
.row_offset = 0,
}, s.getTopLeft(.active));
} }

View File

@ -51,13 +51,17 @@ pub fn init(
rows: size.CellCountInt, rows: size.CellCountInt,
max_scrollback: usize, max_scrollback: usize,
) !Screen { ) !Screen {
// Initialize our backing pages. This will initialize the viewport. // Initialize our backing pages.
var pages = try PageList.init(alloc, cols, rows, max_scrollback); var pages = try PageList.init(alloc, cols, rows, max_scrollback);
errdefer pages.deinit(); errdefer pages.deinit();
// The viewport is guaranteed to exist, so grab it so we can setup // The active area is guaranteed to be allocated and the first
// our initial cursor. // page in the list after init. This lets us quickly setup the cursor.
const page_offset = pages.rowOffset(.{ .active = .{ .x = 0, .y = 0 } }); // 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); const page_rac = page_offset.rowAndCell(0);
return .{ return .{
@ -146,13 +150,6 @@ pub fn cursorDownScroll(self: *Screen) !void {
self.cursor.page_offset = page_offset; self.cursor.page_offset = page_offset;
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;
// 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; /// 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); for ("abcdef") |c| try t.print(c);
try testing.expectEqual(@as(usize, 4), t.screen.cursor.y); try testing.expectEqual(@as(usize, 4), t.screen.cursor.y);
try testing.expectEqual(@as(usize, 0), t.screen.cursor.x); try testing.expectEqual(@as(usize, 0), t.screen.cursor.x);
// TODO once viewport is moved {
// { const str = try t.plainString(alloc);
// const str = try t.plainString(alloc); defer alloc.free(str);
// defer alloc.free(str); try testing.expectEqualStrings("b\nc\nd\ne\nf", str);
// try testing.expectEqualStrings("b\nc\nd\ne\nf", str); }
// }
} }
test "Terminal: zero-width character at start" { test "Terminal: zero-width character at start" {