terminal: moveCell handles graphemes, clears source

This commit is contained in:
Mitchell Hashimoto
2024-03-21 15:04:16 -07:00
parent 2d8810b4be
commit 8142eb9678

View File

@ -335,17 +335,33 @@ pub const Page = struct {
const src_cells = src_row.cells.ptr(self.memory)[src_left .. src_left + len];
const dst_cells = dst_row.cells.ptr(self.memory)[dst_left .. dst_left + len];
// If src has no graphemes, this is very fast.
// Clear our destination now matter what
self.clearCells(dst_row, dst_left, dst_left + len);
// If src has no graphemes, this is very fast because we can
// just copy the cells directly because every other attribute
// is position-independent.
const src_grapheme = src_row.grapheme or grapheme: {
for (src_cells) |c| if (c.hasGrapheme()) break :grapheme true;
break :grapheme false;
};
if (!src_grapheme) {
fastmem.copy(Cell, dst_cells, src_cells);
return;
} else {
// Source has graphemes, meaning we have to do a slower
// cell by cell copy.
for (src_cells, dst_cells) |*src, *dst| {
dst.* = src.*;
if (!src.hasGrapheme()) continue;
// Required for moveGrapheme assertions
dst.content_tag = .codepoint;
self.moveGrapheme(src, dst);
}
}
@panic("TODO: grapheme move");
// Clear our source row now that the copy is complete
self.clearCells(src_row, src_left, src_left + len);
}
/// Clear the cells in the given row. This will reclaim memory used
@ -453,6 +469,24 @@ pub const Page = struct {
return slice.offset.ptr(self.memory)[0..slice.len];
}
/// Move the graphemes from one cell to another. This can't fail
/// because we avoid any allocations since we're just moving data.
pub fn moveGrapheme(self: *const Page, src: *Cell, dst: *Cell) void {
if (comptime std.debug.runtime_safety) {
assert(src.hasGrapheme());
assert(!dst.hasGrapheme());
}
const src_offset = getOffset(Cell, self.memory, src);
const dst_offset = getOffset(Cell, self.memory, dst);
var map = self.grapheme_map.map(self.memory);
const entry = map.getEntry(src_offset).?;
const value = entry.value_ptr.*;
map.removeByPtr(entry.key_ptr);
map.putAssumeCapacity(dst_offset, value);
src.content_tag = .codepoint;
}
/// Clear the graphemes for a given cell.
pub fn clearGrapheme(self: *Page, row: *Row, cell: *Cell) void {
if (comptime std.debug.runtime_safety) assert(cell.hasGrapheme());
@ -1322,3 +1356,91 @@ test "Page cloneFrom frees dst graphemes" {
}
try testing.expectEqual(@as(usize, 0), page2.graphemeCount());
}
test "Page moveCells text-only" {
var page = try Page.init(.{
.cols = 10,
.rows = 10,
.styles = 8,
});
defer page.deinit();
// Write
for (0..page.capacity.cols) |x| {
const rac = page.getRowAndCell(x, 0);
rac.cell.* = .{
.content_tag = .codepoint,
.content = .{ .codepoint = @intCast(x + 1) },
};
}
const src = page.getRow(0);
const dst = page.getRow(1);
page.moveCells(src, 0, dst, 0, page.capacity.cols);
// New rows should have text
for (0..page.capacity.cols) |x| {
const rac = page.getRowAndCell(x, 1);
try testing.expectEqual(
@as(u21, @intCast(x + 1)),
rac.cell.content.codepoint,
);
}
// Old row should be blank
for (0..page.capacity.cols) |x| {
const rac = page.getRowAndCell(x, 0);
try testing.expectEqual(
@as(u21, 0),
rac.cell.content.codepoint,
);
}
}
test "Page moveCells graphemes" {
var page = try Page.init(.{
.cols = 10,
.rows = 10,
.styles = 8,
});
defer page.deinit();
// Write
for (0..page.capacity.cols) |x| {
const rac = page.getRowAndCell(x, 0);
rac.cell.* = .{
.content_tag = .codepoint,
.content = .{ .codepoint = @intCast(x + 1) },
};
try page.appendGrapheme(rac.row, rac.cell, 0x0A);
}
const original_count = page.graphemeCount();
const src = page.getRow(0);
const dst = page.getRow(1);
page.moveCells(src, 0, dst, 0, page.capacity.cols);
try testing.expectEqual(original_count, page.graphemeCount());
// New rows should have text
for (0..page.capacity.cols) |x| {
const rac = page.getRowAndCell(x, 1);
try testing.expectEqual(
@as(u21, @intCast(x + 1)),
rac.cell.content.codepoint,
);
try testing.expectEqualSlices(
u21,
&.{0x0A},
page.lookupGrapheme(rac.cell).?,
);
}
// Old row should be blank
for (0..page.capacity.cols) |x| {
const rac = page.getRowAndCell(x, 0);
try testing.expectEqual(
@as(u21, 0),
rac.cell.content.codepoint,
);
}
}