Commit 66c8e0e

Eric Bower  ·  2026-04-08 20:22:43 -0400 EDT
parent bdbf795
feat: change pty window size when new leader is set

When we set a new client leader we send a Resize event request from the daemon
to the client.  So now whenever a user types into their stdin we set the new leader
and then resize the window.
2 files changed,  +31, -26
+1, -0
......@@ -80,6 +80,7 @@ pub fn appendMessage(
8080 tag: Tag,
8181 data: []const u8,
8282 ) !void {
83+ std.log.info("sending ipc message tag={s}", .{@tagName(tag)});
8384 const header = Header{
8485 .tag = tag,
8586 .len = @intCast(data.len),
+30, -26
......@@ -319,11 +319,6 @@ const Cfg = struct {
319319 }
320320 };
321321
322-const EnsureSessionResult = struct {
323- created: bool,
324- is_daemon: bool,
325-};
326-
327322 /// Daemon is responsible for managing a zmx session.
328323 ///
329324 /// It holds all the state for a running session. Instead of a single daemon for all sessions, we
......@@ -354,6 +349,11 @@ const Daemon = struct {
354349 task_command: ?[]const []const u8 = null,
355350 pty_write_buf: std.ArrayList(u8) = .empty,
356351
352+ const EnsureSessionResult = struct {
353+ created: bool,
354+ is_daemon: bool,
355+ };
356+
357357 pub fn deinit(self: *Daemon) void {
358358 self.clients.deinit(self.alloc);
359359 self.pty_write_buf.deinit(self.alloc);
......@@ -384,6 +384,15 @@ const Daemon = struct {
384384 return false;
385385 }
386386
387+ fn setLeader(self: *Daemon, client: *Client) !void {
388+ std.log.info("setting new leader client_fd={d}", .{client.socket_fd});
389+ self.leader_client_fd = client.socket_fd;
390+ // Send a resize message to the client so it can send us back their window size
391+ // so we can resize the pty and ghostty state.
392+ try ipc.appendMessage(self.alloc, &client.write_buf, .Resize, "");
393+ client.has_pending_output = true;
394+ }
395+
387396 /// Runs in the forked child. Either execs or returns an error (caller
388397 /// must exit on error -- returning would fall through to parent code).
389398 fn execChild(self: *Daemon) !noreturn {
......@@ -598,11 +607,7 @@ const Daemon = struct {
598607 const isNewline = std.mem.indexOfScalar(u8, payload, '\r') != null;
599608 const isUpArrow = std.mem.eql(u8, payload, "\x1b[A") or util.isUpArrow(payload);
600609 if (isNewline or isUpArrow) {
601- std.log.info(
602- "setting new leader session={s} client_fd={d}",
603- .{ self.session_name, client.socket_fd },
604- );
605- self.leader_client_fd = client.socket_fd;
610+ try self.setLeader(client);
606611 self.queuePtyInput(payload);
607612 return;
608613 }
......@@ -623,11 +628,7 @@ const Daemon = struct {
623628 defer client.alloc.free(output);
624629 // if there's no text output then this client is effectively read-only until they type
625630 if (output.len > 0) {
626- std.log.info(
627- "setting new leader session={s} client_fd={d}",
628- .{ self.session_name, client.socket_fd },
629- );
630- self.leader_client_fd = client.socket_fd;
631+ try self.setLeader(client);
631632 // new leader is set to this client so send *entire* payload
632633 self.queuePtyInput(payload);
633634 }
......@@ -669,11 +670,7 @@ const Daemon = struct {
669670
670671 // no leader is set so set one
671672 if (self.leader_client_fd == null) {
672- std.log.info(
673- "setting new leader session={s} client_fd={d}",
674- .{ self.session_name, client.socket_fd },
675- );
676- self.leader_client_fd = client.socket_fd;
673+ try self.setLeader(client);
677674 }
678675
679676 // only resize if leader
......@@ -704,11 +701,7 @@ const Daemon = struct {
704701 ) !void {
705702 if (payload.len != @sizeOf(ipc.Resize)) return;
706703 if (self.leader_client_fd == null) {
707- std.log.info(
708- "setting new leader session={s} client_fd={d}",
709- .{ self.session_name, client.socket_fd },
710- );
711- self.leader_client_fd = client.socket_fd;
704+ try self.setLeader(client);
712705 }
713706 // only leader can resize
714707 if (self.leader_client_fd != client.socket_fd) return;
......@@ -1020,7 +1013,7 @@ fn wait(cfg: *Cfg, session_names: std.ArrayList([]const u8)) !void {
10201013 }
10211014 }
10221015
1023- std.Thread.sleep(3000 * std.time.ns_per_ms);
1016+ std.Thread.sleep(1000 * std.time.ns_per_ms);
10241017 }
10251018 }
10261019
......@@ -1529,6 +1522,17 @@ fn clientLoop(client_sock_fd: i32) !void {
15291522 try stdout_buf.appendSlice(alloc, msg.payload);
15301523 }
15311524 },
1525+ .Resize => {
1526+ // daemon is asking for the client's window size usually in response
1527+ // to this client being set as leader.
1528+ const next_size = ipc.getTerminalSize(posix.STDOUT_FILENO);
1529+ try ipc.appendMessage(
1530+ alloc,
1531+ &sock_write_buf,
1532+ .Resize,
1533+ std.mem.asBytes(&next_size),
1534+ );
1535+ },
15321536 else => {},
15331537 }
15341538 }