terminal: insertLines/deleteLines handle split across pages

This commit is contained in:
Mitchell Hashimoto
2024-03-18 20:47:38 -07:00
parent 2b50bd5305
commit 5e1f8b6cc4
2 changed files with 76 additions and 48 deletions

View File

@ -1270,12 +1270,24 @@ pub fn insertLines(self: *Terminal, count: usize) void {
var it = bot.rowIterator(.left_up, top); var it = bot.rowIterator(.left_up, top);
while (it.next()) |p| { while (it.next()) |p| {
const dst_p = p.down(adjusted_count).?; const dst_p = p.down(adjusted_count).?;
assert(dst_p.page == p.page); // TODO: handle different pages
const src: *Row = p.rowAndCell().row; const src: *Row = p.rowAndCell().row;
const dst: *Row = dst_p.rowAndCell().row; const dst: *Row = dst_p.rowAndCell().row;
if (!left_right) { if (!left_right) {
// If the pages are not the same, we need to do a slow copy.
if (dst_p.page != p.page) {
dst_p.page.data.cloneRowFrom(
&p.page.data,
dst,
src,
) catch |err| {
std.log.warn("TODO: insertLines handle clone error err={}", .{err});
unreachable;
};
continue;
}
// Swap the src/dst cells. This ensures that our dst gets the proper // Swap the src/dst cells. This ensures that our dst gets the proper
// shifted rows and src gets non-garbage cell data that we can clear. // shifted rows and src gets non-garbage cell data that we can clear.
const dst_row = dst.*; const dst_row = dst.*;
@ -1284,6 +1296,8 @@ pub fn insertLines(self: *Terminal, count: usize) void {
continue; continue;
} }
assert(dst_p.page == p.page); // TODO: handle different pages for left/right
// Left/right scroll margins we have to copy cells, which is much slower... // Left/right scroll margins we have to copy cells, which is much slower...
var page = &self.screen.cursor.page_pin.page.data; var page = &self.screen.cursor.page_pin.page.data;
page.moveCells( page.moveCells(
@ -1369,12 +1383,24 @@ pub fn deleteLines(self: *Terminal, count_req: usize) void {
var it = top.rowIterator(.right_down, bot); var it = top.rowIterator(.right_down, bot);
while (it.next()) |p| { while (it.next()) |p| {
const src_p = p.down(count).?; const src_p = p.down(count).?;
assert(src_p.page == p.page); // TODO: handle different pages
const src: *Row = src_p.rowAndCell().row; const src: *Row = src_p.rowAndCell().row;
const dst: *Row = p.rowAndCell().row; const dst: *Row = p.rowAndCell().row;
if (!left_right) { if (!left_right) {
// If the pages are not the same, we need to do a slow copy.
if (src_p.page != p.page) {
p.page.data.cloneRowFrom(
&src_p.page.data,
dst,
src,
) catch |err| {
std.log.warn("TODO: deleteLines handle clone error err={}", .{err});
unreachable;
};
continue;
}
// Swap the src/dst cells. This ensures that our dst gets the proper // Swap the src/dst cells. This ensures that our dst gets the proper
// shifted rows and src gets non-garbage cell data that we can clear. // shifted rows and src gets non-garbage cell data that we can clear.
const dst_row = dst.*; const dst_row = dst.*;
@ -1383,6 +1409,8 @@ pub fn deleteLines(self: *Terminal, count_req: usize) void {
continue; continue;
} }
assert(src_p.page == p.page); // TODO: handle different pages for left/right
// Left/right scroll margins we have to copy cells, which is much slower... // Left/right scroll margins we have to copy cells, which is much slower...
var page = &self.screen.cursor.page_pin.page.data; var page = &self.screen.cursor.page_pin.page.data;
page.moveCells( page.moveCells(

View File

@ -240,7 +240,20 @@ pub const Page = struct {
const other_rows = other.rows.ptr(other.memory)[y_start..y_end]; const other_rows = other.rows.ptr(other.memory)[y_start..y_end];
const rows = self.rows.ptr(self.memory)[0 .. y_end - y_start]; const rows = self.rows.ptr(self.memory)[0 .. y_end - y_start];
for (rows, other_rows) |*dst_row, *src_row| { for (rows, other_rows) |*dst_row, *src_row| try self.cloneRowFrom(
other,
dst_row,
src_row,
);
}
/// Clone a single row from another page into this page.
pub fn cloneRowFrom(
self: *Page,
other: *const Page,
dst_row: *Row,
src_row: *const Row,
) !void {
// Copy all the row metadata but keep our cells offset // Copy all the row metadata but keep our cells offset
const cells_offset = dst_row.cells; const cells_offset = dst_row.cells;
dst_row.* = src_row.*; dst_row.* = src_row.*;
@ -253,7 +266,7 @@ pub const Page = struct {
// If we have no managed memory in the row, we can just copy. // If we have no managed memory in the row, we can just copy.
if (!dst_row.grapheme and !dst_row.styled) { if (!dst_row.grapheme and !dst_row.styled) {
fastmem.copy(Cell, cells, other_cells); fastmem.copy(Cell, cells, other_cells);
continue; return;
} }
// We have managed memory, so we have to do a slower copy to // We have managed memory, so we have to do a slower copy to
@ -273,7 +286,6 @@ pub const Page = struct {
} }
} }
} }
}
/// Get a single row. y must be valid. /// Get a single row. y must be valid.
pub fn getRow(self: *const Page, y: usize) *Row { pub fn getRow(self: *const Page, y: usize) *Row {
@ -602,21 +614,9 @@ pub const Capacity = struct {
// for rows & cells (which will allow us to calculate the number of // for rows & cells (which will allow us to calculate the number of
// rows we can fit at a certain column width) we need to layout the // rows we can fit at a certain column width) we need to layout the
// "meta" members of the page (i.e. everything else) from the end. // "meta" members of the page (i.e. everything else) from the end.
const grapheme_map_start = alignBackward( const grapheme_map_start = alignBackward(usize, layout.total_size - layout.grapheme_map_layout.total_size, GraphemeMap.base_align);
usize, const grapheme_alloc_start = alignBackward(usize, grapheme_map_start - layout.grapheme_alloc_layout.total_size, GraphemeAlloc.base_align);
layout.total_size - layout.grapheme_map_layout.total_size, const styles_start = alignBackward(usize, grapheme_alloc_start - layout.styles_layout.total_size, style.Set.base_align);
GraphemeMap.base_align
);
const grapheme_alloc_start = alignBackward(
usize,
grapheme_map_start - layout.grapheme_alloc_layout.total_size,
GraphemeAlloc.base_align
);
const styles_start = alignBackward(
usize,
grapheme_alloc_start - layout.styles_layout.total_size,
style.Set.base_align
);
const available_size = styles_start; const available_size = styles_start;
const size_per_row = @sizeOf(Row) + (@sizeOf(Cell) * @as(usize, @intCast(cols))); const size_per_row = @sizeOf(Row) + (@sizeOf(Cell) * @as(usize, @intCast(cols)));