summaryrefslogtreecommitdiff
path: root/src/ninep/tree.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-28 09:41:55 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:14 -0300
commitf5eaddb2cf28a9b72d5dd5b3b10502a316d4de85 (patch)
tree3d043946453c8da589ef17eef1ebc66f2d2c1b24 /src/ninep/tree.zig
parent0ee8d748c028ad5257f95e15db38646aecd2851b (diff)
downloadpardes-f5eaddb2cf28a9b72d5dd5b3b10502a316d4de85.tar.gz
pardes-f5eaddb2cf28a9b72d5dd5b3b10502a316d4de85.zip
Split control messages by scope: the root ctl takes the session's builtins and reads the settings, a pane's ctl its own
Every builtin could only be clicked, or written to exec, and the settings could be read only as the Config window's prose. acme keeps window verbs on a window's ctl, and webfs and upas/fs keep session settings on a root ctl. Each builtin now declares its scope (scope = .session; settings are all session, the rest pane), read by the registry. The root /ctl takes session builtins and reads every setting in the words a write takes, so its read written back changes nothing (panel and scene effects now take on/off like the toggles, to make that true); a pane's ctl takes the pane's builtins beside get, lock and unlock. Writes are checked whole and refused in Plan 9's ctl words (unknown control message "X", wrong #args ...), which 9ns now maps to EINVAL (cloud9 re-pinned at a8c7a715). A builtin that would prompt for its argument fails the write instead, and a refusal is answered at once, not after the frame. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/ninep/tree.zig')
-rw-r--r--src/ninep/tree.zig8
1 files changed, 6 insertions, 2 deletions
diff --git a/src/ninep/tree.zig b/src/ninep/tree.zig
index b0de446e..13dfb0cf 100644
--- a/src/ninep/tree.zig
+++ b/src/ninep/tree.zig
@@ -175,6 +175,7 @@ pub const TopFile = enum(u4) {
pane,
new,
focus,
+ ctl,
pub fn fileName(f: TopFile) []const u8 {
return if (f == .root) "/" else @tagName(f);
@@ -183,7 +184,7 @@ pub const TopFile = enum(u4) {
pub fn mode(f: TopFile) u16 {
return switch (f) {
.root, .pane => 0o755,
- .look, .exec, .log, .focus => 0o666,
+ .look, .exec, .log, .focus, .ctl => 0o666,
.README, .index, .status, .screen, .listeners, .new => 0o444,
};
}
@@ -445,6 +446,7 @@ fn topSize(p: *Pardes, f: TopFile) u64 {
.look, .exec => ctl.resultsLen(p),
.log => events.logLen(&p.fs.log),
.listeners => screen.listenersLen(p),
+ .ctl => ctl.rootLen(p),
.focus => focus: {
const pn = p.panes[p.active] orelse break :focus 0;
var digits: [16]u8 = undefined;
@@ -523,7 +525,7 @@ fn readdir(p: *Pardes, req: Req, target: Target) Reply {
}
if (skip > 0) skip -= 1 else stageDirent(out, p.gpa, fs.os_root, true, "os");
// After the first ten, which older clients list by position.
- inline for (.{TopFile.focus}) |t| {
+ inline for (.{ TopFile.focus, TopFile.ctl }) |t| {
if (skip > 0) skip -= 1 else stageDirent(out, p.gpa, @intFromEnum(t), t.dir(), t.fileName());
}
sources.stage(p, out, "", &skip);
@@ -716,6 +718,7 @@ fn read(p: *Pardes, req: Req, target: Target) Reply {
.screen => screen.readSnapshot(p, req, null),
.listeners => screen.readListeners(p, req),
.focus => ctl.readFocus(p, req),
+ .ctl => ctl.readRoot(p, req),
// The serial the open handed this fid, so that two reads of one
// fid answer the same pane: the read observes, the open acted.
.new => serial: {
@@ -749,6 +752,7 @@ fn write(p: *Pardes, req: Req, target: Target) Reply {
.look, .exec => ctl.command(p, req, null, f == .exec),
.log => events.writeLog(p, req),
.focus => ctl.writeFocus(p, req),
+ .ctl => ctl.writeRoot(p, req),
else => Reply.fail(req.tag, E.PERM),
},
.pane => |t| {