summaryrefslogtreecommitdiff
path: root/test/panes.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 /test/panes.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 'test/panes.zig')
-rw-r--r--test/panes.zig37
1 files changed, 37 insertions, 0 deletions
diff --git a/test/panes.zig b/test/panes.zig
index 8e71e69d..2d3aed43 100644
--- a/test/panes.zig
+++ b/test/panes.zig
@@ -394,6 +394,42 @@ const BodyHitTests = struct {
}
};
+const LineNumberLookTests = struct {
+ test "right-click on a line number looks at that line, sticky context headers included" {
+ if (!syntax.enabled) return error.SkipZigTest;
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 64, .rows = 18 });
+ defer p.deinit();
+ p.row_metrics = .{ .body_w = 10, .body_h = 20, .tagline_w = 8, .tagline_h = 10 };
+ const pane = try TreeContextTests.setZigFile(p, "const Box = struct {\n pub fn work(\n value: usize,\n ) void {\n" ++ " // body\n" ** 60 ++ " }\n};\n");
+ try std.testing.expect(p.executeBuiltinLine(0, "TreeContext"));
+ pane.scrollBy(30);
+ var frame = std.heap.ArenaAllocator.init(p.gpa);
+ defer frame.deinit();
+ _ = try p.render(frame.allocator());
+ const layer = &p.surface.body_layers[0];
+ try std.testing.expect(layer.context_rows >= 2);
+ // A header row's number is its declaration's own source line, not the
+ // body line it sits over (`pub fn work(` is line 1); a body row's is
+ // its own.
+ try std.testing.expectEqual(@as(i32, 1), pane.wrapAt(1).line);
+ const rows = [_]u16{ 1, pane.context_rows + 3 };
+ for (rows) |row| {
+ // Each Look recentres the view; come back under the headers.
+ pane.scrollBy(30 - pane.scroll());
+ _ = frame.reset(.retain_capacity);
+ _ = try p.render(frame.allocator());
+ const expected = pane.wrapAt(row).line;
+ var press = BodyHitTests.mouse(&p.surface.body_layers[0], row, 1, .press);
+ press.button = .right;
+ var release = BodyHitTests.mouse(&p.surface.body_layers[0], row, 1, .release);
+ release.button = .right;
+ p.update(.{ .mouse = press });
+ p.update(.{ .mouse = release });
+ try std.testing.expectEqual(expected, pane.cur_row);
+ }
+ }
+};
+
const TreeContextTests = struct {
const source = "const Box = struct {\n" ++
" pub fn work(\n" ++
@@ -4069,6 +4105,7 @@ test {
_ = TagNameTintTests;
_ = TreeContextTests;
_ = BodyHitTests;
+ _ = LineNumberLookTests;
_ = TtySelectionTests;
_ = ClickCursorTests;
_ = JumpSelectionTests;