summaryrefslogtreecommitdiff
path: root/src/File.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/File.zig')
-rw-r--r--src/File.zig40
1 files changed, 35 insertions, 5 deletions
diff --git a/src/File.zig b/src/File.zig
index c738ee58..d41007c3 100644
--- a/src/File.zig
+++ b/src/File.zig
@@ -105,6 +105,7 @@ pub const State = struct {
pub const NodeStep = struct { ranges: []modal.Selection, primary: usize };
pub fn dumpPane(
+ p: *Pardes,
arena: std.mem.Allocator,
pane: *const Pane,
file: *const State,
@@ -114,6 +115,18 @@ pub fn dumpPane(
origin: []const u8,
origin_arg: []const u8,
) !dump.Pane {
+ const dirty = file.revision != file.saved_revision;
+ const on_disk = onDisk(file.path);
+ // A clean file's text is its file's: read from disk when restored, so
+ // a change made there since is what comes back. Any other is kept, once.
+ const from_disk = file.output == null and !dirty and on_disk;
+ // What an unsaved pane's text was read against: the disk as it is, or,
+ // when a change there was seen already, something it is not.
+ const disk_hash: ?u64 = if (file.output != null or !dirty or !on_disk) null else if (file.disk_newer) |newer| newer +% 1 else blk: {
+ const bytes = filesystem.read(p, file.path) catch break :blk null;
+ defer p.gpa.free(bytes);
+ break :blk std.hash.Wyhash.hash(0, bytes);
+ };
return .{
.kind = .file,
.tag = tag,
@@ -127,10 +140,10 @@ pub fn dumpPane(
.tree_context = file.tree_context,
.location_rows = try dumpLocationRows(arena, file.location_rows),
.path = file.path,
- .content = file.content,
- .content_b64 = try dump.encodeBytes(arena, file.content),
- .dirty = file.revision != file.saved_revision,
- .on_disk = onDisk(file.path),
+ .content_b64 = if (from_disk) "" else try dump.encodeBytes(arena, file.content),
+ .dirty = dirty,
+ .disk_hash = disk_hash,
+ .on_disk = on_disk,
.origin = origin,
.origin_arg = origin_arg,
.mini_source = if (file.mini) |mini| mini.source else "",
@@ -855,7 +868,16 @@ pub fn restore(p: *Pardes, id: usize, src: dump.Pane) !*Pane {
saved.content_b64.len > encoded_limit or saved.mini_colors_b64.len > encoded_limit)
return error.InvalidMini;
}
- const content: []u8 = if (saved.content_b64.len > 0)
+ // A clean file's text is read from its file: one changed on disk since
+ // the dump comes back changed, never as the old text marked clean (and
+ // a dump from before, which kept it, is read so too). Gone from disk, the
+ // dump's text if it kept one.
+ const from_disk: ?[]u8 = if (Output.fromWord(saved.origin) == null and !saved.dirty and saved.on_disk and
+ saved.mini_source.len == 0 and filesystem.localPath(saved.path) != null)
+ filesystem.read(p, saved.path) catch null
+ else
+ null;
+ const content: []u8 = if (from_disk) |bytes| bytes else if (saved.content_b64.len > 0)
try dump.decodeBytes(p.gpa, saved.content_b64)
else
try p.gpa.dupe(u8, saved.content);
@@ -923,6 +945,14 @@ pub fn restore(p: *Pardes, id: usize, src: dump.Pane) !*Pane {
// One never on disk (Config's new file, a name not yet saved) is
// restored as it was: clean, and nothing deleted.
if (output == null and saved.on_disk and !onDisk(path)) deleted(p, @intCast(id));
+ // Unsaved, and its file changed on disk since the text was read: said,
+ // and its first Save asks before overwriting the newer file.
+ if (saved.disk_hash) |read_against| if (output == null and onDisk(path)) {
+ if (filesystem.read(p, path)) |bytes| {
+ defer p.gpa.free(bytes);
+ if (std.hash.Wyhash.hash(0, bytes) != read_against) changed(p, @intCast(id), bytes);
+ } else |_| {}
+ };
return pane;
}