mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
terminal: add a test to verify our grapheme state is what we expect
This commit is contained in:
@ -489,12 +489,19 @@ pub const Row = struct {
|
|||||||
return .{ .row = self };
|
return .{ .row = self };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the number of codepoints in the cell at column x,
|
||||||
|
/// including the primary codepoint.
|
||||||
|
pub fn codepointLen(self: Row, x: usize) usize {
|
||||||
|
var it = self.codepointIterator(x);
|
||||||
|
return it.len() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
/// Read-only iterator for the grapheme codepoints in a cell. This only
|
/// Read-only iterator for the grapheme codepoints in a cell. This only
|
||||||
/// iterates over the EXTRA GRAPHEME codepoints and not the primary
|
/// iterates over the EXTRA GRAPHEME codepoints and not the primary
|
||||||
/// codepoint in cell.char.
|
/// codepoint in cell.char.
|
||||||
pub fn codepointIterator(self: Row, x: usize) CodepointIterator {
|
pub fn codepointIterator(self: Row, x: usize) CodepointIterator {
|
||||||
const cell = &self.storage[x + 1].cell;
|
const cell = &self.storage[x + 1].cell;
|
||||||
assert(cell.attrs.grapheme);
|
if (!cell.attrs.grapheme) return .{ .data = .{ .zero = {} } };
|
||||||
|
|
||||||
const key = self.getId() + x + 1;
|
const key = self.getId() + x + 1;
|
||||||
const data: GraphemeData = self.screen.graphemes.get(key) orelse data: {
|
const data: GraphemeData = self.screen.graphemes.get(key) orelse data: {
|
||||||
@ -543,6 +550,18 @@ pub const CodepointIterator = struct {
|
|||||||
data: GraphemeData,
|
data: GraphemeData,
|
||||||
i: usize = 0,
|
i: usize = 0,
|
||||||
|
|
||||||
|
/// Returns the number of codepoints in the iterator.
|
||||||
|
pub fn len(self: CodepointIterator) usize {
|
||||||
|
switch (self.data) {
|
||||||
|
.zero => return 0,
|
||||||
|
.one => return 1,
|
||||||
|
.two => return 2,
|
||||||
|
.three => return 3,
|
||||||
|
.four => return 4,
|
||||||
|
.many => |v| return v.len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn next(self: *CodepointIterator) ?u21 {
|
pub fn next(self: *CodepointIterator) ?u21 {
|
||||||
switch (self.data) {
|
switch (self.data) {
|
||||||
.zero => return null,
|
.zero => return null,
|
||||||
|
@ -1630,6 +1630,61 @@ test "Terminal: print over wide char at 0,0" {
|
|||||||
try testing.expectEqual(@as(usize, 1), t.screen.cursor.x);
|
try testing.expectEqual(@as(usize, 1), t.screen.cursor.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "Terminal: print multicodepoint grapheme" {
|
||||||
|
var t = try init(testing.allocator, 80, 80);
|
||||||
|
defer t.deinit(testing.allocator);
|
||||||
|
|
||||||
|
// https://github.com/mitchellh/ghostty/issues/289
|
||||||
|
// This is: 👨👩👧 (which may or may not render correctly)
|
||||||
|
try t.print(0x1F468);
|
||||||
|
try t.print(0x200D);
|
||||||
|
try t.print(0x1F469);
|
||||||
|
try t.print(0x200D);
|
||||||
|
try t.print(0x1F467);
|
||||||
|
|
||||||
|
// We should have 6 cells taken up
|
||||||
|
try testing.expectEqual(@as(usize, 0), t.screen.cursor.y);
|
||||||
|
try testing.expectEqual(@as(usize, 6), t.screen.cursor.x);
|
||||||
|
|
||||||
|
// Assert various properties about our screen to verify
|
||||||
|
// we have all expected cells.
|
||||||
|
const row = t.screen.getRow(.{ .screen = 0 });
|
||||||
|
{
|
||||||
|
const cell = row.getCell(0);
|
||||||
|
try testing.expectEqual(@as(u32, 0x1F468), cell.char);
|
||||||
|
try testing.expect(cell.attrs.wide);
|
||||||
|
try testing.expectEqual(@as(usize, 2), row.codepointLen(0));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const cell = row.getCell(1);
|
||||||
|
try testing.expectEqual(@as(u32, ' '), cell.char);
|
||||||
|
try testing.expect(cell.attrs.wide_spacer_tail);
|
||||||
|
try testing.expectEqual(@as(usize, 1), row.codepointLen(1));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const cell = row.getCell(2);
|
||||||
|
try testing.expectEqual(@as(u32, 0x1F469), cell.char);
|
||||||
|
try testing.expect(cell.attrs.wide);
|
||||||
|
try testing.expectEqual(@as(usize, 2), row.codepointLen(2));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const cell = row.getCell(3);
|
||||||
|
try testing.expectEqual(@as(u32, ' '), cell.char);
|
||||||
|
try testing.expect(cell.attrs.wide_spacer_tail);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const cell = row.getCell(4);
|
||||||
|
try testing.expectEqual(@as(u32, 0x1F467), cell.char);
|
||||||
|
try testing.expect(cell.attrs.wide);
|
||||||
|
try testing.expectEqual(@as(usize, 1), row.codepointLen(4));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const cell = row.getCell(5);
|
||||||
|
try testing.expectEqual(@as(u32, ' '), cell.char);
|
||||||
|
try testing.expect(cell.attrs.wide_spacer_tail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
Reference in New Issue
Block a user