summaryrefslogtreecommitdiff
path: root/src/dump.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-22 17:43:57 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:14 -0300
commit9695cb098c784792af79c22d46a17f7bc7247d33 (patch)
treefa446f3cb588b3184b7914b3f50c36cd3e5ece7b /src/dump.zig
parentf962de52df4b3d33438150920ae95b8708b0dde0 (diff)
downloadpardes-9695cb098c784792af79c22d46a17f7bc7247d33.tar.gz
pardes-9695cb098c784792af79c22d46a17f7bc7247d33.zip
Repaint PDF highlights by row, send rasters by shared memory, and animate messages
PDF highlights (hover preview, search, selection) are baked into page rasters, and any change re-rendered the whole page with MuPDF; the TTY then re-sent it as base64 (4.7 MB a page), the GUI as a new texture. Worse, a pointer motion over a PDF invalidated the page even when no preview was shown, so every motion paid that. Now: - A raster whose baked highlight set equals the wanted one is left alone. - A highlighted page keeps its clean rows (before highlights and tint); a change repaints only the rows of quads that differ, running MuPDF's highlight pass (pardes_pdf_paint_highlights) over those clean rows and tinting them: the operations a full render performs, so the pixels are identical. MuPDF band renders are NOT bit-identical to a whole page (edge rows, resampled images), so they are never used to patch; the comment claiming otherwise is corrected. - ImagePlace.patch hands shells the changed rows; the GUI uploads just those rows into the texture it holds. - The TTY probes kitty shared memory (t=s) with an id vaxis never reaches and sends rasters as a /dev/shm name when the terminal reads it; direct base64 otherwise (ssh). - Shells that take row patches (GUI, TTY with shm) repaint a selection while it is dragged instead of only on release. Latency elsewhere: - TTY: an animating frame no longer sleeps 16 ms blind; a tick thread posts into the input queue, so input inside the frame is handled at once. - TTY and GUI: queued pointer motions coalesce to the last. - GUI: a skipped swapchain image re-arms the frame (3 retries); animations still tick while nothing presents. - Editing: the line index is carried across an edit instead of rebuilt from a scan of the whole file per keystroke. Messages fall into their row (ease-in; the GUI slides the band out from under the tagline, a terminal fades it), stay until the next input as before, linger MessageLinger ms (default 800), and dissolve (ease-out). MessageAnimation toggles it; both are settings, in Config and startup files. The snapshot harness pins the old behaviour. The detached server now ticks animations. A restored terminal comes back live: the old screen and scrollback (dumped as clean VT by ghostty's formatter, replayed at the new size; older dumps fall back to their rendered text), a dim "restored history" marker, then a new shell in the directory it was in. Right-click on a line number in a file pane looks at that line (a sticky context header's number included). Measured with an external pty driver (TTY), an in-process fence trace (GUI, PARDES_TEST_LATENCY), and test/pdf_pointer_bench.zig (pixel identity against the baseline and a whole-page oracle); balanced A/A/B rounds, paired per-round statistics. Messages stack: each event gets its own row and its own fall, linger and dissolve; a line keeps its row until it leaves and a new one fills the first free row. Announcements and statuses are replaced in place, not stacked. MessageFall, MessageDissolve and DumpDir are settings Config reports. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Diffstat (limited to 'src/dump.zig')
-rw-r--r--src/dump.zig19
1 files changed, 17 insertions, 2 deletions
diff --git a/src/dump.zig b/src/dump.zig
index 89abd995..ff5d2166 100644
--- a/src/dump.zig
+++ b/src/dump.zig
@@ -11,11 +11,11 @@ const log = std.log.scoped(.dump);
/// pins it for deterministic goldens); else $XDG_DATA_HOME|~/.local/share
/// /pardes/pardes-<utc>.zon — timestamped so dumps never overwrite each other.
/// Creates the pardes dir (parents assumed; a failure surfaces at open).
-pub fn outPath(buf: *[1024:0]u8) ?[:0]const u8 {
+pub fn outPath(buf: *[1024:0]u8, dir_setting: []const 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 = defaultDirectory(&dir_buf) orelse return null;
+ const dir = directory(&dir_buf, dir_setting) orelse return null;
var dz: [901:0]u8 = undefined;
@memcpy(dz[0..dir.len], dir);
dz[dir.len] = 0;
@@ -32,6 +32,15 @@ pub fn outPath(buf: *[1024:0]u8) ?[:0]const u8 {
ds.getSecondsIntoMinute(),
}, 0) catch null;
}
+/// Where dumps go and relative Restore names are looked up: the `DumpDir`
+/// setting when set (a leading `~/` is the home directory), else the default.
+pub fn directory(buf: []u8, dir_setting: []const u8) ?[]const u8 {
+ if (dir_setting.len == 0) return defaultDirectory(buf);
+ if (std.mem.startsWith(u8, dir_setting, "~/")) if (std.c.getenv("HOME")) |h|
+ return std.fmt.bufPrint(buf, "{s}/{s}", .{ std.mem.span(h), dir_setting[2..] }) catch null;
+ return std.fmt.bufPrint(buf, "{s}", .{dir_setting}) 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|
@@ -69,8 +78,14 @@ pub const PaneKind = enum {
pub const Terminal = struct {
cwd: []const u8 = "",
+ /// The rendered scrollback and screen as plain text, one row per line.
stream: []const u8 = "",
stream_b64: []const u8 = "",
+ /// `stream_b64` is the emulator's primary screen and scrollback as clean
+ /// VT (ghostty's formatter), which replays to what the screen showed.
+ /// Absent (older dumps), it is the raw tail of the pty's output, which
+ /// replays faithfully only if it holds the whole session at one size.
+ stream_is_screen: bool = false,
cursor: Cursor = .{},
};