mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
wip(terminal): Fast path for scroll regions
This commit is contained in:
@ -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.
|
||||||
|
@ -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.*;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user