From 6878e1c309172d624c0d7a3555f6f0217ae6770e Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Thu, 10 Sep 2026 10:57:58 -0300 Subject: Resolve relative restores in the dump directory and propagate LSP probe errors --- src/detached/server.zig | 2 +- src/dump.zig | 16 ++++++++------ src/fs.zig | 57 +++++++++++++++++++++++++++++++++++++++++++++++++ src/gui/gui.zig | 2 +- src/macos.zig | 2 +- src/tty/tty.zig | 2 +- 6 files changed, 71 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/detached/server.zig b/src/detached/server.zig index 8b49bcb2..9a47a562 100644 --- a/src/detached/server.zig +++ b/src/detached/server.zig @@ -1163,7 +1163,7 @@ pub fn run(init: std.process.Init, opts: pardes.Options, name: []const u8) !void try session.core.pump(h); if (session.core.quit) break; if (session.core.takeRestore()) |path| restore: { - const bytes = filesystem.readFile(gpa, path) catch |err| { + const bytes = filesystem.readRestore(gpa, path) catch |err| { session.core.reportError(session.core.active, "Restore", err); break :restore; }; diff --git a/src/dump.zig b/src/dump.zig index bb692481..93bf08cc 100644 --- a/src/dump.zig +++ b/src/dump.zig @@ -15,12 +15,7 @@ pub fn outPath(buf: *[1024:0]u8) ?[:0]const u8 { if (std.c.getenv("PARDES_DUMP")) |p| return std.fmt.bufPrintSentinel(buf, "{s}", .{std.mem.span(p)}, 0) catch null; var dir_buf: [900]u8 = undefined; - const dir = if (std.c.getenv("XDG_DATA_HOME")) |x| - std.fmt.bufPrint(&dir_buf, "{s}/pardes", .{std.mem.span(x)}) catch return null - else if (std.c.getenv("HOME")) |h| - std.fmt.bufPrint(&dir_buf, "{s}/.local/share/pardes", .{std.mem.span(h)}) catch return null - else - return null; + const dir = defaultDirectory(&dir_buf) orelse return null; var dz: [901:0]u8 = undefined; @memcpy(dz[0..dir.len], dir); dz[dir.len] = 0; @@ -37,6 +32,15 @@ pub fn outPath(buf: *[1024:0]u8) ?[:0]const u8 { ds.getSecondsIntoMinute(), }, 0) catch null; } +/// The standard dump directory, without creating it or generating a filename. +pub fn defaultDirectory(buf: []u8) ?[]const u8 { + if (std.c.getenv("XDG_DATA_HOME")) |x| + return std.fmt.bufPrint(buf, "{s}/pardes", .{std.mem.span(x)}) catch null; + if (std.c.getenv("HOME")) |h| + return std.fmt.bufPrint(buf, "{s}/.local/share/pardes", .{std.mem.span(h)}) catch null; + return null; +} + pub const magic = "pardes-dump"; pub const version: u32 = 1; pub const max_panes: usize = 16; diff --git a/src/fs.zig b/src/fs.zig index 14b6a76a..50b56f76 100644 --- a/src/fs.zig +++ b/src/fs.zig @@ -1200,6 +1200,63 @@ pub fn readFile(gpa: std.mem.Allocator, path: []const u8) ![]u8 { return readFileLimit(gpa, path, limits.max_file_bytes); } +/// Restore first tries a relative argument under the default dump directory, +/// then preserves the ordinary file lookup. Absolute paths remain verbatim. +pub fn readRestore(gpa: std.mem.Allocator, path: []const u8) ![]u8 { + var dir_buf: [4096]u8 = undefined; + const dir = @import("dump.zig").defaultDirectory(&dir_buf); + return readRestoreIn(gpa, path, dir); +} + +fn readRestoreIn(gpa: std.mem.Allocator, path: []const u8, dir: ?[]const u8) ![]u8 { + if (!std.fs.path.isAbsolute(path)) { + if (dir) |base| { + var buf: [4096]u8 = undefined; + if (std.fmt.bufPrint(&buf, "{s}/{s}", .{ base, path })) |candidate| { + if (readFile(gpa, candidate)) |bytes| return bytes else |err| switch (err) { + error.FileNotFound => {}, + else => return err, + } + } else |_| {} + } + } + return readFile(gpa, path); +} + +test "Restore prefers default directory then falls back to original path" { + if (!platform_has_fs) return error.SkipZigTest; + const gpa = std.testing.allocator; + var tmp = std.testing.tmpDir(.{}); + defer tmp.cleanup(); + const relative = try std.fmt.allocPrint(gpa, ".zig-cache/tmp/{s}/a.dump", .{tmp.sub_path}); + defer gpa.free(relative); + const base = try std.fmt.allocPrint(gpa, ".zig-cache/tmp/{s}/dumps", .{tmp.sub_path}); + defer gpa.free(base); + const nested = try std.fmt.allocPrint(gpa, "dumps/.zig-cache/tmp/{s}", .{tmp.sub_path}); + defer gpa.free(nested); + try tmp.dir.createDirPath(std.testing.io, nested); + try tmp.dir.writeFile(std.testing.io, .{ .sub_path = "dumps/a.dump", .data = "short name" }); + const short = try readRestoreIn(gpa, "a.dump", base); + defer gpa.free(short); + try std.testing.expectEqualStrings("short name", short); + try tmp.dir.writeFile(std.testing.io, .{ .sub_path = "a.dump", .data = "original" }); + const fallback = try readRestoreIn(gpa, relative, base); + defer gpa.free(fallback); + try std.testing.expectEqualStrings("original", fallback); + const candidate = try std.fmt.allocPrint(gpa, "{s}/{s}", .{ base, relative }); + defer gpa.free(candidate); + try writeFile(candidate, "default"); + const preferred = try readRestoreIn(gpa, relative, base); + defer gpa.free(preferred); + try std.testing.expectEqualStrings("default", preferred); + const absolute = try tmp.dir.realPathFileAlloc(std.testing.io, "a.dump", gpa); + defer gpa.free(absolute); + const direct = try readRestoreIn(gpa, absolute, base); + defer gpa.free(direct); + try std.testing.expectEqualStrings("original", direct); + try std.testing.expectError(error.FileNotFound, readRestoreIn(gpa, "missing-restore-test.dump", base)); +} + fn readFileLimit(gpa: std.mem.Allocator, path: []const u8, limit: usize) ![]u8 { if (std.mem.indexOfScalar(u8, path, 0) != null) return error.OpenFailed; if (!platform_has_fs or std.mem.startsWith(u8, path, "/virtual/")) { diff --git a/src/gui/gui.zig b/src/gui/gui.zig index a7d9d167..f7b9fc7e 100644 --- a/src/gui/gui.zig +++ b/src/gui/gui.zig @@ -2382,7 +2382,7 @@ fn localSession( } } if (core.takeRestore()) |rp| blk: { - const bytes = filesystem.readFile(gpa, rp) catch |err| { + const bytes = filesystem.readRestore(gpa, rp) catch |err| { core.reportError(core.active, "Restore", err); break :blk; }; diff --git a/src/macos.zig b/src/macos.zig index 36c70f86..3e4edd12 100644 --- a/src/macos.zig +++ b/src/macos.zig @@ -1227,7 +1227,7 @@ export fn pardes_tick() bool { fn restoreCore(st: *State) bool { if (st.core.quit) return false; const path = st.core.takeRestore() orelse return false; - const bytes = filesystem.readFile(st.gpa, path) catch |err| { + const bytes = filesystem.readRestore(st.gpa, path) catch |err| { st.core.reportError(st.core.active, "Restore", err); return false; }; diff --git a/src/tty/tty.zig b/src/tty/tty.zig index 1f11c535..0379e59c 100644 --- a/src/tty/tty.zig +++ b/src/tty/tty.zig @@ -729,7 +729,7 @@ fn localSession( frames: while (!core.quit) { try core.pump(host); if (core.takeRestore()) |rp| blk: { - const bytes = filesystem.readFile(gpa, rp) catch |err| { + const bytes = filesystem.readRestore(gpa, rp) catch |err| { core.reportError(core.active, "Restore", err); break :blk; }; -- cgit v1.3