From 63d584a0ba7806759f7139e87f45e411c9a1573d Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Mon, 28 Sep 2026 17:27:30 -0300 Subject: A Save the host cannot do fails the 9P write that asked for it, and the log names the path and why The write answered ok and the pane stayed dirty, with `save: AccessDenied` on its message row: a script saw success. The failure now says `Save : `, and a 9P write that waited on the save fails with EIO and that text, logged as an err record. Co-Authored-By: Claude Opus 5.5 --- src/pardes.zig | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'src/pardes.zig') diff --git a/src/pardes.zig b/src/pardes.zig index f559b125..581f616e 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -2261,7 +2261,7 @@ test "a save the host could not do leaves the pane dirty" { const Refusing = struct { fn writeFile(ctx: ?*anyopaque, pane: u8, _: []const u8, _: []const u8) void { const core: *Pardes = @ptrCast(@alignCast(ctx.?)); - core.saveFailed(pane, "save", error.PermissionDenied); + core.saveFailed(pane, "/x/y.txt", error.PermissionDenied); } }; const p = try Pardes.init(gpa, .{ .tty_only = true, .cols = 100, .rows = 30 }); @@ -4906,15 +4906,23 @@ pub const Pardes = struct { if (p.host.vtable.write_file) |f| return f(p.host.ctx, pane, path, bytes); // The in-process filesystem reports the same way a real host does, so // an OOM here leaves the pane dirty rather than looking saved. - if (!p.fallback.writeFile(path, bytes)) p.saveFailed(pane, "save", error.OutOfMemory); + if (!p.fallback.writeFile(path, bytes)) p.saveFailed(pane, path, error.OutOfMemory); } - pub fn saveFailed(p: *Pardes, id: u8, what: []const u8, err: anyerror) void { + /// A write of `path` the host could not do: the pane stays dirty, the + /// message row says `Save : `, and the 9P write that asked + /// for it, waiting on the save, fails with that (`fs.late_failure`). + pub fn saveFailed(p: *Pardes, id: u8, path: []const u8, err: anyerror) void { if (p.panes[id]) |pane| if (pane.file) |*f| { // The `-%` spelling fs.zig already uses for "make this dirty". f.saved_revision = f.revision -% 1; }; - p.reportError(id, what, err); + var what: [limits.host_path_cap + 8]u8 = undefined; + p.reportError(id, std.fmt.bufPrint(&what, "Save {s}", .{path}) catch "Save", err); + const said = if (p.panes[id]) |pane| pane.msg[0..pane.msg_len] else "Save failed"; + const kept = @import("Messages.zig").clip(said, p.fs.late_failure.len); + @memcpy(p.fs.late_failure[0..kept.len], kept); + p.fs.late_failure_len = @intCast(kept.len); } /// The path a watch is about: a real file's, or a PDF's. -- cgit v1.3