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.zig38
1 files changed, 37 insertions, 1 deletions
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index 7d5f0ca0..112df099 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -722,7 +722,11 @@ pub fn writePane(p: *Pardes, req: Req, pane: *Pane) Reply {
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);
+ // Naming the path, in words 9ns reads as the errno.
+ if (errno != 0) {
+ const path = if (pane_files.fileOf(pane)) |f| f.path else "";
+ return tree.failText(req.tag, errno, std.fmt.bufPrint(&p.fs.ename, "get: {s}: {s}", .{ path[0..@min(path.len, 256)], if (errno == E.NOENT) "no such file" else "cannot be read" }) catch "get: no such file");
+ }
} else if (std.mem.eql(u8, line, "lock")) {
if (mine == null) return tree.failText(req.tag, E.INVAL, tree.e_bad_ctl);
if (other) return tree.failText(req.tag, E.BUSY, e_locked);
@@ -799,11 +803,19 @@ fn get(p: *Pardes, pane: *Pane) u16 {
error.FileNotFound => E.NOENT,
else => E.IO,
};
+ // Throwing unsaved edits away for it is a reload the log hears of, as a
+ // clean one from the watch is.
+ const discarded = f.revision != f.saved_revision;
panes.File.pushUndo(p, pane);
panes.File.setContent(p, f, bytes);
f.saved_revision = f.revision;
f.saved_hash = std.hash.Wyhash.hash(0, f.content);
f.disk_newer = null;
+ f.disk_gone = false;
+ if (discarded) {
+ var rec: [32]u8 = undefined;
+ pardes.ctlfs.events.notePath(p, "changed", std.fmt.bufPrint(&rec, "{d} reloaded", .{pane.serial}) catch "");
+ }
return 0;
}
@@ -1363,6 +1375,9 @@ test "get reloads the pane from disk and reports a missing file without losing d
try testing.expectEqualStrings("from disk\n", pane.file.?.content);
try testing.expect(!pane_files.dirtyOf(pane));
try testing.expect(pane.file.?.history.undo_len > 0);
+ // What it had (renamed, so dirty) was thrown away for it: logged.
+ var reloaded: [32]u8 = undefined;
+ try testing.expect(th.logHas(p, try std.fmt.bufPrint(&reloaded, "changed {d} reloaded\n", .{serial})));
_ = wr(p, Node.of(serial, .name), try std.fmt.bufPrint(&name, "{s}/missing.txt\n", .{directory}));
_ = wr(p, Node.of(serial, .body), "unsaved\n");
@@ -1784,3 +1799,24 @@ test "Save on a terminal asked over 9P is an ask in the log, answered with a pat
try testing.expect(p.panes[id].?.prompt == .none);
try testing.expect(th.logHas(p, try std.fmt.bufPrint(&want, "answer {d} /tmp/pardes-ask-save.txt\n", .{serial})));
}
+
+test "get names the path it could not read, logs the edits it threw away, and a deleted file is said once" {
+ const p = try withFile(testing.allocator, "x\n");
+ defer p.deinit();
+ const serial = serialOf(p);
+ const f = &p.panes[0].?.file.?;
+ const path = f.path;
+ // Its file is not on disk: get names it.
+ const missing = wr(p, Node.of(serial, .ctl), "get\n");
+ try testing.expectEqual(E.NOENT, missing.errno());
+ var want: [512]u8 = undefined;
+ try testing.expectEqualStrings(try std.fmt.bufPrint(&want, "get: {s}: no such file", .{path}), missing.reply.ename);
+ // Deleted on disk: said once.
+ pardes.panes.File.deleted(p, 0);
+ pardes.panes.File.deleted(p, 0);
+ var rec: [32]u8 = undefined;
+ const log = @intFromEnum(tree.TopFile.log);
+ const h = call(p, .{ .tag = 1, .op = .open, .node = log }).reply.handle;
+ try testing.expectEqual(@as(usize, 1), std.mem.count(u8, call(p, .{ .tag = 2, .op = .read, .node = log, .handle = h, .size = 1 << 16 }).bytes, try std.fmt.bufPrint(&rec, "changed {d} deleted\n", .{serial})));
+ _ = call(p, .{ .tag = 3, .op = .release, .node = log, .handle = h });
+}