- commit
- abfa487
- parent
- 89393db
- author
- Eric Bower
- date
- 2025-10-10 21:10:50 -0400 EDT
fix: restore session
1 files changed,
+32,
-40
+32,
-40
1@@ -361,7 +361,7 @@ fn handleDetachSession(client: *Client, session_name: []const u8, target_client_
2
3 client.attached_session = null;
4 _ = session.attached_clients.remove(client.fd);
5-
6+
7 const response = "{\"type\":\"detach_session_response\",\"payload\":{\"status\":\"ok\"}}\n";
8 std.debug.print("Sending detach response to client fd={d}: {s}", .{ client.fd, response });
9
10@@ -515,40 +515,6 @@ fn handleAttachSession(ctx: *ServerContext, client: *Client, session_name: []con
11 client.attached_session = session.name;
12 try session.attached_clients.put(client.fd, {});
13
14- // If reattaching, send the current terminal state
15- if (is_reattach and session.attached_clients.count() > 1) {
16- const snapshot = try renderTerminalSnapshot(session, ctx.allocator);
17- defer ctx.allocator.free(snapshot);
18-
19- // Build JSON response with escaped snapshot
20- var response_buf = try std.ArrayList(u8).initCapacity(ctx.allocator, 4096);
21- defer response_buf.deinit(ctx.allocator);
22-
23- try response_buf.appendSlice(ctx.allocator, "{\"type\":\"pty_out\",\"payload\":{\"text\":\"");
24-
25- // Escape the snapshot for JSON
26- for (snapshot) |byte| {
27- switch (byte) {
28- '"' => try response_buf.appendSlice(ctx.allocator, "\\\""),
29- '\\' => try response_buf.appendSlice(ctx.allocator, "\\\\"),
30- '\n' => try response_buf.appendSlice(ctx.allocator, "\\n"),
31- '\r' => try response_buf.appendSlice(ctx.allocator, "\\r"),
32- '\t' => try response_buf.appendSlice(ctx.allocator, "\\t"),
33- 0x08 => try response_buf.appendSlice(ctx.allocator, "\\b"),
34- 0x0C => try response_buf.appendSlice(ctx.allocator, "\\f"),
35- 0x00...0x07, 0x0B, 0x0E...0x1F, 0x7F...0xFF => {
36- const escaped = try std.fmt.allocPrint(ctx.allocator, "\\u{x:0>4}", .{byte});
37- defer ctx.allocator.free(escaped);
38- try response_buf.appendSlice(ctx.allocator, escaped);
39- },
40- else => try response_buf.append(ctx.allocator, byte),
41- }
42- }
43-
44- try response_buf.appendSlice(ctx.allocator, "\"}}\n");
45- _ = try posix.write(client.fd, response_buf.items);
46- }
47-
48 // Start reading from PTY if not already started (first client)
49 if (session.attached_clients.count() == 1) {
50 try readFromPty(ctx, client, session);
51@@ -562,6 +528,32 @@ fn handleAttachSession(ctx: *ServerContext, client: *Client, session_name: []con
52 defer ctx.allocator.free(response);
53 _ = try posix.write(client.fd, response);
54 }
55+
56+ // If reattaching, send the current terminal state after attach response
57+ if (is_reattach) {
58+ const snapshot = try renderTerminalSnapshot(session, ctx.allocator);
59+ defer ctx.allocator.free(snapshot);
60+
61+ // Use Zig's JSON formatting to properly escape the snapshot
62+ var out: std.io.Writer.Allocating = .init(ctx.allocator);
63+ defer out.deinit();
64+
65+ var json_writer: std.json.Stringify = .{ .writer = &out.writer };
66+
67+ try json_writer.beginObject();
68+ try json_writer.objectField("type");
69+ try json_writer.write("pty_out");
70+ try json_writer.objectField("payload");
71+ try json_writer.beginObject();
72+ try json_writer.objectField("text");
73+ try json_writer.write(snapshot);
74+ try json_writer.endObject();
75+ try json_writer.endObject();
76+
77+ const response = try std.fmt.allocPrint(ctx.allocator, "{s}\n", .{out.written()});
78+ defer ctx.allocator.free(response);
79+ _ = try posix.write(client.fd, response);
80+ }
81 }
82
83 fn handlePtyInput(client: *Client, text: []const u8) !void {
84@@ -663,17 +655,17 @@ fn renderTerminalSnapshot(session: *Session, allocator: std.mem.Allocator) ![]u8
85 const screen = &session.vt.screen;
86 const rows = screen.pages.rows;
87 const cols = screen.pages.cols;
88-
89+
90 var row: usize = 0;
91 while (row < rows) : (row += 1) {
92 var col: usize = 0;
93 while (col < cols) : (col += 1) {
94 // Build a point.Point referring to the active (visible) page
95- const pt: ghostty.point.Point = .{ .active = .{
96- .x = @as(u16, @intCast(col)),
97+ const pt: ghostty.point.Point = .{ .active = .{
98+ .x = @as(u16, @intCast(col)),
99 .y = @as(u16, @intCast(row)),
100 } };
101-
102+
103 if (screen.pages.getCell(pt)) |cell_ref| {
104 const cp = cell_ref.cell.content.codepoint;
105 if (cp == 0) {
106@@ -692,7 +684,7 @@ fn renderTerminalSnapshot(session: *Session, allocator: std.mem.Allocator) ![]u8
107 try output.append(allocator, ' ');
108 }
109 }
110-
111+
112 if (row < rows - 1) {
113 try output.appendSlice(allocator, "\r\n");
114 }