From ba0a0f82be43dde325012b3018b186bc808bdafc Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Tue, 29 Sep 2026 08:00:41 -0300 Subject: A Save whose write fails changes nothing: not the name, not the dirty flag A scratch took its new name before the host wrote it, so `Save /root/x.txt` failing with EACCES renamed it anyway; a failed write to another name marked a clean file dirty. A scratch is now named once its write is done (promoteSaved), and a failed write puts the saved revision back. Co-Authored-By: Claude Opus 5.5 --- src/exec.zig | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'src/exec.zig') diff --git a/src/exec.zig b/src/exec.zig index 2b0c90cb..0bce67d2 100644 --- a/src/exec.zig +++ b/src/exec.zig @@ -301,17 +301,15 @@ pub fn saveTo(p: *Pardes, id: usize, path: []const u8) void { if (pane.isTerminal()) askWrite(p, id, pane.serial, full); return; }; + // A scratch takes the name once the write is done (promoteSaved): a + // Save that fails changes nothing, the name included. if (f.output != null and panes.Output.fileTraits(f.output).saves) { - const owned = p.gpa.dupe(u8, full) catch return; - p.gpa.free(f.path); - f.path = owned; - f.output = null; // an ordinary file pane from here on - f.watch_after_save = true; - pane.clearCwd(); - // re-derive the tag as a plain file's - if (pane.tag.own) |own| p.gpa.free(own); - pane.tag.own = null; - p.emit(.{ .save_file = .{ .pane = @intCast(id) } }); + p.emit(.{ .save_text = .{ + .pane = @intCast(id), + .serial = pane.serial, + .path = Pardes.SavePath.from(full), + .promote = true, + } }); return; } // its own path, spelled out: the in-place write, so the pane comes clean -- cgit v1.3