mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
terminal/new: clear graphemes on overwrite
This commit is contained in:
@ -513,10 +513,15 @@ fn printCell(
|
||||
}
|
||||
|
||||
// If the prior value had graphemes, clear those
|
||||
if (cell.grapheme) @panic("TODO: clear graphemes");
|
||||
if (cell.grapheme) {
|
||||
self.screen.cursor.page_offset.page.data.clearGrapheme(
|
||||
self.screen.cursor.page_row,
|
||||
cell,
|
||||
);
|
||||
}
|
||||
|
||||
// Write
|
||||
self.screen.cursor.page_cell.* = .{
|
||||
cell.* = .{
|
||||
.style_id = self.screen.cursor.style_id,
|
||||
.codepoint = c,
|
||||
.wide = wide,
|
||||
@ -1362,6 +1367,33 @@ test "Terminal: print invalid VS16 with second char" {
|
||||
}
|
||||
}
|
||||
|
||||
test "Terminal: overwrite grapheme should clear grapheme data" {
|
||||
var t = try init(testing.allocator, 5, 5);
|
||||
defer t.deinit(testing.allocator);
|
||||
|
||||
// Enable grapheme clustering
|
||||
t.modes.set(.grapheme_cluster, true);
|
||||
|
||||
try t.print(0x26C8); // Thunder cloud and rain
|
||||
try t.print(0xFE0E); // VS15 to make narrow
|
||||
t.setCursorPos(1, 1);
|
||||
try t.print('A');
|
||||
|
||||
{
|
||||
const str = try t.plainString(testing.allocator);
|
||||
defer testing.allocator.free(str);
|
||||
try testing.expectEqualStrings("A", str);
|
||||
}
|
||||
|
||||
{
|
||||
const list_cell = t.screen.pages.getCell(.{ .screen = .{ .x = 0, .y = 0 } }).?;
|
||||
const cell = list_cell.cell;
|
||||
try testing.expectEqual(@as(u21, 'A'), cell.codepoint);
|
||||
try testing.expect(!cell.grapheme);
|
||||
try testing.expectEqual(Cell.Wide.narrow, cell.wide);
|
||||
}
|
||||
}
|
||||
|
||||
test "Terminal: soft wrap" {
|
||||
var t = try init(testing.allocator, 3, 80);
|
||||
defer t.deinit(testing.allocator);
|
||||
|
@ -268,6 +268,30 @@ pub const Page = struct {
|
||||
return slice.offset.ptr(self.memory)[0..slice.len];
|
||||
}
|
||||
|
||||
/// Clear the graphemes for a given cell.
|
||||
pub fn clearGrapheme(self: *Page, row: *Row, cell: *Cell) void {
|
||||
assert(cell.grapheme);
|
||||
|
||||
// Get our entry in the map, which must exist
|
||||
const cell_offset = getOffset(Cell, self.memory, cell);
|
||||
var map = self.grapheme_map.map(self.memory);
|
||||
const entry = map.getEntry(cell_offset).?;
|
||||
|
||||
// Free our grapheme data
|
||||
const cps = entry.value_ptr.offset.ptr(self.memory)[0..entry.value_ptr.len];
|
||||
self.grapheme_alloc.free(self.memory, cps);
|
||||
|
||||
// Remove the entry
|
||||
map.removeByPtr(entry.key_ptr);
|
||||
|
||||
// Mark that we no longer have graphemes, also search the row
|
||||
// to make sure its state is correct.
|
||||
cell.grapheme = false;
|
||||
const cells = row.cells.ptr(self.memory)[0..self.size.cols];
|
||||
for (cells) |c| if (c.grapheme) return;
|
||||
row.grapheme = false;
|
||||
}
|
||||
|
||||
pub const Layout = struct {
|
||||
total_size: usize,
|
||||
rows_start: usize,
|
||||
@ -577,6 +601,11 @@ test "Page appendGrapheme small" {
|
||||
try testing.expect(rac.row.grapheme);
|
||||
try testing.expect(rac.cell.grapheme);
|
||||
try testing.expectEqualSlices(u21, &.{ 0x0A, 0x0B }, page.lookupGrapheme(rac.cell).?);
|
||||
|
||||
// Clear it
|
||||
page.clearGrapheme(rac.row, rac.cell);
|
||||
try testing.expect(!rac.row.grapheme);
|
||||
try testing.expect(!rac.cell.grapheme);
|
||||
}
|
||||
|
||||
test "Page appendGrapheme larger than chunk" {
|
||||
@ -601,3 +630,26 @@ test "Page appendGrapheme larger than chunk" {
|
||||
try testing.expectEqual(@as(u21, @intCast(0x0A + i)), cps[i]);
|
||||
}
|
||||
}
|
||||
|
||||
test "Page clearGrapheme not all cells" {
|
||||
var page = try Page.init(.{
|
||||
.cols = 10,
|
||||
.rows = 10,
|
||||
.styles = 8,
|
||||
});
|
||||
defer page.deinit();
|
||||
|
||||
const rac = page.getRowAndCell(0, 0);
|
||||
rac.cell.codepoint = 0x09;
|
||||
try page.appendGrapheme(rac.row, rac.cell, 0x0A);
|
||||
|
||||
const rac2 = page.getRowAndCell(1, 0);
|
||||
rac2.cell.codepoint = 0x09;
|
||||
try page.appendGrapheme(rac2.row, rac2.cell, 0x0A);
|
||||
|
||||
// Clear it
|
||||
page.clearGrapheme(rac.row, rac.cell);
|
||||
try testing.expect(rac.row.grapheme);
|
||||
try testing.expect(!rac.cell.grapheme);
|
||||
try testing.expect(rac2.cell.grapheme);
|
||||
}
|
||||
|
Reference in New Issue
Block a user