summaryrefslogtreecommitdiff
path: root/src/File.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/File.zig')
-rw-r--r--src/File.zig28
1 files changed, 26 insertions, 2 deletions
diff --git a/src/File.zig b/src/File.zig
index 810bc766..4011301a 100644
--- a/src/File.zig
+++ b/src/File.zig
@@ -58,6 +58,12 @@ pub const State = struct {
/// as an undo to the save point is in acme.
saved_hash: ?u64 = null,
watch_after_save: bool = false,
+ /// The file changed on disk under unsaved edits, which were kept (see
+ /// `changed`): its hash, so the same change is said once, until a Save
+ /// or get settles it. A Save warns once before overwriting it, as acme's
+ /// Put does (exec.c:577, "modified since last read").
+ disk_newer: ?u64 = null,
+ disk_newer_warned: bool = false,
/// Seconds of the last content change, for the filesystem's stat; zero until edited.
mtime: u32 = 0,
/// Non-null for a generated output buffer rather than an on-disk file.
@@ -964,12 +970,30 @@ pub fn redo(p: *Pardes, pane: *Pane) void {
restoreSnap(pane, f, next);
}
-/// Commit an externally rewritten file onto the same undo history as typed
-/// edits. Unsaved work remains one `u` away; there is no third merge state.
+/// A file rewritten on disk. A clean buffer takes the new text, committed
+/// onto the same undo history as typed edits. A buffer with unsaved edits
+/// is never reloaded under them: it keeps its text and stays dirty, and
+/// says so once (`<file> changed on disk (get reloads it, Save overwrites
+/// it)`, logged `changed <serial>`); get then asks before throwing
+/// the edits away and Save before overwriting the newer file. acme reloads
+/// nothing by itself: its get asks (winclean) and its Put refuses a file
+/// modified since it was read (exec.c:577).
pub fn changed(p: *Pardes, id: u8, bytes: []const u8) void {
const pane = p.panes[id] orelse return;
const f = if (pane.file) |*file| file else return;
if (std.mem.eql(u8, f.content, bytes)) return;
+ if (f.saved_hash) |saved| if (f.revision != f.saved_revision and std.hash.Wyhash.hash(0, f.content) != saved) {
+ const disk = std.hash.Wyhash.hash(0, bytes);
+ if (f.disk_newer == disk) return;
+ f.disk_newer = disk;
+ f.disk_newer_warned = false;
+ var said: [limits.host_path_cap + 64]u8 = undefined;
+ p.setMessage(id, std.fmt.bufPrint(&said, "{s} changed on disk (get reloads it, Save overwrites it)", .{f.path}) catch "changed on disk (get reloads it, Save overwrites it)");
+ var rec: [16]u8 = undefined;
+ pardes.ctlfs.events.notePath(p, "changed", std.fmt.bufPrint(&rec, "{d}", .{pane.serial}) catch "");
+ return;
+ };
+ f.disk_newer = null;
const new = p.gpa.dupe(u8, bytes) catch return;
pushUndo(p, pane);
setContent(p, f, new);