summaryrefslogtreecommitdiff
path: root/src/ninep/ctl.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 03:39:43 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:15 -0300
commit84d23aef86c0bcb6ee14bb69b1e4d6d65205e2f6 (patch)
treef45ab1d07c16ceec51d8c164ad210aa220efe484 /src/ninep/ctl.zig
parent98e94b86a7c38e2bf4d66e57144fc9329906bb3b (diff)
downloadpardes-84d23aef86c0bcb6ee14bb69b1e4d6d65205e2f6.tar.gz
pardes-84d23aef86c0bcb6ee14bb69b1e4d6d65205e2f6.zip
size says its limits, keeps every pane its rows, and ptys follow their panes
size refused an out-of-range line without saying the range, took a size too small for the panes (leaving bodies of no rows), and a terminal squeezed to its tag kept a pty of its old size. The refusal now names 20x6 to 4096x4096 (a bare size is EINVAL like any malformed line), a size that would leave any pane less than its tag and 2 rows is refused and undone, and a terminal's pty is resized with its pane down to one row (only a folded or unplaced one keeps its grid). Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/ninep/ctl.zig')
-rw-r--r--src/ninep/ctl.zig32
1 files changed, 27 insertions, 5 deletions
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index dd2d9ed0..dd382290 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -473,11 +473,22 @@ pub fn writeRoot(p: *Pardes, req: Req) Reply {
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);
+ const size = sizeOf(line) orelse return refuse(p, req, e_size, 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] } });
+ if (apply) {
+ const was: [2]u16 = .{ p.screen_w, p.screen_h };
+ p.update(.{ .resize = .{ .cols = size[0], .rows = size[1] } });
+ p.sync();
+ // Every pane keeps its tag and two rows, as placement
+ // leaves them: a size too small for that is refused.
+ if (!pardes.layout.everyPaneRoomy(p)) {
+ p.update(.{ .resize = .{ .cols = was[0], .rows = was[1] } });
+ p.sync();
+ return refuse(p, req, "size: too small for the panes, each its tag and 2 rows", line);
+ }
+ }
continue;
}
if (!apply) {
@@ -493,12 +504,16 @@ 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.
+const size_min = [2]u16{ 20, 6 };
+const size_max = [2]u16{ 4096, 4096 };
+const e_size = std.fmt.comptimePrint("size takes <cols> <rows>, at least {d}x{d}, at most {d}x{d}", .{ size_min[0], size_min[1], size_max[0], size_max[1] });
+
+/// `size <cols> <rows>`, within size_min and size_max.
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;
+ if (it.next() != null or cols < size_min[0] or rows < size_min[1] or cols > size_max[0] or rows > size_max[1]) return null;
return .{ cols, rows };
}
@@ -1490,5 +1505,12 @@ test "size sets the screen of a session no frontend is attached to, and only of
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());
+ try testing.expectEqual(E.INVAL, wr(p, root_ctl, "size\n").errno());
+ try testing.expect(std.mem.indexOf(u8, wr(p, root_ctl, "size 5 2\n").reply.ename, "at least 20x6, at most 4096x4096") != null);
+ // Too small for the panes it has, each its tag and two rows: refused,
+ // the size as it was.
+ for (0..4) |_| p.newScratchBelow(p.active);
+ p.sync();
+ try testing.expect(std.mem.indexOf(u8, wr(p, root_ctl, "size 80 8\n").reply.ename, "too small for the panes") != null);
+ try testing.expectEqual(@as(u16, 40), p.screen_h);
}