summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-01 13:46:44 -0300
committerGabriel Schneider <[email protected]>2026-09-01 13:57:41 -0300
commitcce6b18a49870086982f9a0e1fda90ed170b9fba (patch)
treee5ce990d0a1d43503375d891bc51f283e0a1c215 /test
parentae9325a5cb128d0d952afb8f9feaaca68e5e37a2 (diff)
downloadpardes-cce6b18a49870086982f9a0e1fda90ed170b9fba.tar.gz
pardes-cce6b18a49870086982f9a0e1fda90ed170b9fba.zip
macos: one tagline rule for both hosts, a kqueue beside the inotify, and effects that compile
Three things this shell had its own copy of, and in each case the fix is that it stops having one. **The tagline band.** A pane tag draws at `gui_tagline_font_percent` of the body face and the band it sits on shrinks with it, while the grid row stays body-sized — so something has to decide where the shorter band sits in the taller row. This shell decided by centring, always, which is precisely the case `config.gui_topbar_pane_border_px` exists to prevent: the topbar's unused half-band meets the first pane tag's unused half-band and the window background shows through the seam. The strip is as wide as the bands are short — on a 20-pixel cell, 4 physical pixels at the default 82%, 10 at 50%, 14 at 30% — so it grew as the tagline face shrank and read as "the tagline is wrong on the mac" rather than as one missing rule. The rule is `pardes.taglineBandOffset` in the core now and both pixel hosts call it: row zero bottom-aligned, the first pane-tag row top-aligned, the two joined by `gui_topbar_pane_border_px` in the theme's scrollbar-track colour, every row between centred, and a `Tagbottom` band on the final row flush with the window edge — with the sub-cell strip beneath it painted in that band's own colour, because the core grid holds only whole cells and a window is any height it likes. `pardes_tagline_band_offset`, `pardes_topbar_pane_border_px` and `pardes_topbar_pane_border_rgb` carry it over the C ABI as PHYSICAL pixels: the host multiplies its points by the backing scale going in and divides coming out, which is the snapping `Metrics` already does for the cell, and is what keeps a one-pixel rule one pixel instead of a two-pixel smear. **The watch.** `file_watch.zig` was one mark/reconcile transaction over `inotify`, so the tty shell, the SDL window and the detached daemon all watched nothing off Linux: an edit made outside pardes never reached the pane, and a PDF replaced on disk kept rendering the old inode. It is the same transaction over two kernels now — `init`, `wait`, `stop`, `drain`, `markDir` and `unmarkDir` are still the whole of it, and the hosts wait on a kqueue and poll it exactly as they did the old descriptor. A macOS mark is TWO filters, because a kqueue directory filter reports its entries changing and never a write to a file already inside it: the parent mark follows rename-over saves, `markFile` catches in-place writes, and `remarkFile` re-arms the file filter once a rename has moved the inode. That is the same pair the AppKit host's DispatchSources already used for the same reason. Directory marks are deduplicated here by device and inode, because each `EVFILT_VNODE` filter needs a descriptor of its own and inotify did that deduplication itself; `stop` and `drain` wake through the one `EVFILT_USER` filter, since a kqueue cannot simply be read the way an inotify descriptor can. **The effects.** The three `crt.ci.metal` entry points are `extern "C" [[stitchable]]`. `CIKernel.kernels(withMetalString:)` compiles that source at runtime, looks for stitchable functions, and rejects the WHOLE source with "cannot find a valid stitchable Metal function in the source" when it finds none — so `ScenePostprocessor.init?` returned nil and every scene effect and panel transition silently degraded to the plain CoreText draw. The `effect_sources.zig` test pins the exact spelling of all three, and `draw-effect` in the e2e suite catches the degradation rather than the spelling. Beside them, the offscreen harness owes the core a PRESENTATION. Its window is borderless and never ordered front, so AppKit runs no display cycle and `pardes_frame_presented` — whose only caller is `draw(_:)` — never fired. The core holds pointer gestures inert while a layout mutation has not reached a backend, which for an unpresenting harness is the rest of the script: the first pane a script opened silently killed every later click, drag and Look. So `readFrame` presents what it just rendered, into a bitmap nobody reads. `PARDES_CHROME` also looks under `/Applications`, where a browser's executable lives inside an application bundle and never on `PATH`. The macOS goldens are regenerated; docs/macos.md, config.md, detached.md, web.md and the design PDF follow.
Diffstat (limited to 'test')
-rw-r--r--test/e2e_harness.zig31
-rw-r--r--test/image_harness.zig51
-rw-r--r--test/macos-snapshots/boot.golden8
-rw-r--r--test/macos-snapshots/cwd.golden16
-rw-r--r--test/macos-snapshots/drop.golden40
-rw-r--r--test/macos-snapshots/drop.snap6
-rw-r--r--test/macos-snapshots/font.golden24
-rw-r--r--test/macos-snapshots/keys.golden90
-rw-r--r--test/macos-snapshots/rotate.golden176
-rw-r--r--test/macos-snapshots/trackpad.golden82
-rw-r--r--test/macos_e2e.swift29
-rw-r--r--test/web-snapshots/source-list.golden130
-rw-r--r--test/web_snapshot.mjs6
13 files changed, 381 insertions, 308 deletions
diff --git a/test/e2e_harness.zig b/test/e2e_harness.zig
index 6f2f5ef1..e08e59f2 100644
--- a/test/e2e_harness.zig
+++ b/test/e2e_harness.zig
@@ -261,6 +261,26 @@ pub const Harness = struct {
if (self.trace) self.traceScreen("waitFor miss");
return false;
}
+
+ /// Wait up to `ms` for `needle` to appear in the app's RAW output, pumping
+ /// bytes the whole time. Same shape as `waitFor`, against `raw` rather than
+ /// the grid: for control sequences the emulator swallows and never renders.
+ pub fn waitForRaw(self: *Harness, needle: []const u8, ms: i64) bool {
+ if (std.mem.indexOf(u8, self.raw.items, needle) != null) return true;
+ const deadline = nowMs() + ms;
+ var buf: [4096]u8 = undefined;
+ while (nowMs() < deadline) {
+ var fds = [_]posix.pollfd{.{ .fd = self.master, .events = posix.POLL.IN, .revents = 0 }};
+ _ = posix.poll(&fds, 50) catch {};
+ if ((fds[0].revents & posix.POLL.IN) == 0) continue;
+ const n = posix.read(self.master, &buf) catch break;
+ if (n == 0) break;
+ self.recordRaw(buf[0..n]);
+ self.stream.nextSlice(buf[0..n]);
+ if (std.mem.indexOf(u8, self.raw.items, needle) != null) return true;
+ }
+ return false;
+ }
fn recordRaw(self: *Harness, bytes: []const u8) void {
self.raw.appendSlice(bytes) catch |err| switch (err) {
error.CaptureFull => {},
@@ -338,6 +358,17 @@ pub const Harness = struct {
return error.ExpectFailed;
}
}
+
+ /// Assert a byte sequence appears in the app's raw output, waiting for it.
+ /// A fixed `pump` before `expectRawContains` budgets a STARTUP instead of
+ /// waiting for an answer, and a cold 70 MB Debug binary on a loaded machine
+ /// overruns any such budget.
+ pub fn expectRawWaitFor(self: *Harness, needle: []const u8, ms: i64, msg: []const u8) !void {
+ if (!self.waitForRaw(needle, ms)) {
+ std.debug.print("E2E FAIL: {s}\n(raw output has no {any})\n", .{ msg, needle });
+ return error.ExpectFailed;
+ }
+ }
};
/// Write a file (helper for test setup, raw libc).
diff --git a/test/image_harness.zig b/test/image_harness.zig
index 21ec706e..1141d81f 100644
--- a/test/image_harness.zig
+++ b/test/image_harness.zig
@@ -231,8 +231,11 @@ fn runKitty(arena: std.mem.Allocator, exe: [:0]const u8, base: [:0]const u8) !vo
var h = try eh.Harness.initArgs(gpa, exe, 12, 30, image_path);
defer h.deinit();
- try h.pump(150);
- try h.expectRawContains("\x1b_Gi=1,a=q\x1b\\", "app did not issue the Kitty graphics capability query");
+ try h.expectRawWaitFor(
+ "\x1b_Gi=1,a=q\x1b\\",
+ 5000,
+ "app did not issue the Kitty graphics capability query",
+ );
// APC says graphics is present; DA1 is the last capability response and
// closes the asynchronous handshake. Arrow-up is an ordinary queued event
@@ -278,8 +281,11 @@ fn runKittyPdf(arena: std.mem.Allocator, exe: [:0]const u8, base: [:0]const u8)
var h = try eh.Harness.initArgs(gpa, exe, 16, 40, pdf_path);
defer h.deinit();
- try h.pump(150);
- try h.expectRawContains("\x1b_Gi=1,a=q\x1b\\", "app did not issue the Kitty graphics capability query");
+ try h.expectRawWaitFor(
+ "\x1b_Gi=1,a=q\x1b\\",
+ 5000,
+ "app did not issue the Kitty graphics capability query",
+ );
try h.send("\x1b_Gi=1;OK\x1b\\\x1b[?1;2c\x1b[A");
const transmit = "\x1b_Gf=32,s=96,v=64,i=";
@@ -514,27 +520,24 @@ fn runGui(arena: std.mem.Allocator, exe: [:0]const u8, base: [:0]const u8) !void
var h = try eh.Harness.initArgs(gpa, exe, 10, 20, image_path);
defer h.deinit();
- try h.pump(1200);
-
- const capture = readFile(gpa, capture_path) catch |err| {
- std.debug.print("SDL image harness produced no capture ({t}); raw child output: {s}\n", .{ err, h.raw.items });
- return err;
- };
- defer gpa.free(capture);
- const pixels = ppmPixels(capture) orelse return error.BadCapture;
- var exact: usize = 0;
- var i: usize = 0;
- while (i + 2 < pixels.len) : (i += 3) {
- if (std.mem.eql(u8, pixels[i .. i + 3], &fixture_rgb)) exact += 1;
- }
// The source contributes 512 aligned pixels. Leave ample room for driver
// filtering while still excluding glyph-art fallback and incidental UI
// colors.
- if (exact < 200) {
- std.debug.print("SDL image harness found only {d} native-color pixels in the GPU capture\n", .{exact});
- return error.NativePixelsMissing;
- }
- std.debug.print("native image harness ok: SDL GPU capture ({d} source pixels)\n", .{exact});
+ //
+ // WAIT for the capture rather than budget a fixed startup and read once.
+ // The first frame lands when the GPU device is ready, and on a host whose
+ // only SPIR-V backend is vulkan-on-MoltenVK that is ~0.7s idle and past
+ // 1.9s under load — a 1200ms budget made this arm fail with an unwritten
+ // latest.ppm while the device was still coming up. Same deadline the PDF
+ // arm below already gives its first capture.
+ const bounds = waitForCaptureBounds(&h, capture_path, fixture_rgb, 200, 5000) catch |err| {
+ std.debug.print(
+ "SDL image harness produced no usable capture ({t}); raw child output: {s}\n",
+ .{ err, h.raw.items },
+ );
+ return err;
+ };
+ std.debug.print("native image harness ok: SDL GPU capture ({d} source pixels)\n", .{bounds.count});
}
fn runGuiPdf(arena: std.mem.Allocator, exe: [:0]const u8, base: [:0]const u8) !void {
@@ -681,8 +684,8 @@ fn waitForCaptureBounds(
} else |_| {}
_ = try h.pumpOnce(50);
}
- std.debug.print("SDL PDF harness found only {d} pixels of color {any}\n", .{ best, color });
- return error.PdfPageColorMissing;
+ std.debug.print("SDL harness found only {d} pixels of color {any}\n", .{ best, color });
+ return error.CaptureColorMissing;
}
fn expectThemeGap(
diff --git a/test/macos-snapshots/boot.golden b/test/macos-snapshots/boot.golden
index f442a92a..f79a8e2a 100644
--- a/test/macos-snapshots/boot.golden
+++ b/test/macos-snapshots/boot.golden
@@ -1,6 +1,6 @@
== snap boot grid=80x24 cursor=4,2
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-|$ /private/tmp/pardes-macos-e2e/boot/cwd New Del Filter
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|$ /private/tmp/pardes-macos-e2e/boot/cwd Save New Newtty Del Filter
| $
|
|
@@ -25,8 +25,8 @@
|
== draw boot 680x396 nonblank
== snap resized grid=100x30 cursor=4,2
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-|$ /private/tmp/pardes-macos-e2e/boot/cwd New Del Filter
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|$ /private/tmp/pardes-macos-e2e/boot/cwd Save New Newtty Del Filter
| $
|
|
diff --git a/test/macos-snapshots/cwd.golden b/test/macos-snapshots/cwd.golden
index 68624146..022550d2 100644
--- a/test/macos-snapshots/cwd.golden
+++ b/test/macos-snapshots/cwd.golden
@@ -1,6 +1,6 @@
== snap spawned grid=100x24 cursor=4,2
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-|$ /private/tmp/pardes-macos-e2e/cwd/cwd New Del Filter
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|$ /private/tmp/pardes-macos-e2e/cwd/cwd Save New Newtty Del Filter
| $
|
|
@@ -24,8 +24,8 @@
|
|
== snap moved grid=100x24 cursor=4,3
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-|$ /private/tmp New Del Filter
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|$ /private/tmp Save New Newtty Del Filter
| $ cd /tmp
| $
|
@@ -49,8 +49,8 @@
|
|
== snap moved-again grid=100x24 cursor=4,4
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-|$ / New Del Filter
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|$ / Save New Newtty Del Filter
| $ cd /tmp
| $ cd /
| $
@@ -74,8 +74,8 @@
|
|
== snap idle grid=100x24 cursor=4,4
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-|$ / New Del Filter
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|$ / Save New Newtty Del Filter
| $ cd /tmp
| $ cd /
| $
diff --git a/test/macos-snapshots/drop.golden b/test/macos-snapshots/drop.golden
index 4d2ae400..01247ed3 100644
--- a/test/macos-snapshots/drop.golden
+++ b/test/macos-snapshots/drop.golden
@@ -1,6 +1,6 @@
== snap booted grid=100x30 cursor=4,3
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-|$ /private/tmp/pardes-macos-e2e/drop/cwd New Del Filter
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|$ /private/tmp/pardes-macos-e2e/drop/cwd Save New Newtty Del Filter
| $ printf 'first file\n' > one.txt; printf 'second file\n' > two.txt
| $
|
@@ -30,15 +30,10 @@
|
|
== snap dropped_on_shell grid=100x30 cursor=7,2
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/drop/cwd/one.txt S$ /private/tmp/pardes-macos-e2e/drop/cwd New Del
-| 1 first file $ printf 'first file\n' > one.txt; printf 'secon
-| 2 d file\n' > two.txt
-| $
-|
-|
-|
-|
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/drop/cwd/one.txt Save New Newtty Del
+| 1 first file
+| 2
|
|
|
@@ -50,6 +45,9 @@
|
|
|
+|$ /private/tmp/pardes-macos-e2e/drop/cwd Save New Newtty Del Filter
+| $ printf 'first file\n' > one.txt; printf 'second file\n' > two.txt
+| $
|
|
|
@@ -60,26 +58,28 @@
|
|
|
-== snap dropped_on_document grid=100x30 cursor=7,17
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/drop/cwd/one.txt S$ /private/tmp/pardes-macos-e2e/drop/cwd New Del
-| 1 first file $ printf 'first file\n' > one.txt; printf 'secon
-| 2 d file\n' > two.txt
-| $
|
|
+== snap dropped_on_document grid=100x30 cursor=7,9
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/drop/cwd/one.txt Save New Newtty Del
+| 1 first file
+| 2
|
|
|
|
+| /private/tmp/pardes-macos-e2e/drop/cwd/two.txt Save New Newtty Del
+| 1 second file
+| 2
|
|
|
|
+|$ /private/tmp/pardes-macos-e2e/drop/cwd Save New Newtty Del Filter
+| $ printf 'first file\n' > one.txt; printf 'second file\n' > two.txt
+| $
|
-| /private/tmp/pardes-macos-e2e/drop/cwd/two.txt S
-| 1 second file
-| 2
|
|
|
diff --git a/test/macos-snapshots/drop.snap b/test/macos-snapshots/drop.snap
index f427fe2a..78ca94e5 100644
--- a/test/macos-snapshots/drop.snap
+++ b/test/macos-snapshots/drop.snap
@@ -31,7 +31,11 @@ snap dropped_on_shell
# ...and now the placement is the assertion. Dropping the SECOND file inside
# the pane the first one opened puts it next to that pane, not next to the
# shell — which is only true because the click went where the pointer was.
-drop /private/tmp/pardes-macos-e2e/drop/cwd/two.txt 10 20
+# Row 5, not row 20: since c3d0b84 a document only claims a COLUMN when both
+# halves would still be 100 cells wide, so on this 100-cell grid one.txt
+# stacks ABOVE the shell instead of beside it, and row 20 is now the shell.
+# The coordinate has to stay inside the pane the comment names.
+drop /private/tmp/pardes-macos-e2e/drop/cwd/two.txt 10 5
stable 700 15000
snap dropped_on_document
draw drop
diff --git a/test/macos-snapshots/font.golden b/test/macos-snapshots/font.golden
index 7eac1565..2bb87be4 100644
--- a/test/macos-snapshots/font.golden
+++ b/test/macos-snapshots/font.golden
@@ -1,6 +1,6 @@
== snap boot grid=100x24 cursor=4,2
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-|$ /private/tmp/pardes-macos-e2e/font/cwd New Del Filter
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|$ /private/tmp/pardes-macos-e2e/font/cwd Save New Newtty Del Filter
| $
|
|
@@ -24,8 +24,8 @@
|
|
== snap menlo grid=100x24 cursor=4,2
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-|$ /private/tmp/pardes-macos-e2e/font/cwd New Del Filter
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|$ /private/tmp/pardes-macos-e2e/font/cwd Save New Newtty Del Filter
| $
|
|
@@ -49,8 +49,8 @@
|
|
== snap unchanged grid=100x24 cursor=4,2
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-|$ /private/tmp/pardes-macos-e2e/font/cwd New Del Filter
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|$ /private/tmp/pardes-macos-e2e/font/cwd Save New Newtty Del Filter
| $
|
|
@@ -74,8 +74,8 @@
|
|
== snap bigger grid=77x18 cursor=4,2
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-|$ /private/tmp/pardes-macos-e2e/font/cwd New Del Filter
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|$ /private/tmp/pardes-macos-e2e/font/cwd Save New Newtty Del Filter
| $
|
|
@@ -93,8 +93,8 @@
|
|
== snap reset grid=100x24 cursor=4,2
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-|$ /private/tmp/pardes-macos-e2e/font/cwd New Del Filter
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|$ /private/tmp/pardes-macos-e2e/font/cwd Save New Newtty Del Filter
| $
|
|
@@ -118,8 +118,8 @@
|
|
== snap floor grid=242x56 cursor=4,2
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-|$ /private/tmp/pardes-macos-e2e/font/cwd New Del Filter
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|$ /private/tmp/pardes-macos-e2e/font/cwd Save New Newtty Del Filter
| $
|
|
diff --git a/test/macos-snapshots/keys.golden b/test/macos-snapshots/keys.golden
index ddc7c3e5..89733a4d 100644
--- a/test/macos-snapshots/keys.golden
+++ b/test/macos-snapshots/keys.golden
@@ -1,6 +1,6 @@
== snap typed grid=80x24 cursor=16,2
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-|$ /private/tmp/pardes-macos-e2e/keys/cwd New Del Filter
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|$ /private/tmp/pardes-macos-e2e/keys/cwd Save New Newtty Del Filter
| $ echo al''pha
|
|
@@ -24,8 +24,8 @@
|
|
== snap ran grid=80x24 cursor=4,4
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-|$ /private/tmp/pardes-macos-e2e/keys/cwd New Del Filter
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|$ /private/tmp/pardes-macos-e2e/keys/cwd Save New Newtty Del Filter
| $ echo al''pha
| alpha
| $
@@ -49,8 +49,8 @@
|
|
== snap fixed grid=80x24 cursor=16,4
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-|$ /private/tmp/pardes-macos-e2e/keys/cwd New Del Filter
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|$ /private/tmp/pardes-macos-e2e/keys/cwd Save New Newtty Del Filter
| $ echo al''pha
| alpha
| $ echo bra''vo
@@ -74,8 +74,8 @@
|
|
== snap second grid=80x24 cursor=4,6
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-|$ /private/tmp/pardes-macos-e2e/keys/cwd New Del Filter
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|$ /private/tmp/pardes-macos-e2e/keys/cwd Save New Newtty Del Filter
| $ echo al''pha
| alpha
| $ echo bra''vo
@@ -99,11 +99,11 @@
|
|
== snap normal grid=80x24 cursor=4,6
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/keys/cwd New Del Filter
-|
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/keys/cwd Save New Newtty Del Filter
+| echo al''pha
| alpha
-|
+| echo bra''vo
| bravo
|
|
@@ -124,11 +124,11 @@
|
|
== snap moved grid=80x24 cursor=7,3
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/keys/cwd New Del Filter
-|
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/keys/cwd Save New Newtty Del Filter
+| echo al''pha
| alpha
-|
+| echo bra''vo
| bravo
|
|
@@ -149,11 +149,11 @@
|
|
== snap home grid=80x24 cursor=2,3
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/keys/cwd New Del Filter
-|
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/keys/cwd Save New Newtty Del Filter
+| echo al''pha
| alpha
-|
+| echo bra''vo
| bravo
|
|
@@ -174,11 +174,11 @@
|
|
== snap end grid=80x24 cursor=6,3
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/keys/cwd New Del Filter
-|
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/keys/cwd Save New Newtty Del Filter
+| echo al''pha
| alpha
-|
+| echo bra''vo
| bravo
|
|
@@ -199,11 +199,11 @@
|
|
== snap pagedown grid=80x24 cursor=2,5
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/keys/cwd New Del Filter
-|
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/keys/cwd Save New Newtty Del Filter
+| echo al''pha
| alpha
-|
+| echo bra''vo
| bravo
|
|
@@ -224,11 +224,11 @@
|
|
== snap pageup grid=80x24 cursor=2,5
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/keys/cwd New Del Filter
-|
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/keys/cwd Save New Newtty Del Filter
+| echo al''pha
| alpha
-|
+| echo bra''vo
| bravo
|
|
@@ -249,11 +249,11 @@
|
|
== snap deleted grid=80x24 cursor=2,5
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/keys/cwd New Del Filter
-|
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/keys/cwd Save New Newtty Del Filter
+| echo al''pha
| alpha
-|
+| echo bra''vo
| bravo
|
|
@@ -274,11 +274,11 @@
|
|
== snap escaped grid=80x24 cursor=2,5
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/keys/cwd New Del Filter
-|
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/keys/cwd Save New Newtty Del Filter
+| echo al''pha
| alpha
-|
+| echo bra''vo
| bravo
|
|
@@ -299,13 +299,13 @@
|
|
== snap tabbed grid=80x24 cursor=2,5
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/keys/cwd New Del Filter
-|
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/keys/cwd Save New Newtty Del Filter
+| echo al''pha
| alpha
-|
+| echo bra''vo
+| bravo
| bravo
-|
| bash: bravo: command not found
|
|
diff --git a/test/macos-snapshots/rotate.golden b/test/macos-snapshots/rotate.golden
index c2ffa052..3254a7fc 100644
--- a/test/macos-snapshots/rotate.golden
+++ b/test/macos-snapshots/rotate.golden
@@ -1,39 +1,39 @@
-== snap results grid=100x30 cursor=4,25
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/rotate/cwd New Del Filter
-| zz
-| x MARK 14
+== snap results grid=100x30 cursor=7,4
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/rotate/cwd Save New Newtty Del Filter
+| printf 'x MA''RK %s\nzz\n' 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
+| 24
+| x MARK 01
| zz
-| x MARK 15
+| x MARK 02
| zz
-| x MARK 16
+| x MARK 03
| zz
-| x MARK 17
+| x MARK 04
| zz
-| x MARK 18
+| x MARK 05
| zz
-| x MARK 19
+| x MARK 06
| zz
-| x MARK 20
+| x MARK 07
| zz
-| x MARK 21
+| x MARK 08
| zz
-| x MARK 22
+| x MARK 09
| zz
-| x MARK 23
+| x MARK 10
| zz
-| x MARK 24
+| x MARK 11
| zz
-|
-| /private/tmp/pardes-macos-e2e/rotate/cwd/+Search New Del
+| /private/tmp/pardes-macos-e2e/rotate/cwd/+Search Save New Newtty Del
| 1 @p0:3:3-6 x MARK 01
| 2 @p0:5:3-6 x MARK 02
| 3 @p0:7:3-6 x MARK 03
-== snap forward grid=100x30 cursor=7,4
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/rotate/cwd New Del Filter
-|
-|
+== snap forward grid=100x30 cursor=7,28
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/rotate/cwd Save New Newtty Del Filter
+| printf 'x MA''RK %s\nzz\n' 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
+| 24
| x MARK 01
| zz
| x MARK 02
@@ -56,15 +56,15 @@
| zz
| x MARK 11
| zz
-| /private/tmp/pardes-macos-e2e/rotate/cwd/+Search New Del
+| /private/tmp/pardes-macos-e2e/rotate/cwd/+Search Save New Newtty Del
| 1 @p0:3:3-6 x MARK 01
| 2 @p0:5:3-6 x MARK 02
| 3 @p0:7:3-6 x MARK 03
-== snap forward2 grid=100x30 cursor=7,6
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/rotate/cwd New Del Filter
-|
-|
+== snap forward2 grid=100x30 cursor=7,28
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/rotate/cwd Save New Newtty Del Filter
+| printf 'x MA''RK %s\nzz\n' 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
+| 24
| x MARK 01
| zz
| x MARK 02
@@ -87,15 +87,15 @@
| zz
| x MARK 11
| zz
-| /private/tmp/pardes-macos-e2e/rotate/cwd/+Search New Del
-| 1 @p0:3:3-6 x MARK 01
+| /private/tmp/pardes-macos-e2e/rotate/cwd/+Search Save New Newtty Del
| 2 @p0:5:3-6 x MARK 02
| 3 @p0:7:3-6 x MARK 03
-== snap back grid=100x30 cursor=7,6
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/rotate/cwd New Del Filter
-|
-|
+| 4 @p0:9:3-6 x MARK 04
+== snap back grid=100x30 cursor=7,28
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/rotate/cwd Save New Newtty Del Filter
+| printf 'x MA''RK %s\nzz\n' 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
+| 24
| x MARK 01
| zz
| x MARK 02
@@ -118,15 +118,15 @@
| zz
| x MARK 11
| zz
-| /private/tmp/pardes-macos-e2e/rotate/cwd/+Search New Del
-| 1 @p0:3:3-6 x MARK 01
+| /private/tmp/pardes-macos-e2e/rotate/cwd/+Search Save New Newtty Del
| 2 @p0:5:3-6 x MARK 02
| 3 @p0:7:3-6 x MARK 03
-== snap forward_by_key grid=100x30 cursor=7,8
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/rotate/cwd New Del Filter
-|
-|
+| 4 @p0:9:3-6 x MARK 04
+== snap forward_by_key grid=100x30 cursor=7,28
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/rotate/cwd Save New Newtty Del Filter
+| printf 'x MA''RK %s\nzz\n' 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
+| 24
| x MARK 01
| zz
| x MARK 02
@@ -149,15 +149,15 @@
| zz
| x MARK 11
| zz
-| /private/tmp/pardes-macos-e2e/rotate/cwd/+Search New Del
-| 1 @p0:3:3-6 x MARK 01
-| 2 @p0:5:3-6 x MARK 02
+| /private/tmp/pardes-macos-e2e/rotate/cwd/+Search Save New Newtty Del
| 3 @p0:7:3-6 x MARK 03
-== snap placed grid=100x30 cursor=7,8
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/rotate/cwd New Del Filter
-|
-|
+| 4 @p0:9:3-6 x MARK 04
+| 5 @p0:11:3-6 x MARK 05
+== snap placed grid=100x30 cursor=7,28
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/rotate/cwd Save New Newtty Del Filter
+| printf 'x MA''RK %s\nzz\n' 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
+| 24
| x MARK 01
| zz
| x MARK 02
@@ -180,15 +180,15 @@
| zz
| x MARK 11
| zz
-| /private/tmp/pardes-macos-e2e/rotate/cwd/+Search New Del
-| 1 @p0:3:3-6 x MARK 01
-| 2 @p0:5:3-6 x MARK 02
+| /private/tmp/pardes-macos-e2e/rotate/cwd/+Search Save New Newtty Del
| 3 @p0:7:3-6 x MARK 03
-== snap placed_released grid=100x30 cursor=7,8
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/rotate/cwd New Del Filter
-|
-|
+| 4 @p0:9:3-6 x MARK 04
+| 5 @p0:11:3-6 x MARK 05
+== snap placed_released grid=100x30 cursor=7,28
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/rotate/cwd Save New Newtty Del Filter
+| printf 'x MA''RK %s\nzz\n' 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
+| 24
| x MARK 01
| zz
| x MARK 02
@@ -211,15 +211,15 @@
| zz
| x MARK 11
| zz
-| /private/tmp/pardes-macos-e2e/rotate/cwd/+Search New Del
-| 1 @p0:3:3-6 x MARK 01
-| 2 @p0:5:3-6 x MARK 02
+| /private/tmp/pardes-macos-e2e/rotate/cwd/+Search Save New Newtty Del
| 3 @p0:7:3-6 x MARK 03
-== snap thrown grid=100x30 cursor=7,16
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/rotate/cwd New Del Filter
-|
-|
+| 4 @p0:9:3-6 x MARK 04
+| 5 @p0:11:3-6 x MARK 05
+== snap thrown grid=100x30 cursor=7,28
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/rotate/cwd Save New Newtty Del Filter
+| printf 'x MA''RK %s\nzz\n' 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
+| 24
| x MARK 01
| zz
| x MARK 02
@@ -242,39 +242,39 @@
| zz
| x MARK 11
| zz
-| /private/tmp/pardes-macos-e2e/rotate/cwd/+Search New Del
-| 5 @p0:11:3-6 x MARK 05
-| 6 @p0:13:3-6 x MARK 06
+| /private/tmp/pardes-macos-e2e/rotate/cwd/+Search Save New Newtty Del
| 7 @p0:15:3-6 x MARK 07
-== snap thrown_coasted grid=100x30 cursor=7,22
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/rotate/cwd New Del Filter
-| x MARK 07
-| zz
-| x MARK 08
+| 8 @p0:17:3-6 x MARK 08
+| 9 @p0:19:3-6 x MARK 09
+== snap thrown_coasted grid=100x30 cursor=7,28
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/rotate/cwd Save New Newtty Del Filter
+| printf 'x MA''RK %s\nzz\n' 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
+| 24
+| x MARK 01
| zz
-| x MARK 09
+| x MARK 02
| zz
-| x MARK 10
+| x MARK 03
| zz
-| x MARK 11
+| x MARK 04
| zz
-| x MARK 12
+| x MARK 05
| zz
-| x MARK 13
+| x MARK 06
| zz
-| x MARK 14
+| x MARK 07
| zz
-| x MARK 15
+| x MARK 08
| zz
-| x MARK 16
+| x MARK 09
| zz
-| x MARK 17
+| x MARK 10
| zz
-| x MARK 18
+| x MARK 11
| zz
-| /private/tmp/pardes-macos-e2e/rotate/cwd/+Search New Del
-| 15 @p0:31:3-6 x MARK 15
-| 16 @p0:33:3-6 x MARK 16
+| /private/tmp/pardes-macos-e2e/rotate/cwd/+Search Save New Newtty Del
| 17 @p0:35:3-6 x MARK 17
+| 18 @p0:37:3-6 x MARK 18
+| 19 @p0:39:3-6 x MARK 19
== draw rotate 850x495 nonblank
diff --git a/test/macos-snapshots/trackpad.golden b/test/macos-snapshots/trackpad.golden
index f1356df0..631e5af9 100644
--- a/test/macos-snapshots/trackpad.golden
+++ b/test/macos-snapshots/trackpad.golden
@@ -1,7 +1,7 @@
== snap ready grid=100x30 cursor=4,8
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/trackpad/cwd New Del Filter
-|
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/trackpad/cwd Save New Newtty Del Filter
+| printf 'x MA''RK a\nzz\nx MA''RK b\nzz\nx MA''RK c\n'
| x MARK a
| zz
| x MARK b
@@ -30,9 +30,9 @@
|
|
== snap adapter grid=100x30 cursor=7,5
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/trackpad/cwd New Del Filter
-|
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/trackpad/cwd Save New Newtty Del Filter
+| printf 'x MA''RK a\nzz\nx MA''RK b\nzz\nx MA''RK c\n'
| x MARK a
| zz
| x MARK b
@@ -56,14 +56,14 @@
|
|
|
-| /private/tmp/pardes-macos-e2e/trackpad/cwd/+Search New Del
+| /private/tmp/pardes-macos-e2e/trackpad/cwd/+Search Save New Newtty Del
| 1 @p0:2:3-6 x MARK a
| 2 @p0:4:3-6 x MARK b
| 3 @p0:6:3-6 x MARK c
== snap look grid=100x30 cursor=7,5
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/trackpad/cwd New Del Filter
-|
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/trackpad/cwd Save New Newtty Del Filter
+| printf 'x MA''RK a\nzz\nx MA''RK b\nzz\nx MA''RK c\n'
| x MARK a
| zz
| x MARK b
@@ -87,14 +87,14 @@
|
|
|
-| /private/tmp/pardes-macos-e2e/trackpad/cwd/+Search New Del
+| /private/tmp/pardes-macos-e2e/trackpad/cwd/+Search Save New Newtty Del
| 1 @p0:2:3-6 x MARK a
| 2 @p0:4:3-6 x MARK b
| 3 @p0:6:3-6 x MARK c
== snap dragged grid=100x30 cursor=9,3
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/trackpad/cwd New Del Filter
-|
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/trackpad/cwd Save New Newtty Del Filter
+| printf 'x MA''RK a\nzz\nx MA''RK b\nzz\nx MA''RK c\n'
| x MARK a
| zz
| x MARK b
@@ -118,14 +118,14 @@
|
|
|
-| /private/tmp/pardes-macos-e2e/trackpad/cwd/+Search New Del
+| /private/tmp/pardes-macos-e2e/trackpad/cwd/+Search Save New Newtty Del
| 1 @p0:2:3-6 x MARK a
| 2 @p0:4:3-6 x MARK b
| 3 @p0:6:3-6 x MARK c
== snap hover grid=100x30 cursor=9,3
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/trackpad/cwd New Del Filter
-|
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/trackpad/cwd Save New Newtty Del Filter
+| printf 'x MA''RK a\nzz\nx MA''RK b\nzz\nx MA''RK c\n'
| x MARK a
| zz
| x MARK b
@@ -149,14 +149,14 @@
|
|
|
-| /private/tmp/pardes-macos-e2e/trackpad/cwd/+Search New Del
+| /private/tmp/pardes-macos-e2e/trackpad/cwd/+Search Save New Newtty Del
| 1 @p0:2:3-6 x MARK a
| 2 @p0:4:3-6 x MARK b
| 3 @p0:6:3-6 x MARK c
== snap scrolled grid=100x30 cursor=9,3
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/trackpad/cwd New Del Filter
-|
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/trackpad/cwd Save New Newtty Del Filter
+| printf 'x MA''RK a\nzz\nx MA''RK b\nzz\nx MA''RK c\n'
| x MARK a
| zz
| x MARK b
@@ -180,14 +180,14 @@
|
|
|
-| /private/tmp/pardes-macos-e2e/trackpad/cwd/+Search New Del
+| /private/tmp/pardes-macos-e2e/trackpad/cwd/+Search Save New Newtty Del
| 1 @p0:2:3-6 x MARK a
| 2 @p0:4:3-6 x MARK b
| 3 @p0:6:3-6 x MARK c
== snap notched grid=100x30 cursor=9,3
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/trackpad/cwd New Del Filter
-|
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/trackpad/cwd Save New Newtty Del Filter
+| printf 'x MA''RK a\nzz\nx MA''RK b\nzz\nx MA''RK c\n'
| x MARK a
| zz
| x MARK b
@@ -211,21 +211,21 @@
|
|
|
-| /private/tmp/pardes-macos-e2e/trackpad/cwd/+Search New Del
+| /private/tmp/pardes-macos-e2e/trackpad/cwd/+Search Save New Newtty Del
| 1 @p0:2:3-6 x MARK a
| 2 @p0:4:3-6 x MARK b
| 3 @p0:6:3-6 x MARK c
== snap exec grid=100x30 cursor=7,10
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/trackpad/cwd New Del Filter
-|
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/trackpad/cwd Save New Newtty Del Filter
+| printf 'x MA''RK a\nzz\nx MA''RK b\nzz\nx MA''RK c\n'
| x MARK a
| zz
| x MARK b
| zz
| x MARK c
|
-| /tmp/pardes-macos-e2e/trackpad/tmp/pardes-XXXXXX Save New Del
+| /private/tmp/pardes-macos-e2e/trackpad/cwd/+New Save New Newtty Del
| 1
|
|
@@ -242,21 +242,21 @@
|
|
|
-| /private/tmp/pardes-macos-e2e/trackpad/cwd/+Search New Del
+| /private/tmp/pardes-macos-e2e/trackpad/cwd/+Search Save New Newtty Del
| 1 @p0:2:3-6 x MARK a
| 2 @p0:4:3-6 x MARK b
| 3 @p0:6:3-6 x MARK c
-== snap force grid=100x30 cursor=54,3
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/trackpad/cwd New D /private/tmp/pardes-macos-e2e/trackpad/cwd New D
-|
+== snap force grid=100x30 cursor=57,2
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/trackpad/cwd Save /private/tmp/pardes-macos-e2e/trackpad/cwd/+New
+| RK c\n' 1
| x MARK a
| zz
| x MARK b
| zz
| x MARK c
|
-| /tmp/pardes-macos-e2e/trackpad/tmp/pardes-XXXXXX
+| /private/tmp/pardes-macos-e2e/trackpad/cwd/+New
| 1
|
|
@@ -278,16 +278,16 @@
| 2 @p0:4:3-6 x MARK b
| 3 @p0:6:3-6 x MARK c
== snap select grid=100x30 cursor=4,3
-|New Newcol Find Grep Help Tutor Dump NextColor Debug Kill
-| /private/tmp/pardes-macos-e2e/trackpad/cwd New D /private/tmp/pardes-macos-e2e/trackpad/cwd New D
-|
+|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /private/tmp/pardes-macos-e2e/trackpad/cwd Save /private/tmp/pardes-macos-e2e/trackpad/cwd/+New
+| RK c\n' 1
| x MARK a
| zz
| x MARK b
| zz
| x MARK c
|
-| /tmp/pardes-macos-e2e/trackpad/tmp/pardes-XXXXXX
+| /private/tmp/pardes-macos-e2e/trackpad/cwd/+New
| 1
|
|
diff --git a/test/macos_e2e.swift b/test/macos_e2e.swift
index c076aebb..800e2d43 100644
--- a/test/macos_e2e.swift
+++ b/test/macos_e2e.swift
@@ -95,6 +95,8 @@ private final class Driver: PardesViewDelegate {
private var observer: NSObjectProtocol?
private var output = ""
private var nextAnimationFrame: Date?
+ /// Where present() puts the pixels nobody reads.
+ private var presentationRep: NSBitmapImageRep?
/// The script's own file name, for error messages.
private let scriptName: String
@@ -219,6 +221,7 @@ private final class Driver: PardesViewDelegate {
window?.contentView = nil
window = nil
view = nil
+ presentationRep = nil
host.clipboard = nil
host.woke = false
}
@@ -336,6 +339,10 @@ private final class Driver: PardesViewDelegate {
private func readFrame() -> Frame {
let count = pardes_frame()
+ // The core has produced a frame; presenting it is this harness's half of
+ // the contract, and it has to happen AFTER the render rather than before
+ // — see present().
+ defer { present() }
let cols = Int(pardes_frame_cols())
let rows = Int(pardes_frame_rows())
// -1 means hidden. Clamped to 0 rather than printed, which is what
@@ -396,6 +403,28 @@ private final class Driver: PardesViewDelegate {
options: .regularExpression)
}
+ /// Put the frame readFrame() just produced on screen — for a window that has
+ /// no screen, into a bitmap. draw(_:) is the only caller of
+ /// pardes_frame_presented, and this window is deliberately never ordered
+ /// front, so without this nothing here would ever present anything: the core
+ /// would owe a presentation for the rest of the script and correctly hold
+ /// every pointer gesture after the first layout change inert, addressing
+ /// pixels no backend had shown. The app pays the same debt on every pump
+ /// (AppDelegate.pump marks the view, AppKit's display cycle draws it).
+ ///
+ /// The rep is kept and reused rather than allocated per frame: this runs on
+ /// every poll slice, and cacheDisplay only needs somewhere to put pixels
+ /// nobody reads. `draw` makes its own, because it reads them.
+ private func present() {
+ guard let view, view.bounds.width >= 1, view.bounds.height >= 1 else { return }
+ let bounds = view.bounds
+ if presentationRep?.size != bounds.size {
+ presentationRep = view.bitmapImageRepForCachingDisplay(in: bounds)
+ }
+ guard let rep = presentationRep else { return }
+ view.cacheDisplay(in: bounds, to: rep)
+ }
+
/// Render the view the way AppKit would and prove the CoreText pass put
/// something on the screen. `snap` reads the core's cell buffer and would be
/// perfectly happy with a draw(_:) that returned on its first line; this is
diff --git a/test/web-snapshots/source-list.golden b/test/web-snapshots/source-list.golden
index 56f2aa69..12af692c 100644
--- a/test/web-snapshots/source-list.golden
+++ b/test/web-snapshots/source-list.golden
@@ -82,18 +82,18 @@
| 3 const mupdf_build = @import("mupdf.zig");
| 4 const snap_build = @import("build/snap.zig");
| 5 const grammar_manifest = @import("src/grammar_manifest.zig");
-| 6
-| 7 pub const Platform = enum { tty, gui, web, macos };
-| 8
-| 9 /// The oldest macOS pardes.app claims to run on, spelled ONCE. Three things
-| 10 /// have to agree about it or the bundle is a lie: the target this build gives
-| 11 /// the static library, the `-target` the app's swiftc link is given (which is
-| 12 /// what writes LC_BUILD_VERSION, the thing dyld actually enforces), and the
-| 13 /// plist's LSMinimumSystemVersion. The macos branch below derives the last two
-| 14 /// from this, so there is one string and no drift.
-| 15 pub const macos_min_version: std.SemanticVersion = .{ .major = 13, .minor = 0, .patch = 0 };
-| 16
-| 17 /// The ZLS the language backend links, spelled once. It names the commit
+| 6 /// The package manifest, imported UNTYPED on purpose — see the `version`
+| 7 /// option in `shellOptions` for why that word is load-bearing.
+| 8 const zon = @import("build.zig.zon");
+| 9
+| 10 /// `esp32p4` is not a shell in this package at all: it is one freestanding
+| 11 /// OBJECT, compiled for riscv32-freestanding, which the `zig_p4` firmware
+| 12 /// package links beside its own `_start`. See the esp32p4 branch below.
+| 13 pub const Platform = enum { tty, gui, web, macos, esp32p4 };
+| 14
+| 15 /// The oldest macOS pardes.app claims to run on, spelled ONCE. Three things
+| 16 /// have to agree about it or the bundle is a lie: the target this build gives
+| 17 /// the static library, the `-target` the app's swiftc link is given (which is
| /home/goblin/00-projects/0x4200.cafe/02-pardes-code Save New Newtty Del Filter
| git ls-files --cached --others --exclude-standard -- '*.zig' | sort
| build.zig
@@ -120,36 +120,36 @@
|4: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-26 #bdbdbd,#080808, 27-33 #cf87e8,#080808,b 34-34 #bdbdbd,#080808, 35-45 #e3c78a,#080808, 46-47 #bdbdbd,#080808, 48-119 d,#080808,
|5: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-25 #bdbdbd,#080808, 26-32 #cf87e8,#080808,b 33-33 #bdbdbd,#080808, 34-49 #e3c78a,#080808, 50-51 #bdbdbd,#080808, 52-119 d,#080808,
|6: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-31 #bdbdbd,#080808, 32-38 #cf87e8,#080808,b 39-39 #bdbdbd,#080808, 40-65 #e3c78a,#080808, 66-67 #bdbdbd,#080808, 68-119 d,#080808,
-|7: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|8: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-27 #bdbdbd,#080808, 28-31 #cf87e8,#080808,b 32-57 #bdbdbd,#080808, 58-119 d,#080808,
-|9: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|10: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-82 #ffffff,#080808,b 83-119 d,#080808,
-|11: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-84 #ffffff,#080808,b 85-119 d,#080808,
-|12: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-84 #ffffff,#080808,b 85-119 d,#080808,
-|13: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-82 #ffffff,#080808,b 83-119 d,#080808,
-|14: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-85 #ffffff,#080808,b 86-119 d,#080808,
-|15: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-57 #ffffff,#080808,b 58-119 d,#080808,
-|16: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-69 #bdbdbd,#080808, 70-71 #e3c78a,#080808, 72-82 #bdbdbd,#080808, 83-83 #e3c78a,#080808, 84-94 #bdbdbd,#080808, 95-95 #e3c78a,#080808, 96-98 #bdbdbd,#080808, 99-119 d,#080808,
-|17: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|18: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-79 #ffffff,#080808,b 80-119 d,#080808,
+|7: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-79 #ffffff,#080808,b 80-119 d,#080808,
+|8: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-69 #ffffff,#080808,b 70-119 d,#080808,
+|9: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-18 #bdbdbd,#080808, 19-25 #cf87e8,#080808,b 26-26 #bdbdbd,#080808, 27-41 #e3c78a,#080808, 42-43 #bdbdbd,#080808, 44-119 d,#080808,
+|10: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
+|11: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-81 #ffffff,#080808,b 82-119 d,#080808,
+|12: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-80 #ffffff,#080808,b 81-119 d,#080808,
+|13: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-78 #ffffff,#080808,b 79-119 d,#080808,
+|14: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-27 #bdbdbd,#080808, 28-31 #cf87e8,#080808,b 32-66 #bdbdbd,#080808, 67-119 d,#080808,
+|15: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
+|16: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-82 #ffffff,#080808,b 83-119 d,#080808,
+|17: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-84 #ffffff,#080808,b 85-119 d,#080808,
+|18: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-84 #ffffff,#080808,b 85-119 d,#080808,
|19: 0-1 #ffffff,#262626, 2-99 #949494,#121212, 100-119 d,#121212,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-68 #bdbdbd,#080808, 69-119 d,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-10 #bdbdbd,#080808, 11-119 d,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-15 #bdbdbd,#080808, 16-119 d,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-10 #bdbdbd,#080808, 11-119 d,#080808,
-|24: 0-0 d,#121212, 1-1 d,#080808, 2-19 #bdbdbd,#080808, 20-119 d,#080808,
-|25: 0-0 d,#121212, 1-1 d,#080808, 2-18 #bdbdbd,#080808, 19-119 d,#080808,
-|26: 0-0 d,#121212, 1-1 d,#080808, 2-17 #bdbdbd,#080808, 18-119 d,#080808,
-|27: 0-0 d,#121212, 1-1 d,#080808, 2-15 #bdbdbd,#080808, 16-119 d,#080808,
-|28: 0-0 d,#121212, 1-1 d,#080808, 2-13 #bdbdbd,#080808, 14-119 d,#080808,
-|29: 0-0 d,#121212, 1-1 d,#080808, 2-23 #bdbdbd,#080808, 24-119 d,#080808,
-|30: 0-0 d,#121212, 1-1 d,#080808, 2-18 #bdbdbd,#080808, 19-119 d,#080808,
-|31: 0-0 d,#121212, 1-1 d,#080808, 2-14 #bdbdbd,#080808, 15-119 d,#080808,
-|32: 0-0 d,#121212, 1-1 d,#080808, 2-25 #bdbdbd,#080808, 26-119 d,#080808,
-|33: 0-0 d,#121212, 1-1 d,#080808, 2-16 #bdbdbd,#080808, 17-119 d,#080808,
-|34: 0-0 d,#121212, 1-1 d,#080808, 2-17 #bdbdbd,#080808, 18-119 d,#080808,
-|35: 0-0 d,#121212, 1-1 d,#080808, 2-16 #bdbdbd,#080808, 17-119 d,#080808,
-|36: 0-0 d,#121212, 1-1 d,#080808, 2-14 #bdbdbd,#080808, 15-119 d,#080808,
+|20: 0-0 d,#444444, 1-1 d,#080808, 2-119 #bdbdbd,#080808,
+|21: 0-0 d,#444444, 1-1 d,#080808, 2-119 #bdbdbd,#080808,
+|22: 0-0 d,#444444, 1-1 d,#080808, 2-119 #bdbdbd,#080808,
+|23: 0-0 d,#444444, 1-1 d,#080808, 2-119 #bdbdbd,#080808,
+|24: 0-0 d,#121212, 1-1 d,#080808, 2-119 #bdbdbd,#080808,
+|25: 0-0 d,#121212, 1-1 d,#080808, 2-119 #bdbdbd,#080808,
+|26: 0-0 d,#121212, 1-1 d,#080808, 2-119 #bdbdbd,#080808,
+|27: 0-0 d,#121212, 1-1 d,#080808, 2-119 #bdbdbd,#080808,
+|28: 0-0 d,#121212, 1-1 d,#080808, 2-119 #bdbdbd,#080808,
+|29: 0-0 d,#121212, 1-1 d,#080808, 2-119 #bdbdbd,#080808,
+|30: 0-0 d,#121212, 1-1 d,#080808, 2-119 #bdbdbd,#080808,
+|31: 0-0 d,#121212, 1-1 d,#080808, 2-119 #bdbdbd,#080808,
+|32: 0-0 d,#121212, 1-1 d,#080808, 2-119 #bdbdbd,#080808,
+|33: 0-0 d,#121212, 1-1 d,#080808, 2-119 #bdbdbd,#080808,
+|34: 0-0 d,#121212, 1-1 d,#080808, 2-119 #bdbdbd,#080808,
+|35: 0-0 d,#121212, 1-1 d,#080808, 2-119 #bdbdbd,#080808,
+|36: 0-0 d,#121212, 1-1 d,#080808, 2-119 #bdbdbd,#080808,
== snap separator-resized grid=120x37 cursor=7,2
|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
| build.zig Save New Newtty Del
@@ -158,18 +158,18 @@
| 3 const mupdf_build = @import("mupdf.zig");
| 4 const snap_build = @import("build/snap.zig");
| 5 const grammar_manifest = @import("src/grammar_manifest.zig");
-| 6
-| 7 pub const Platform = enum { tty, gui, web, macos };
-| 8
-| 9 /// The oldest macOS pardes.app claims to run on, spelled ONCE. Three things
-| 10 /// have to agree about it or the bundle is a lie: the target this build gives
-| 11 /// the static library, the `-target` the app's swiftc link is given (which is
-| 12 /// what writes LC_BUILD_VERSION, the thing dyld actually enforces), and the
-| 13 /// plist's LSMinimumSystemVersion. The macos branch below derives the last two
-| 14 /// from this, so there is one string and no drift.
-| 15 pub const macos_min_version: std.SemanticVersion = .{ .major = 13, .minor = 0, .patch = 0 };
-| 16
-| 17 /// The ZLS the language backend links, spelled once. It names the commit
+| 6 /// The package manifest, imported UNTYPED on purpose — see the `version`
+| 7 /// option in `shellOptions` for why that word is load-bearing.
+| 8 const zon = @import("build.zig.zon");
+| 9
+| 10 /// `esp32p4` is not a shell in this package at all: it is one freestanding
+| 11 /// OBJECT, compiled for riscv32-freestanding, which the `zig_p4` firmware
+| 12 /// package links beside its own `_start`. See the esp32p4 branch below.
+| 13 pub const Platform = enum { tty, gui, web, macos, esp32p4 };
+| 14
+| 15 /// The oldest macOS pardes.app claims to run on, spelled ONCE. Three things
+| 16 /// have to agree about it or the bundle is a lie: the target this build gives
+| 17 /// the static library, the `-target` the app's swiftc link is given (which is
| /home/goblin/00-projects/0x4200.cafe/02-pardes-code Save New Newtty Del Filter
| src/allocators.zig
| src/animation.zig
@@ -196,18 +196,18 @@
| 3 const mupdf_build = @import("mupdf.zig");
| 4 const snap_build = @import("build/snap.zig");
| 5 const grammar_manifest = @import("src/grammar_manifest.zig");
-| 6
-| 7 pub const Platform = enum { tty, gui, web, macos };
-| 8
-| 9 /// The oldest macOS pardes.app claims to run on, spelled ONCE. Three things
-| 10 /// have to agree about it or the bundle is a lie: the target this build gives
-| 11 /// the static library, the `-target` the app's swiftc link is given (which is
-| 12 /// what writes LC_BUILD_VERSION, the thing dyld actually enforces), and the
-| 13 /// plist's LSMinimumSystemVersion. The macos branch below derives the last two
-| 14 /// from this, so there is one string and no drift.
-| 15 pub const macos_min_version: std.SemanticVersion = .{ .major = 13, .minor = 0, .patch = 0 };
-| 16
-| 17 /// The ZLS the language backend links, spelled once. It names the commit
+| 6 /// The package manifest, imported UNTYPED on purpose — see the `version`
+| 7 /// option in `shellOptions` for why that word is load-bearing.
+| 8 const zon = @import("build.zig.zon");
+| 9
+| 10 /// `esp32p4` is not a shell in this package at all: it is one freestanding
+| 11 /// OBJECT, compiled for riscv32-freestanding, which the `zig_p4` firmware
+| 12 /// package links beside its own `_start`. See the esp32p4 branch below.
+| 13 pub const Platform = enum { tty, gui, web, macos, esp32p4 };
+| 14
+| 15 /// The oldest macOS pardes.app claims to run on, spelled ONCE. Three things
+| 16 /// have to agree about it or the bundle is a lie: the target this build gives
+| 17 /// the static library, the `-target` the app's swiftc link is given (which is
| /home/goblin/00-projects/0x4200.cafe/02-pardes-code Save New Newtty Del Filter
| src/fonts.zig
| src/grammar_manifest.zig
diff --git a/test/web_snapshot.mjs b/test/web_snapshot.mjs
index 7b40c174..a1912f15 100644
--- a/test/web_snapshot.mjs
+++ b/test/web_snapshot.mjs
@@ -446,6 +446,12 @@ async function findChrome() {
const found = childProcess.spawnSync("which", [command], { encoding: "utf8" });
if (found.status === 0 && found.stdout.trim()) candidates.push(found.stdout.trim());
}
+ // macOS installs a browser as an application BUNDLE, whose executable is
+ // buried inside it and never on PATH, so the lookup above finds nothing on
+ // a Mac that has Chrome sitting in /Applications.
+ if (process.platform === "darwin")
+ for (const app of ["Google Chrome", "Chromium", "Google Chrome Canary"])
+ candidates.push(`/Applications/${app}.app/Contents/MacOS/${app}`);
const cache = process.env.PLAYWRIGHT_BROWSERS_PATH || path.join(os.homedir(), ".cache", "ms-playwright");
for (const entry of await fsp.readdir(cache).catch(() => [])) {
if (entry.startsWith("chromium-")) {