diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-29 03:14:31 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:15 -0300 |
| commit | a7960117dfb83ad65a0466a96affbbb524936b7f (patch) | |
| tree | a824bff6e91e0e0e3cf84e9ac88a12201d708f81 /src | |
| parent | 6dfc6838c1c02978c026b650d69f87f23e3ff81c (diff) | |
| download | pardes-a7960117dfb83ad65a0466a96affbbb524936b7f.tar.gz pardes-a7960117dfb83ad65a0466a96affbbb524936b7f.zip | |
A detached session with no frontend takes its size from the root ctl
A --detach session nobody is attached to stayed 80x24, too small for an
agent's panes, and nothing could change it. The root ctl takes size <cols>
<rows> while no frontend is attached (refused while one owns the size), and
a client that attaches later still sets its own (the server compares with
the core's size). Documented with the 80x24 default.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src')
| -rw-r--r-- | src/detached/server.zig | 4 | ||||
| -rw-r--r-- | src/ninep/ctl.zig | 30 |
2 files changed, 33 insertions, 1 deletions
diff --git a/src/detached/server.zig b/src/detached/server.zig index 8f45135a..af299051 100644 --- a/src/detached/server.zig +++ b/src/detached/server.zig @@ -1076,7 +1076,9 @@ pub const Session = struct { rows = if (rows == 0) c.rows else @min(rows, c.rows); } var regridded = false; - if (cols != 0 and (cols != s.cols or rows != s.rows)) { + // Against the core's size too: a root ctl `size` may have set it + // while nobody was attached. + if (cols != 0 and (cols != s.cols or rows != s.rows or cols != s.core.screen_w or rows != s.core.screen_h)) { s.cols = cols; s.rows = rows; for (&s.clients) |*c| c.need_full = true; diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig index 378dd844..26a18a12 100644 --- a/src/ninep/ctl.zig +++ b/src/ninep/ctl.zig @@ -472,6 +472,14 @@ pub fn writeRoot(p: *Pardes, req: Req) Reply { var it = Messages.init(p, req.data); while (it.next()) |line| { if (line.len == 0) continue; + if (std.mem.startsWith(u8, line, "size ") or std.mem.eql(u8, line, "size")) { + const size = sizeOf(line) orelse return refuse(p, req, "size takes <cols> <rows>", line); + // A frontend's window is the size; only a session none is + // attached to (--detach, unattended) takes one written. + if (!p.unattended) return refuse(p, req, "size: a frontend is attached and owns the size", line); + if (apply) p.update(.{ .resize = .{ .cols = size[0], .rows = size[1] } }); + continue; + } if (!apply) { if (checkBuiltin(p, req, line, .session)) |refusal| return refusal; continue; @@ -485,6 +493,15 @@ pub fn writeRoot(p: *Pardes, req: Req) Reply { return .{ .tag = req.tag, .written = @intCast(req.data.len) }; } +/// `size <cols> <rows>`, each at least a few cells and at most 4096. +fn sizeOf(line: []const u8) ?[2]u16 { + var it = std.mem.tokenizeAny(u8, line["size".len..], " \t"); + const cols = std.fmt.parseInt(u16, it.next() orelse return null, 10) catch return null; + const rows = std.fmt.parseInt(u16, it.next() orelse return null, 10) catch return null; + if (it.next() != null or cols < 20 or rows < 4 or cols > 4096 or rows > 4096) return null; + return .{ cols, rows }; +} + // ---- /commands ---- /// Every builtin the registry holds, one a line: its word, `arg` when it @@ -1460,3 +1477,16 @@ test "Edit's p and = never fail for want of room for +Errors: the text is logged for (p.panes) |slot| count += @intFromBool(slot != null); try testing.expectEqual(@as(usize, 1), count); // the +Errors that had no room is gone } + +test "size sets the screen of a session no frontend is attached to, and only of one" { + const p = try withFile(testing.allocator, "x\n"); + defer p.deinit(); + const root_ctl = @intFromEnum(tree.TopFile.ctl); + try testing.expectEqual(E.INVAL, wr(p, root_ctl, "size 120 40\n").errno()); // a frontend's + p.unattended = true; + try testing.expectEqual(Status.ok, wr(p, root_ctl, "size 120 40\n").reply.status); + try testing.expectEqual(@as(u16, 120), p.screen_w); + try testing.expectEqual(@as(u16, 40), p.screen_h); + try testing.expectEqual(E.INVAL, wr(p, root_ctl, "size 120\n").errno()); + try testing.expectEqual(E.INVAL, wr(p, root_ctl, "size 5 2\n").errno()); +} |
