summaryrefslogtreecommitdiff
path: root/src/ninep/cols.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 01:48:39 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:15 -0300
commit5b11fc35b961eb03c8816bf957bbf8e27a22ae3e (patch)
tree3a0022699f4c92ec86b2249cf3455139809d56a4 /src/ninep/cols.zig
parent5b5896965758ff8f2077c8e8e2f0250f580967c3 (diff)
downloadpardes-5b11fc35b961eb03c8816bf957bbf8e27a22ae3e.tar.gz
pardes-5b11fc35b961eb03c8816bf957bbf8e27a22ae3e.zip
The workspace tag has /tagexec, every exec file reads back what it touched, and a tag's words log as the session's
/tagexec runs a word as a click in the workspace tag, as col/<serial>/exec does in a column's. A column's exec was write-only; it and /tagexec now read back the serials the last write touched, as /exec does. A click in a tag no longer goes to the focused pane's event reader, and what a word run from a column's ctl or exec or /tagexec says is logged msg -, not against the focused pane. The README, fs.md and the skill say so, and document the answer record. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/ninep/cols.zig')
-rw-r--r--src/ninep/cols.zig42
1 files changed, 36 insertions, 6 deletions
diff --git a/src/ninep/cols.zig b/src/ninep/cols.zig
index 49df715a..8a3474b3 100644
--- a/src/ninep/cols.zig
+++ b/src/ninep/cols.zig
@@ -123,8 +123,11 @@ pub fn released(p: *Pardes, serial: ?u32) void {
}
/// A column's ctl: the words that act on a column, as its tag's clicks do --
-/// Delcol, Joincol, New, Tty -- one a line, each run as from that tag.
+/// Delcol, Joincol, New, Tty -- one a line, each run as from that tag. What
+/// they say is the session's in the log (`msg -`), not the focused pane's.
pub fn writeCtl(p: *Pardes, req: Req, serial: u32) Reply {
+ p.fs.session_write = true;
+ defer p.fs.session_write = false;
var lines = std.mem.splitScalar(u8, req.data, '\n');
while (lines.next()) |raw| {
const line = std.mem.trim(u8, raw, " \t\r");
@@ -142,18 +145,24 @@ pub fn writeCtl(p: *Pardes, req: Req, serial: u32) Reply {
return .{ .tag = req.tag, .written = @intCast(req.data.len) };
}
-/// A column's exec: each line run as a middle click on it in that column's
-/// tag, acting on that column.
-pub fn writeExec(p: *Pardes, req: Req, serial: u32) Reply {
+/// A column's exec (`serial`), or the workspace tag's (/tagexec, null):
+/// each line run as a middle click on it in that tag, a column's acting on
+/// that column. A read answers the panes the last write touched, as /exec's
+/// does; what the words say is the session's in the log (`msg -`).
+pub fn writeExec(p: *Pardes, req: Req, serial: ?u32) Reply {
+ p.fs.results_len = 0;
+ p.fs.session_write = true;
+ defer p.fs.session_write = false;
var lines = std.mem.splitScalar(u8, req.data, '\n');
while (lines.next()) |raw| {
const line = std.mem.trim(u8, raw, " \t\r");
if (line.len == 0) continue;
for (line) |c| if (c < ' ' and c != '\t') return Reply.fail(req.tag, E.INVAL);
- const col = layout.columnBySerial(p, serial) orelse return Reply.fail(req.tag, E.NOENT);
+ const col = if (serial) |s| layout.columnBySerial(p, s) orelse return Reply.fail(req.tag, E.NOENT) else null;
+ if (p.panes[p.active] == null) return Reply.fail(req.tag, E.NOENT);
p.exec_column = col;
defer p.exec_column = null;
- pardes.ctlfs.ctl.run(p, p.active, true, line);
+ pardes.ctlfs.ctl.run(p, p.active, true, line, true);
}
return .{ .tag = req.tag, .written = @intCast(req.data.len) };
}
@@ -284,3 +293,24 @@ test "a column's ctl and exec act on it as its tag would, and rmdir closes it on
// The root's ctl points a column word at the column's own.
try testing.expect(std.mem.endsWith(u8, th.wr(p, @intFromEnum(tree.TopFile.ctl), "Delcol\n").reply.ename, "write it to col/<serial>/ctl"));
}
+
+test "tagexec runs a word as a click in the workspace tag; exec files read back what they touched; their messages are the session's" {
+ const p = try th.withFile(testing.allocator, "x\n");
+ defer p.deinit();
+ const tagexec = @intFromEnum(tree.TopFile.tagexec);
+ try testing.expectEqual(tree.Status.ok, th.look_up(p, tree.root, "tagexec").reply.status);
+ try testing.expectEqual(tree.Status.ok, th.wr(p, tagexec, "Newcol\n").reply.status);
+ try testing.expectEqual(@as(usize, 2), p.ncol);
+ try testing.expectEqual(tree.Status.ok, th.wr(p, tagexec, "Msg from the top\n").reply.status);
+ try testing.expect(th.logHas(p, "msg - from the top\n"));
+ // A column's exec makes a pane there, reads it back, and its Msg is
+ // the session's too.
+ const right = layout.columnSerial(p, 1);
+ try testing.expectEqual(tree.Status.ok, th.wr(p, Node.ofCol(right, .exec), "New\n").reply.status);
+ const made = p.panes[p.col_panes[1][0]].?.serial;
+ var want: [16]u8 = undefined;
+ try testing.expectEqualStrings(try std.fmt.bufPrint(&want, "{d}\n", .{made}), th.rd(p, Node.ofCol(right, .exec), 0, 64).bytes);
+ try testing.expectEqualStrings(try std.fmt.bufPrint(&want, "{d}\n", .{made}), th.rd(p, tagexec, 0, 64).bytes);
+ try testing.expectEqual(tree.Status.ok, th.wr(p, Node.ofCol(right, .exec), "Msg from a column\n").reply.status);
+ try testing.expect(th.logHas(p, "msg - from a column\n"));
+}