terminal/new: use new pagelist grow mechanism that prunes

This commit is contained in:
Mitchell Hashimoto
2024-02-27 10:29:12 -08:00
parent 79146e3abd
commit 345b246e06
2 changed files with 19 additions and 44 deletions

View File

@ -258,7 +258,9 @@ pub fn scroll(self: *PageList, behavior: Scroll) void {
/// This may allocate, but also may not if our current page has more /// This may allocate, but also may not if our current page has more
/// capacity we can use. This will prune scrollback if necessary to /// capacity we can use. This will prune scrollback if necessary to
/// adhere to max_size. /// adhere to max_size.
pub fn grow2(self: *PageList) !?*List.Node { ///
/// This returns the newly allocated page node if there is one.
pub fn grow(self: *PageList) !?*List.Node {
const last = self.pages.last.?; const last = self.pages.last.?;
if (last.data.capacity.rows > last.data.size.rows) { if (last.data.capacity.rows > last.data.size.rows) {
// Fast path: we have capacity in the last page. // Fast path: we have capacity in the last page.
@ -305,16 +307,6 @@ pub fn grow2(self: *PageList) !?*List.Node {
return next_page; return next_page;
} }
/// Grow the page list by exactly one page and return the new page. The
/// newly allocated page will be size 0 (but capacity is set).
pub fn grow(self: *PageList) !*List.Node {
const next_page = try self.createPage();
// we don't errdefer this because we've added it to the linked
// list and its fine to have dangling unused pages.
self.pages.append(next_page);
return next_page;
}
/// Create a new page node. This does not add it to the list and this /// Create a new page node. This does not add it to the list and this
/// does not do any memory size accounting with max_size/page_size. /// does not do any memory size accounting with max_size/page_size.
fn createPage(self: *PageList) !*List.Node { fn createPage(self: *PageList) !*List.Node {
@ -461,7 +453,7 @@ fn growRows(self: *PageList, n: usize) !void {
} }
while (n_rem > 0) { while (n_rem > 0) {
page = try self.grow(); page = (try self.grow()).?;
const add = @min(n_rem, page.data.capacity.rows); const add = @min(n_rem, page.data.capacity.rows);
page.data.size.rows = add; page.data.size.rows = add;
n_rem -= add; n_rem -= add;
@ -847,7 +839,7 @@ test "PageList grow fit in capacity" {
try testing.expect(last.size.rows < last.capacity.rows); try testing.expect(last.size.rows < last.capacity.rows);
// Grow // Grow
try testing.expect(try s.grow2() == null); try testing.expect(try s.grow() == null);
{ {
const pt = s.getCell(.{ .active = .{} }).?.screenPoint(); const pt = s.getCell(.{ .active = .{} }).?.screenPoint();
try testing.expectEqual(point.Point{ .screen = .{ try testing.expectEqual(point.Point{ .screen = .{
@ -868,11 +860,11 @@ test "PageList grow allocate" {
const last_node = s.pages.last.?; const last_node = s.pages.last.?;
const last = &s.pages.last.?.data; const last = &s.pages.last.?.data;
for (0..last.capacity.rows - last.size.rows) |_| { for (0..last.capacity.rows - last.size.rows) |_| {
try testing.expect(try s.grow2() == null); try testing.expect(try s.grow() == null);
} }
// Grow, should allocate // Grow, should allocate
const new = (try s.grow2()).?; const new = (try s.grow()).?;
try testing.expect(s.pages.last.? == new); try testing.expect(s.pages.last.? == new);
try testing.expect(last_node.next.? == new); try testing.expect(last_node.next.? == new);
{ {
@ -897,14 +889,14 @@ test "PageList grow prune scrollback" {
const page1_node = s.pages.last.?; const page1_node = s.pages.last.?;
const page1 = page1_node.data; const page1 = page1_node.data;
for (0..page1.capacity.rows - page1.size.rows) |_| { for (0..page1.capacity.rows - page1.size.rows) |_| {
try testing.expect(try s.grow2() == null); try testing.expect(try s.grow() == null);
} }
// Grow and allocate one more page. Then fill that page up. // Grow and allocate one more page. Then fill that page up.
const page2_node = (try s.grow2()).?; const page2_node = (try s.grow()).?;
const page2 = page2_node.data; const page2 = page2_node.data;
for (0..page2.capacity.rows - page2.size.rows) |_| { for (0..page2.capacity.rows - page2.size.rows) |_| {
try testing.expect(try s.grow2() == null); try testing.expect(try s.grow() == null);
} }
// Get our page size // Get our page size
@ -912,7 +904,7 @@ test "PageList grow prune scrollback" {
// Next should create a new page, but it should reuse our first // Next should create a new page, but it should reuse our first
// page since we're at max size. // page since we're at max size.
const new = (try s.grow2()).?; const new = (try s.grow()).?;
try testing.expect(s.pages.last.? == new); try testing.expect(s.pages.last.? == new);
try testing.expectEqual(s.page_size, old_page_size); try testing.expectEqual(s.page_size, old_page_size);

View File

@ -226,31 +226,14 @@ pub fn cursorAbsolute(self: *Screen, x: size.CellCountInt, y: size.CellCountInt)
pub fn cursorDownScroll(self: *Screen) !void { pub fn cursorDownScroll(self: *Screen) !void {
assert(self.cursor.y == self.pages.rows - 1); assert(self.cursor.y == self.pages.rows - 1);
const cursor_page = self.cursor.page_offset.page; // Grow our pages by one row. The PageList will handle if we need to
if (cursor_page.data.capacity.rows > cursor_page.data.size.rows) { // allocate, prune scrollback, whatever.
// If we have cap space in our current cursor page then we can take _ = try self.pages.grow();
// a fast path: update the size, recalculate the row/cell cursor pointers.
cursor_page.data.size.rows += 1;
const page_offset = self.cursor.page_offset.forward(1).?; const page_offset = self.cursor.page_offset.forward(1).?;
const page_rac = page_offset.rowAndCell(self.cursor.x); const page_rac = page_offset.rowAndCell(self.cursor.x);
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;
} else {
// No space, we need to allocate a new page and move the cursor to it.
const new_page = try self.pages.grow();
assert(new_page.data.size.rows == 0);
new_page.data.size.rows = 1;
const page_offset: PageList.RowOffset = .{
.page = new_page,
.row_offset = 0,
};
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;
}
// The newly created line needs to be styled according to the bg color // The newly created line needs to be styled according to the bg color
// if it is set. // if it is set.