terminal/new: pagelist resize to 1 col deletes wide chars

This commit is contained in:
Mitchell Hashimoto
2024-03-04 11:33:06 -08:00
parent 93e63d5356
commit 6b90b6f2b0

View File

@ -593,10 +593,6 @@ const ReflowCursor = struct {
self.y = y;
}
fn copyRowMetadata(self: *ReflowCursor, other: *const Row) void {
self.page_row.semantic_prompt = other.semantic_prompt;
}
fn countTrailingEmptyCells(self: *const ReflowCursor) usize {
// If the row is wrapped, all empty cells are meaningful.
if (self.page_row.wrap) return 0;
@ -614,6 +610,10 @@ const ReflowCursor = struct {
return len;
}
fn copyRowMetadata(self: *ReflowCursor, other: *const Row) void {
self.page_row.semantic_prompt = other.semantic_prompt;
}
};
/// Reflow the given page into the new capacity. The new capacity can have
@ -728,6 +728,30 @@ fn reflowPage(
dst_cursor.copyRowMetadata(src_cursor.page_row);
}
// A rare edge case. If we're resizing down to 1 column
// and the source is a non-narrow character, we reset the
// cell to a narrow blank and we skip to the next cell.
if (cap.cols == 1 and src_cursor.page_cell.wide != .narrow) {
switch (src_cursor.page_cell.wide) {
.narrow => unreachable,
// Wide char, we delete it, reset it to narrow,
// and skip forward.
.wide => {
dst_cursor.page_cell.content.codepoint = 0;
dst_cursor.page_cell.wide = .narrow;
src_cursor.cursorForward();
continue;
},
// Skip spacer tails since we should've already
// handled them in the previous cell.
.spacer_tail => {},
// TODO: test?
.spacer_head => {},
}
} else {
switch (src_cursor.page_cell.content_tag) {
// These are guaranteed to have no styling data and no
// graphemes, a fast path.
@ -776,6 +800,7 @@ fn reflowPage(
dst_md.ref += 1;
dst_cursor.page_cell.style_id = dst_md.id;
}
}
// If our original cursor was on this page, this x/y then
// we need to update to the new location.
@ -3787,3 +3812,48 @@ test "PageList resize reflow less cols copy style" {
}
}
}
test "PageList resize reflow less cols to eliminate a wide char" {
const testing = std.testing;
const alloc = testing.allocator;
var s = try init(alloc, 2, 1, 0);
defer s.deinit();
{
try testing.expect(s.pages.first == s.pages.last);
const page = &s.pages.first.?.data;
{
const rac = page.getRowAndCell(0, 0);
rac.cell.* = .{
.content_tag = .codepoint,
.content = .{ .codepoint = '😀' },
.wide = .wide,
};
}
{
const rac = page.getRowAndCell(1, 0);
rac.cell.* = .{
.content_tag = .codepoint,
.content = .{ .codepoint = ' ' },
.wide = .spacer_tail,
};
}
}
// Resize
try s.resize(.{ .cols = 1, .reflow = true });
try testing.expectEqual(@as(usize, 1), s.cols);
try testing.expectEqual(@as(usize, 1), s.totalRows());
{
try testing.expect(s.pages.first == s.pages.last);
const page = &s.pages.first.?.data;
{
const rac = page.getRowAndCell(0, 0);
try testing.expectEqual(@as(u21, 0), rac.cell.content.codepoint);
try testing.expectEqual(pagepkg.Cell.Wide.narrow, rac.cell.wide);
}
}
}