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 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
|
// Write
|
||||||
self.screen.cursor.page_cell.* = .{
|
cell.* = .{
|
||||||
.style_id = self.screen.cursor.style_id,
|
.style_id = self.screen.cursor.style_id,
|
||||||
.codepoint = c,
|
.codepoint = c,
|
||||||
.wide = wide,
|
.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" {
|
test "Terminal: soft wrap" {
|
||||||
var t = try init(testing.allocator, 3, 80);
|
var t = try init(testing.allocator, 3, 80);
|
||||||
defer t.deinit(testing.allocator);
|
defer t.deinit(testing.allocator);
|
||||||
|
@ -268,6 +268,30 @@ pub const Page = struct {
|
|||||||
return slice.offset.ptr(self.memory)[0..slice.len];
|
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 {
|
pub const Layout = struct {
|
||||||
total_size: usize,
|
total_size: usize,
|
||||||
rows_start: usize,
|
rows_start: usize,
|
||||||
@ -577,6 +601,11 @@ test "Page appendGrapheme small" {
|
|||||||
try testing.expect(rac.row.grapheme);
|
try testing.expect(rac.row.grapheme);
|
||||||
try testing.expect(rac.cell.grapheme);
|
try testing.expect(rac.cell.grapheme);
|
||||||
try testing.expectEqualSlices(u21, &.{ 0x0A, 0x0B }, page.lookupGrapheme(rac.cell).?);
|
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" {
|
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]);
|
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