summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/builtins.zig19
-rw-r--r--src/ninep/ctl.zig14
-rw-r--r--src/ninep/pane.zig3
-rw-r--r--src/tagline.zig2
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";