- commit
- 4b729ab
- parent
- 5ef4207
- author
- Eric Bower
- date
- 2025-10-14 10:12:35 -0400 EDT
refactor: renderTerminalSnapshot
1 files changed,
+77,
-5
+77,
-5
1@@ -736,16 +736,88 @@ fn renderTerminalSnapshot(session: *Session, allocator: std.mem.Allocator) ![]u8
2 // Get the active screen from the terminal
3 const screen = &session.vt.screen;
4 var it = screen.pages.pageIterator(.right_down, .{ .screen = .{} }, null);
5- var page_index: usize = 0;
6
7- while (it.next()) |chunk| : (page_index += 1) {
8+ var blank_rows: usize = 0;
9+ var blank_cells: usize = 0;
10+
11+ while (it.next()) |chunk| {
12 const page: *const ghostty.Page = &chunk.node.data;
13 const start_y = chunk.start;
14 const end_y = chunk.end;
15- }
16
17- // Add final newline if needed
18- try output.appendSlice(allocator, "\r\n");
19+ for (start_y..end_y) |y_usize| {
20+ const y: u16 = @intCast(y_usize);
21+ const row = page.getRow(y);
22+ const cells = page.getCells(row);
23+
24+ // Check if row has any text content
25+ const has_text = blk: {
26+ for (cells) |cell| {
27+ if (cell.hasText()) break :blk true;
28+ }
29+ break :blk false;
30+ };
31+
32+ // If row is blank, accumulate blank rows
33+ if (!has_text) {
34+ blank_rows += 1;
35+ continue;
36+ }
37+
38+ // Dump accumulated blank rows as newlines
39+ for (0..blank_rows) |_| {
40+ try output.appendSlice(allocator, "\r\n");
41+ }
42+ blank_rows = 0;
43+
44+ // If row doesn't continue a wrap, reset blank cells
45+ if (!row.wrap_continuation) blank_cells = 0;
46+
47+ // Write each cell in the row
48+ for (cells) |*cell| {
49+ // Skip spacer cells (wide character continuations)
50+ switch (cell.wide) {
51+ .narrow, .wide => {},
52+ .spacer_head, .spacer_tail => continue,
53+ }
54+
55+ // Accumulate blank cells
56+ if (!cell.hasText()) {
57+ blank_cells += 1;
58+ continue;
59+ }
60+
61+ // Dump accumulated blank cells as spaces
62+ if (blank_cells > 0) {
63+ for (0..blank_cells) |_| {
64+ try output.append(allocator, ' ');
65+ }
66+ blank_cells = 0;
67+ }
68+
69+ // Write the actual character
70+ const cp = cell.content.codepoint;
71+ var buf: [4]u8 = undefined;
72+ const len = std.unicode.utf8Encode(cp, &buf) catch continue;
73+ try output.appendSlice(allocator, buf[0..len]);
74+
75+ // Handle grapheme clusters (combining characters)
76+ if (cell.content_tag == .codepoint_grapheme) {
77+ if (page.lookupGrapheme(cell)) |grapheme| {
78+ for (grapheme) |gcp| {
79+ const glen = std.unicode.utf8Encode(gcp, &buf) catch continue;
80+ try output.appendSlice(allocator, buf[0..glen]);
81+ }
82+ }
83+ }
84+ }
85+
86+ // Add newline after each row (unless it wraps to the next)
87+ if (!row.wrap) {
88+ try output.appendSlice(allocator, "\r\n");
89+ }
90+ }
91+ }
92
93 // Position cursor at correct location (ANSI is 1-based)
94 const cursor = screen.cursor;