- commit
- 7bb755b
- parent
- 280e122
- author
- Eric Bower
- date
- 2025-10-15 14:41:04 -0400 EDT
chore: Wide/Double-Width Character Handling
1 files changed,
+34,
-1
+34,
-1
1@@ -49,7 +49,13 @@ pub fn render(vt: *ghostty.Terminal, allocator: std.mem.Allocator) ![]u8 {
2 const cells = page.getCells(row);
3
4 // Extract text from each cell in the row
5- for (cells, 0..) |*cell, col_idx| {
6+ var col_idx: usize = 0;
7+ while (col_idx < cells.len) : (col_idx += 1) {
8+ const cell = &cells[col_idx];
9+
10+ // Skip spacer cells (already handled by extractCellText, but we still need to skip the iteration)
11+ if (cell.wide == .spacer_tail or cell.wide == .spacer_head) continue;
12+
13 // Create a pin for this specific cell to access graphemes
14 const cell_pin = ghostty.Pin{
15 .node = pin.node,
16@@ -58,6 +64,11 @@ pub fn render(vt: *ghostty.Terminal, allocator: std.mem.Allocator) ![]u8 {
17 };
18
19 try extractCellText(cell_pin, cell, &output, allocator);
20+
21+ // If this is a wide character, skip the next cell (spacer_tail)
22+ if (cell.wide == .wide) {
23+ col_idx += 1; // Skip the spacer cell that follows
24+ }
25 }
26
27 // Add newline after each row
28@@ -160,3 +171,25 @@ test "extractCellText: multi-codepoint grapheme (emoji)" {
29 // Should have both codepoints encoded as UTF-8
30 try testing.expect(buf.items.len > 4); // At least 2 multi-byte UTF-8 sequences
31 }
32+
33+test "wide character handling: skip spacer cells" {
34+ const testing = std.testing;
35+ const allocator = testing.allocator;
36+
37+ var vt = try ghostty.Terminal.init(allocator, 80, 24, 100);
38+ defer vt.deinit(allocator);
39+
40+ // Write wide character (emoji) followed by ASCII
41+ try vt.print(0x1F44B); // 👋 (wide, takes 2 cells)
42+ try vt.print('A');
43+ try vt.print('B');
44+
45+ // Render the terminal
46+ const result = try render(&vt, allocator);
47+ defer allocator.free(result);
48+
49+ // Should have emoji + AB + newline (not emoji + A + B with drift)
50+ // The emoji is UTF-8 encoded, so we just check we have content
51+ try testing.expect(result.len > 0);
52+ try testing.expect(std.mem.indexOf(u8, result, "AB") != null);
53+}