summaryrefslogtreecommitdiff
path: root/src/ninep/ctl.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/ninep/ctl.zig')
-rw-r--r--src/ninep/ctl.zig53
1 files changed, 41 insertions, 12 deletions
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index 42b88b91..bcf9ffd6 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -640,6 +640,23 @@ pub fn readRoot(p: *Pardes, req: Req) Reply {
return tree.stagedReply(p, req);
}
+/// /pager, `pardes -`'s: the directory written (empty, or not absolute: the
+/// session's) gets its one +Pager, made or emptied; the serial is what a
+/// read of this same open answers, never another client's.
+pub fn writePager(p: *Pardes, req: Req) Reply {
+ var it = Messages.init(p, req.data);
+ const line = it.next() orelse "";
+ if (it.next() != null) return tree.failText(req.tag, E.INVAL, "pager: one directory a write");
+ p.fs.results_len = 0;
+ const id = pardes.panes.Output.openPager(p, p.active, std.mem.trim(u8, line, " \t")) catch |err|
+ return tree.failText(req.tag, if (err == error.NoPaneRoom or err == error.NoPaneSlots) E.NOSPC else E.IO, switch (err) {
+ error.NoPaneRoom, error.NoPaneSlots => "pager: no space for a +Pager pane",
+ else => "pager: could not make a +Pager pane",
+ });
+ noteResult(p, p.panes[id].?.serial);
+ return .{ .tag = req.tag, .written = @intCast(req.data.len) };
+}
+
/// One session builtin a line, at whichever pane has the keyboard as each
/// runs, as the root's look and exec click there; all are checked first.
pub fn writeRoot(p: *Pardes, req: Req) Reply {
@@ -648,18 +665,6 @@ pub fn writeRoot(p: *Pardes, req: Req) Reply {
var it = Messages.init(p, req.data);
while (it.next()) |line| {
if (line.len == 0 or exec_line.isComment(line)) continue;
- // `pardes -`'s: the directory's +Pager made or emptied, its
- // serial what /exec reads back.
- if (std.mem.startsWith(u8, line, "pager ") or std.mem.eql(u8, line, "pager")) {
- if (!apply) continue;
- const id = pardes.panes.Output.openPager(p, p.active, std.mem.trim(u8, line["pager".len..], " \t")) catch |err|
- return tree.failText(req.tag, if (err == error.NoPaneRoom or err == error.NoPaneSlots) E.NOSPC else E.IO, switch (err) {
- error.NoPaneRoom, error.NoPaneSlots => "pager: no space for a +Pager pane",
- else => "pager: could not make a +Pager pane",
- });
- noteResult(p, p.panes[id].?.serial);
- continue;
- }
if (std.mem.startsWith(u8, line, "size ") or std.mem.eql(u8, line, "size")) {
// The offending word is the value: `size 5 5` quotes "5 5".
const value = std.mem.trim(u8, line["size".len..], " \t");
@@ -3999,3 +4004,27 @@ test "a refused Delcol changes nothing: no pane, no focus" {
try testing.expectEqual(active_column, p.active_column);
try testing.expect(th.logHas(p, "unsaved "));
}
+
+test "pager answers its +Pager on the open that asked, whatever another client exec'd meanwhile" {
+ const p = try withFile(testing.allocator, "x\n");
+ defer p.deinit();
+ const pager = @intFromEnum(tree.TopFile.pager);
+ const exec = @intFromEnum(tree.TopFile.exec);
+ const asked = call(p, .{ .tag = 1, .op = .open, .node = pager, .omode = 2 }).reply.handle;
+ try testing.expectEqual(Status.ok, call(p, .{ .tag = 2, .op = .write, .node = pager, .handle = asked, .data = "/tmp/pager-race\n" }).reply.status);
+ const paged = for (p.panes) |slot| {
+ const pn = slot orelse continue;
+ if (pn.file) |f| if (std.mem.eql(u8, f.path, "/tmp/pager-race/+Pager")) break pn.serial;
+ } else return error.NoPager;
+ // Another client execs between the request and its read: a pane of its own.
+ const racer = call(p, .{ .tag = 3, .op = .open, .node = exec, .omode = 2 }).reply.handle;
+ try testing.expectEqual(Status.ok, call(p, .{ .tag = 4, .op = .write, .node = exec, .handle = racer, .data = "New\n" }).reply.status);
+ var line: [16]u8 = undefined;
+ const want = try std.fmt.bufPrint(&line, "{d}\n", .{paged});
+ // A fresh open reads the session's last answer, the racer's pane: what
+ // `pardes -` once read, and wrote its text into.
+ try testing.expect(!std.mem.eql(u8, want, rd(p, exec, 0, 64).bytes));
+ try testing.expectEqualStrings(want, call(p, .{ .tag = 5, .op = .read, .node = pager, .handle = asked, .size = 64 }).bytes);
+ // One directory a write.
+ try testing.expectEqual(E.INVAL, wr(p, pager, "/a\n/b\n").errno());
+}