summaryrefslogtreecommitdiff
path: root/src/tty.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-07-06 20:43:40 -0300
committerGabriel Schneider <[email protected]>2026-08-01 15:02:07 -0300
commit513938c1cfb216a3bc4a3559cf7731b8e44a952f (patch)
tree7b711c30ea6ebc255a1d691223b2cb93cd7dedf2 /src/tty.zig
parentd0ba070a87c54c538e5f788485391b0af927d0fb (diff)
downloadpardes-513938c1cfb216a3bc4a3559cf7731b8e44a952f.tar.gz
pardes-513938c1cfb216a3bc4a3559cf7731b8e44a952f.zip
dumps: per-user data dir + timestamped names; Restore builtin loads a dump into the live session. dump.outPath resolves $PARDES_DUMP verbatim (the snapshot harness pins /tmp/pardes-dump.zon so dump/load/restore goldens stay deterministic), else $XDG_DATA_HOME|~/.local/share /pardes/pardes-YYYYMMDD-HHMMSS.zon (dir mkdir-ed; wall clock via libc clock_gettime — std.time.timestamp is gone in 0.16). After write_dump the shell reports the written path back (core.setLastDump) and the topbar grows "Restore <path>": middle-clicking Restore reloads the last dump, and "Restore <path>" executed anywhere takes the path as its first argument (onSelect prefix match). Core stays sans-IO: the builtin stashes restore_req; each shell consumes takeRestore() after drainEffects and swaps in initFromDump at the current screen size (pre-sized: dump panes never greet), tearing down the live ptys (tty: cancel reader + close + gen bump; gui: SIGKILL, the gen-guarded eof closes the old fds). Web ignores it. New restore.snap golden: KEEPME survives the restore, GONESOON echoed after Dump does not, the topbar word appears then resets. 29/29.
Diffstat (limited to 'src/tty.zig')
-rw-r--r--src/tty.zig28
1 files changed, 26 insertions, 2 deletions
diff --git a/src/tty.zig b/src/tty.zig
index 97f10a7a..c62ace3d 100644
--- a/src/tty.zig
+++ b/src/tty.zig
@@ -68,7 +68,7 @@ pub fn run(init: std.process.Init, opts: pardes.Options) !void {
pardes.image.start(io, gpa);
defer pardes.image.stop();
- const core = if (opts.load_path) |lp| blk: {
+ var core = if (opts.load_path) |lp| blk: {
const bytes = try look.readFile(gpa, lp);
defer gpa.free(bytes);
break :blk try pardes.Pardes.initFromDump(gpa, opts, bytes);
@@ -193,6 +193,27 @@ pub fn run(init: std.process.Init, opts: pardes.Options) !void {
drainEffects(core, &ptys, &gens, io, gpa, &loop, &vx, &tty, true);
if (core.quit) break;
+ // Restore builtin: swap in a core rebuilt from the dump; the live
+ // shells die with their masters (readers canceled, gens bumped so
+ // their late eofs never touch the replay panes)
+ if (core.takeRestore()) |rp| blk: {
+ const bytes = look.readFile(gpa, rp) catch break :blk;
+ defer gpa.free(bytes);
+ var o = core.opts;
+ o.cols = core.screen_w;
+ o.rows = core.screen_h; // pre-size: dump panes never greet
+ const nc = pardes.Pardes.initFromDump(gpa, o, bytes) catch break :blk;
+ for (&ptys, 0..) |*slot, pid| if (slot.*) |*pt| {
+ pt.reader.cancel(io) catch {};
+ _ = libc.close(pt.file.handle);
+ slot.* = null;
+ gens[pid] +%= 1;
+ };
+ kitty_handles = @splat(null);
+ core.deinit();
+ core = nc;
+ }
+
// live cwd for tags/look: cheap per-pane lookup, per frame
for (&ptys, 0..) |*slot, id| if (slot.*) |pt| {
var lbuf: [1024]u8 = undefined;
@@ -310,10 +331,13 @@ fn drainEffects(
},
.write_dump => {
const out = core.dump_out orelse continue;
- const fd = libc.open(pardes.dump.default_path, .{ .ACCMODE = .WRONLY, .CREAT = true, .TRUNC = true }, @as(libc.mode_t, 0o644));
+ var pbuf: [1024:0]u8 = undefined;
+ const path = pardes.dump.outPath(&pbuf) orelse continue;
+ const fd = libc.open(path, .{ .ACCMODE = .WRONLY, .CREAT = true, .TRUNC = true }, @as(libc.mode_t, 0o644));
if (fd < 0) continue;
writeFd(fd, out);
_ = libc.close(fd);
+ core.setLastDump(path);
},
.set_clipboard => {
// mirror the core's yank register out via OSC 52