diff options
Diffstat (limited to 'src/File.zig')
| -rw-r--r-- | src/File.zig | 40 |
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; } |
