From 7aa057e29b729ad6d9ac53e3a06f99858fc449e4 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Tue, 29 Sep 2026 00:50:45 -0300 Subject: A column has a ctl, an exec and an rmdir over 9P, and Restore maps its serial A script could read and write a column's tag but not act on the column. col//ctl takes Delcol, Joincol, New and Tty, each acting on that column as from its tag; col//exec runs a word as a middle click in the tag; rmdir col/ closes an empty column and refuses one with panes (ENOTEMPTY, an err record saying why). The root ctl's refusal of Delcol and Joincol points at col//ctl. A dump keeps each column's serial and Restore logs restoredcol ; the dump golden gains them. Documented: Joincol's survivor, the column on the right, keeps its serial and tag. Co-Authored-By: Claude Opus 5.5 --- src/ninep/ctl.zig | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src/ninep/ctl.zig') diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig index 98120555..e1dd3fc5 100644 --- a/src/ninep/ctl.zig +++ b/src/ninep/ctl.zig @@ -51,7 +51,7 @@ fn noteResult(p: *Pardes, serial: u32) void { /// Runs one look or exec from the pane `id`, then records the panes it /// created; failing that, a look records the pane it focused and an exec /// the pane it acted on (even one it closed). -fn run(p: *Pardes, id: usize, exec: bool, text: []const u8) void { +pub fn run(p: *Pardes, id: usize, exec: bool, text: []const u8) void { const context = p.panes[id].?.serial; // A pane an event reader holds hears its clicks instead of acting on // them (editors/acme/look.c:53 and exec.c:173 send them to winevent), @@ -277,7 +277,12 @@ fn checkBuiltin(p: *Pardes, req: Req, line: []const u8, scope: builtins.Scope) ? }; // Edit is the one pane word the root takes too: at the active pane. if (builtins.registry.scope(b) != scope and b != .Edit) - return refuseTo(p, req, if (scope == .pane) "not a window control message" else "not a session control message", line, if (scope == .pane) "/ctl" else "pane//ctl"); + return refuseTo(p, req, if (scope == .pane) "not a window control message" else "not a session control message", line, if (scope == .pane) + "/ctl" + else if (b == .Delcol or b == .Joincol) + "col//ctl" // a column's own ctl, the one /layout names + else + "pane//ctl"); if (arg.len > 0 and !builtins.registry.takesArg(b)) return refuse(p, req, "wrong #args in control message", line); if (arg.len == 0 and builtins.registry.requiresArg(b)) return refuse(p, req, "wrong #args in control message", line); const setting = config.Runtime.find(word) orelse return null; @@ -308,7 +313,7 @@ fn checkBuiltin(p: *Pardes, req: Req, line: []const u8, scope: builtins.Scope) ? /// would. Answers the refusal when it would have opened a prompt for an /// argument, which nobody writing to a file is there to type, or when it /// reported an error: `Mount: AlreadyMounted "Mount peer /tmp/s"`. -fn runBuiltin(p: *Pardes, req: Req, id: usize, line: []const u8) ?Reply { +pub fn runBuiltin(p: *Pardes, req: Req, id: usize, line: []const u8) ?Reply { p.fs.no_prompt = true; p.fs.refused = false; p.fs.failure_len = 0; -- cgit v1.3