aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/src/terminal/Terminal.zig
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-06-01 23:05:23 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-06-01 23:05:51 +0300
commit5bd21b7ed468b5ff4d1a5b2ed7e211f401eb138a (patch)
tree672fa4625cca0ecb3e9376fc7f8e33d7b0e9deef /vendor/libghostty-vt/src/terminal/Terminal.zig
parent32abb3776668ee768200019c170956f67fe33a86 (diff)
chore: update libghostty vendor
refs #276
Diffstat (limited to 'vendor/libghostty-vt/src/terminal/Terminal.zig')
-rw-r--r--vendor/libghostty-vt/src/terminal/Terminal.zig37
1 files changed, 29 insertions, 8 deletions
diff --git a/vendor/libghostty-vt/src/terminal/Terminal.zig b/vendor/libghostty-vt/src/terminal/Terminal.zig
index 6740a93e..d41e4750 100644
--- a/vendor/libghostty-vt/src/terminal/Terminal.zig
+++ b/vendor/libghostty-vt/src/terminal/Terminal.zig
@@ -377,20 +377,20 @@ pub fn print(self: *Terminal, c: u21) !void {
// necessarily a grapheme break.
if (prev.cell.codepoint() == 0) break :grapheme;
+ var previous_codepoint: u21 = prev.cell.content.codepoint;
const grapheme_break = brk: {
var state: uucode.grapheme.BreakState = .default;
- var cp1: u21 = prev.cell.content.codepoint;
if (prev.cell.hasGrapheme()) {
const cps = self.screens.active.cursor.page_pin.node.data.lookupGrapheme(prev.cell).?;
for (cps) |cp2| {
- // log.debug("cp1={x} cp2={x}", .{ cp1, cp2 });
- assert(!unicode.graphemeBreak(cp1, cp2, &state));
- cp1 = cp2;
+ // log.debug("cp1={x} cp2={x}", .{ previous_codepoint, cp2 });
+ assert(!unicode.graphemeBreak(previous_codepoint, cp2, &state));
+ previous_codepoint = cp2;
}
}
- // log.debug("cp1={x} cp2={x} end", .{ cp1, c });
- break :brk unicode.graphemeBreak(cp1, c, &state);
+ // log.debug("cp1={x} cp2={x} end", .{ previous_codepoint, c });
+ break :brk unicode.graphemeBreak(previous_codepoint, c, &state);
};
// If we can NOT break, this means that "c" is part of a grapheme
@@ -402,7 +402,7 @@ pub fn print(self: *Terminal, c: u21) !void {
// the cell width accordingly. VS16 makes the character wide and
// VS15 makes it narrow.
if (c == 0xFE0F or c == 0xFE0E) {
- const prev_props = unicode.table.get(prev.cell.content.codepoint);
+ const prev_props = unicode.table.get(previous_codepoint);
// Check if it is a valid variation sequence in
// emoji-variation-sequences.txt, and if not, ignore the char.
if (!prev_props.emoji_vs_base) return;
@@ -3318,7 +3318,7 @@ test "Terminal: zero-width character at start" {
try testing.expect(!t.isDirty(.{ .screen = .{ .x = 0, .y = 0 } }));
}
-// https://github.com/ghostty-org/ghostty/issues/12581
+// https://github.com/ghostty-org/ghostty/pull/12581
test "Terminal: zero-width character attaches to pending wrap cell" {
var t = try init(testing.allocator, .{ .cols = 2, .rows = 2 });
defer t.deinit(testing.allocator);
@@ -3741,6 +3741,27 @@ test "Terminal: invalid VS16 doesn't mark dirty" {
try testing.expect(!t.isDirty(.{ .screen = .{ .x = 0, .y = 0 } }));
}
+// https://github.com/ghostty-org/ghostty/pull/12596
+test "Terminal: variation selectors apply to preceding codepoint" {
+ var t = try init(testing.allocator, .{ .cols = 5, .rows = 5 });
+ defer t.deinit(testing.allocator);
+
+ // Enable grapheme clustering
+ t.modes.set(.grapheme_cluster, true);
+
+ // Pirate flag: black flag + ZWJ + skull and crossbones + VS16.
+ try t.print(0x1F3F4);
+ try t.print(0x200D);
+ try t.print(0x2620);
+ try t.print(0xFE0F);
+
+ const list_cell = t.screens.active.pages.getCell(.{ .screen = .{ .x = 0, .y = 0 } }).?;
+ const cell = list_cell.cell;
+ try testing.expectEqual(@as(u21, 0x1F3F4), cell.content.codepoint);
+ try testing.expect(cell.hasGrapheme());
+ try testing.expectEqualSlices(u21, &.{ 0x200D, 0x2620, 0xFE0F }, list_cell.node.data.lookupGrapheme(cell).?);
+}
+
test "Terminal: print multicodepoint grapheme, mode 2027" {
var t = try init(testing.allocator, .{ .cols = 80, .rows = 80 });
defer t.deinit(testing.allocator);