summaryrefslogtreecommitdiff
path: root/src/ninep
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 04:52:38 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:16 -0300
commit430d482c16101ce85b5c0f80f6bdd882c09a3272 (patch)
tree10dad6a09f8fd8e0784dc83058c10103c35fba25 /src/ninep
parent4e82c95653e1e8e03fde91e3cea2de04b3fabbc8 (diff)
downloadpardes-430d482c16101ce85b5c0f80f6bdd882c09a3272.tar.gz
pardes-430d482c16101ce85b5c0f80f6bdd882c09a3272.zip
Refusals and records say more: get quotes its line, a bare answer lists the choices, a clean reload is logged
get's refusal now quotes the line as a builtin's (Save's) does; a bare answer while a question stands says what it takes (answer takes k j or -); and a clean buffer reloaded from disk logs changed <serial> reloaded, as the kept dirty case logs changed <serial>. (A failed Save already says why: Save <path>: <the error in words>.) Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/ninep')
-rw-r--r--src/ninep/ctl.zig20
1 files changed, 18 insertions, 2 deletions
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index f40825e3..eb8ed292 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -648,7 +648,15 @@ pub fn writePane(p: *Pardes, req: Req, pane: *Pane) Reply {
if (apply and p.paneBySerial(serial) == null) return Reply.fail(req.tag, E.NOENT);
if (std.mem.eql(u8, line, "get")) {
if (!apply) continue;
- if (getRefused(p, pane)) |said| return tree.failText(req.tag, E.IO, said);
+ // Quoting the line, as a builtin's refusal (Save's) does.
+ if (getRefused(p, pane)) |said_in_ename| {
+ // refuse writes ename, where the words are: copy them out.
+ var said_buf: [320]u8 = undefined;
+ const said = said_buf[0..said_in_ename.len];
+ @memcpy(said, said_in_ename);
+ const r = refuse(p, req, said, line);
+ return .{ .tag = req.tag, .status = .err, .errno = E.IO, .ename = r.ename };
+ }
const errno = get(p, pane);
if (errno != 0) return Reply.fail(req.tag, errno);
} else if (std.mem.eql(u8, line, "lock")) {
@@ -661,6 +669,12 @@ pub fn writePane(p: *Pardes, req: Req, pane: *Pane) Reply {
held = false;
if (apply) pane.fs.lock = null;
} else if (std.mem.eql(u8, line, "answer")) {
+ // With a question up, what it offers.
+ var offered: [64]u8 = undefined;
+ if (p.questionChoices(p.paneBySerial(serial).?, &offered)) |choices| {
+ var why: [96]u8 = undefined;
+ return tree.failText(req.tag, E.INVAL, std.fmt.bufPrint(&p.fs.ename, "answer takes {s} or -", .{choices}) catch std.fmt.bufPrint(&why, "answer takes a choice or -", .{}) catch "answer takes a choice or -");
+ }
return tree.failText(req.tag, E.INVAL, "answer takes a choice or -");
} else if (std.mem.startsWith(u8, line, "answer ")) {
// The pane's question (its `ask` in the log), answered.
@@ -1280,7 +1294,7 @@ test "get reloads the pane from disk and reports a missing file without losing d
// Unsaved text is asked about once, as acme's get asks winclean.
const asked = wr(p, ctl_node, "get\n");
try testing.expectEqual(E.IO, asked.errno());
- try testing.expect(std.mem.endsWith(u8, asked.reply.ename, ": Modified (get again to discard)"));
+ try testing.expect(std.mem.endsWith(u8, asked.reply.ename, ": Modified (get again to discard) \"get\""));
try testing.expectEqual(E.NOENT, wr(p, ctl_node, "get\n").errno());
try testing.expect(p.paneBySerial(serial) != null);
try testing.expectEqualStrings("from disk\nunsaved\n", pane.file.?.content);
@@ -1571,6 +1585,8 @@ test "a file changed on disk under unsaved edits is not reloaded: it says so, ge
// Clean, it takes the new text.
pardes.panes.File.changed(p, 0, "two\n");
try testing.expectEqualStrings("two\n", f.content);
+ var reloaded: [32]u8 = undefined;
+ try testing.expect(th.logHas(p, try std.fmt.bufPrint(&reloaded, "changed {d} reloaded\n", .{serial})));
// Edited, it keeps its text and stays dirty.
_ = wr(p, Node.of(serial, .body), "mine\n");
pardes.panes.File.changed(p, 0, "three\n");