wip(terminal): Fast path for scroll regions

This commit is contained in:
Qwerasd
2024-03-25 14:40:57 -06:00
parent 1ad973b274
commit 0a6ef3fda4
2 changed files with 75 additions and 24 deletions

View File

@ -1986,6 +1986,60 @@ fn destroyPageExt(
pool.nodes.destroy(page); pool.nodes.destroy(page);
} }
/// Fast-path function to erase exactly 1 row. Erasing means that the row
/// is completely removed, not just cleared. All rows below the removed row
/// will be moved up by 1 to account for this.
pub fn eraseRow(
self: *PageList,
pt: point.Point,
) !void {
const pn = self.pin(pt).?;
var page = pn.page;
var rows = page.data.rows.ptr(page.data.memory.ptr);
std.mem.rotate(Row, rows[pn.y..page.data.size.rows], 1);
{
var pin_it = self.tracked_pins.keyIterator();
while (pin_it.next()) |p_ptr| {
const p = p_ptr.*;
if (p.page == page and p.y > pn.y) p.y -= 1;
}
}
while (page.next) |next| {
const next_rows = next.data.rows.ptr(next.data.memory.ptr);
try page.data.cloneRowFrom(&next.data, &rows[page.data.size.rows - 1], &next_rows[0]);
page = next;
rows = next_rows;
std.mem.rotate(Row, rows[0..page.data.size.rows], 1);
var pin_it = self.tracked_pins.keyIterator();
while (pin_it.next()) |p_ptr| {
const p = p_ptr.*;
if (p.page != page) continue;
if (p.y == 0) {
p.page = page.prev.?;
p.y = p.page.data.size.rows - 1;
continue;
}
p.y -= 1;
}
}
// The final row needs to be cleared in case we re-use it.
page.data.clearCells(&rows[page.data.size.rows - 1], 0, page.data.size.cols);
// We don't trim off the final row if we erased active, since one of
// our invariants is that we always have full active space.
if (pt != .active) {
page.data.size.rows -= 1;
}
}
/// Erase the rows from the given top to bottom (inclusive). Erasing /// Erase the rows from the given top to bottom (inclusive). Erasing
/// the rows doesn't clear them but actually physically REMOVES the rows. /// the rows doesn't clear them but actually physically REMOVES the rows.
/// If the top or bottom point is in the middle of a page, the other /// If the top or bottom point is in the middle of a page, the other
@ -2040,20 +2094,20 @@ pub fn eraseRows(
dst.* = src.*; dst.* = src.*;
src.* = old_dst; src.* = old_dst;
// Clear the old data in case we reuse these cells. // // Clear the old data in case we reuse these cells.
chunk.page.data.clearCells(src, 0, chunk.page.data.size.cols); // chunk.page.data.clearCells(src, 0, chunk.page.data.size.cols);
} }
// Clear our remaining cells that we didn't shift or swapped // // Clear our remaining cells that we didn't shift or swapped
// in case we grow back into them. // // in case we grow back into them.
for (scroll_amount..chunk.page.data.size.rows) |i| { // for (scroll_amount..chunk.page.data.size.rows) |i| {
const row: *Row = &rows[i]; // const row: *Row = &rows[i];
chunk.page.data.clearCells( // chunk.page.data.clearCells(
row, // row,
0, // 0,
chunk.page.data.size.cols, // chunk.page.data.size.cols,
); // );
} // }
// Update any tracked pins to shift their y. If it was in the erased // Update any tracked pins to shift their y. If it was in the erased
// row then we move it to the top of this page. // row then we move it to the top of this page.

View File

@ -535,9 +535,15 @@ pub fn cursorDownScroll(self: *Screen) !void {
// If we have a single-row screen, we have no rows to shift // If we have a single-row screen, we have no rows to shift
// so our cursor is in the correct place we just have to clear // so our cursor is in the correct place we just have to clear
// the cells. // the cells.
if (self.pages.rows > 1) { if (self.pages.rows == 1) {
// Erase rows will shift our rows up self.clearCells(
self.pages.eraseRows(.{ .active = .{} }, .{ .active = .{} }); &self.cursor.page_pin.page.data,
self.cursor.page_row,
self.cursor.page_pin.page.data.getCells(self.cursor.page_row),
);
} else {
// eraseRow will shift everything below it up.
try self.pages.eraseRow(.{ .active = .{} });
// The above may clear our cursor so we need to update that // The above may clear our cursor so we need to update that
// again. If this fails (highly unlikely) we just reset // again. If this fails (highly unlikely) we just reset
@ -561,15 +567,6 @@ pub fn cursorDownScroll(self: *Screen) !void {
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;
} }
// Erase rows does NOT clear the cells because in all other cases
// we never write those rows again. Active erasing is a bit
// different so we manually clear our one row.
self.clearCells(
&self.cursor.page_pin.page.data,
self.cursor.page_row,
self.cursor.page_pin.page.data.getCells(self.cursor.page_row),
);
} else { } else {
const old_pin = self.cursor.page_pin.*; const old_pin = self.cursor.page_pin.*;