diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/builtins.zig | 19 | ||||
| -rw-r--r-- | src/ninep/ctl.zig | 14 | ||||
| -rw-r--r-- | src/ninep/pane.zig | 3 | ||||
| -rw-r--r-- | src/tagline.zig | 2 |
4 files changed, 29 insertions, 9 deletions
diff --git a/src/builtins.zig b/src/builtins.zig index b0499dc0..ca01e0fe 100644 --- a/src/builtins.zig +++ b/src/builtins.zig @@ -536,13 +536,18 @@ fn warnModifiedIn(c: Ctx, asking: Pane.Discarding, which: Asked) bool { // under 100 bytes it is not asked about, as acme's winclean does not // whine about a small unnamed window, nor about a command's output. const scratch = if (f.output) |o| o.from == .cmd and o.from.cmd == .New else false; - if (f.revision == f.saved_revision or !(panes.Output.fileTraits(f.output).saves or scratch)) continue; - if (f.output != null and f.content.len < 100) continue; - // Dirty by a rename alone is no text to lose, as get says (ctl.zig). - // Nor is a buffer never edited at all: its first edit is what keeps - // the text it had (File.zig), so with none there is nothing to lose. - const saved = f.saved_hash orelse continue; - if (std.hash.Wyhash.hash(0, f.content) == saved) continue; + // A file deleted on disk is asked about, edited or not: its text is + // nowhere else now (acme's winclean asks the same). + const gone = f.disk_gone and f.output == null; + if (!gone) { + if (f.revision == f.saved_revision or !(panes.Output.fileTraits(f.output).saves or scratch)) continue; + if (f.output != null and f.content.len < 100) continue; + // Dirty by a rename alone is no text to lose, as get says (ctl.zig). + // Nor is a buffer never edited at all: its first edit is what keeps + // the text it had (File.zig), so with none there is nothing to lose. + const saved = f.saved_hash orelse continue; + if (std.hash.Wyhash.hash(0, f.content) == saved) continue; + } if (pane.discard_warned) |w| if (w.revision == f.revision and w.by == asking) continue; pane.discard_warned = .{ .revision = f.revision, .by = asking }; // Scratches share a name: each is named with its pane's serial too, diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig index b93d83c3..ebb85609 100644 --- a/src/ninep/ctl.zig +++ b/src/ninep/ctl.zig @@ -2201,6 +2201,20 @@ test "+Unsaved drops a pane once it has closed" { try testing.expect(std.mem.indexOf(u8, list.file.?.content, "/tmp/pardes-unsaved-a.txt: Modified") == null); } +test "a buffer whose file was deleted on disk is dirty, and Del asks first" { + const p = try withFile(testing.allocator, "x\n"); + defer p.deinit(); + const serial = serialOf(p); + try testing.expectEqualStrings("0", std.mem.trimEnd(u8, rd(p, Node.of(serial, .dirty), 0, 8).bytes, "\n")); + pardes.panes.File.deleted(p, @intCast(p.paneBySerial(serial).?)); + try testing.expectEqualStrings("1", std.mem.trimEnd(u8, rd(p, Node.of(serial, .dirty), 0, 8).bytes, "\n")); + try testing.expectEqual(Status.err, wr(p, Node.of(serial, .ctl), "Del\n").reply.status); + try testing.expect(p.paneBySerial(serial) != null); + _ = wr(p, Node.of(serial, .ctl), "Del\n"); + p.sync(); + try testing.expect(p.paneBySerial(serial) == null); +} + test "every EINVAL a write gets says why, in its err record too; DEL is a control character in a line" { const p = try withFile(testing.allocator, "x\n"); defer p.deinit(); diff --git a/src/ninep/pane.zig b/src/ninep/pane.zig index f90a83d8..d48c8e71 100644 --- a/src/ninep/pane.zig +++ b/src/ninep/pane.zig @@ -125,7 +125,8 @@ pub fn tagOf(p: *Pardes, pane: *Pane) []const u8 { pub fn dirtyOf(pane: *const Pane) bool { const f = if (pane.file) |*x| x else return false; if (!panes.Output.fileTraits(f.output).saves) return false; - return f.revision != f.saved_revision; + // Its file deleted on disk: the text is only here now, as acme counts it. + return f.revision != f.saved_revision or f.disk_gone; } /// The pane's name: its file, its document, or a terminal's directory. diff --git a/src/tagline.zig b/src/tagline.zig index 5f95b2a0..df093925 100644 --- a/src/tagline.zig +++ b/src/tagline.zig @@ -30,7 +30,7 @@ const dirty_marker = " *"; /// A file with changes it has not saved. pub fn dirty(pane: *const panes.Pane) bool { const f = pane.file orelse return false; - return panes.Output.fileTraits(f.output).saves and f.revision != f.saved_revision; + return panes.Output.fileTraits(f.output).saves and (f.revision != f.saved_revision or f.disk_gone); } pub const legacy_pane_tail = " Del"; pub const legacy_file_pane_tail = " Save Del"; |
