diff options
| -rw-r--r-- | src/File.zig | 4 | ||||
| -rw-r--r-- | src/dump.zig | 34 |
2 files changed, 38 insertions, 0 deletions
diff --git a/src/File.zig b/src/File.zig index 6a1ac319..810bc766 100644 --- a/src/File.zig +++ b/src/File.zig @@ -809,6 +809,10 @@ pub fn restore(p: *Pardes, id: usize, src: dump.Pane) !*Pane { .location_rows = location_rows, .scroll = src.scroll, .revision = @intFromBool(saved.dirty), + // Restored with unsaved text, it has text to lose as an edited pane + // has: a hash its text does not match, so Exit, Restore, Del and + // get ask first (builtins.warnModifiedIn reads only edited panes). + .saved_hash = if (saved.dirty) std.hash.Wyhash.hash(0, content) +% 1 else null, .history = history, }; pane.file.?.tree_context = saved.tree_context and supportsContext(pane); diff --git a/src/dump.zig b/src/dump.zig index 88a95994..54b77451 100644 --- a/src/dump.zig +++ b/src/dump.zig @@ -949,3 +949,37 @@ test "a restored pane keeps its dot, as acme's dump keeps a window's" { try std.testing.expectEqual(@as(u32, 4), dot.q0); try std.testing.expectEqual(@as(u32, 7), dot.q1); } + +test "a pane restored with unsaved text is asked about by Exit, Restore, Del and get" { + const gpa = std.testing.allocator; + const p = try Pardes.init(gpa, .{ .tty_only = true }); + defer p.deinit(); + const pane = try p.setTestFile("saved\n"); + _ = ctlfs.pane.spliceBody(p, pane, 0, 0, "unsaved ").?; + try std.testing.expect(pane.file.?.revision != pane.file.?.saved_revision); + try dumpState(p); + // Restore reads its dump before it warns: one it can read. + var tmp = std.testing.tmpDir(.{}); + defer tmp.cleanup(); + try tmp.dir.writeFile(std.testing.io, .{ .sub_path = "d.zon", .data = p.dump_out.? }); + var dir_buf: [4096]u8 = undefined; + const dir = dir_buf[0..try tmp.dir.realPath(std.testing.io, &dir_buf)]; + var restore_line: [4200]u8 = undefined; + for ([_][]const u8{ "Exit", "Restore", "Del", "get" }) |word| { + const restored = try initFromDump(gpa, .{ .tty_only = true }, p.dump_out.?); + defer restored.deinit(); + const id = for (restored.panes, 0..) |slot, i| { + if (slot) |candidate| if (candidate.file != null and candidate.file.?.output == null) break i; + } else return error.FileLost; + const th = @import("ninep/testing.zig"); + const node = if (std.mem.eql(u8, word, "Del") or std.mem.eql(u8, word, "get")) + ctlfs.Node.of(restored.panes[id].?.serial, .ctl) + else + @intFromEnum(ctlfs.TopFile.ctl); + const line = if (std.mem.eql(u8, word, "Restore")) try std.fmt.bufPrint(&restore_line, "Restore {s}/d.zon\n", .{dir}) else if (std.mem.eql(u8, word, "Exit")) "Exit\n" else if (std.mem.eql(u8, word, "Del")) "Del\n" else "get\n"; + const answer = th.wr(restored, node, line); + try std.testing.expectEqual(ctlfs.Status.err, answer.reply.status); + try std.testing.expect(std.mem.indexOf(u8, answer.reply.ename, "Modified") != null); + try std.testing.expect(!restored.quit and restored.panes[id] != null); + } +} |
