summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md15
-rw-r--r--docs/config.md68
-rw-r--r--docs/design.typ21
-rw-r--r--docs/helix-keys.md2
-rw-r--r--docs/screenshots/agave-lsp.txt38
-rw-r--r--docs/screenshots/atelier.pngbin0 -> 461005 bytes
-rw-r--r--docs/screenshots/before.pngbin0 -> 369430 bytes
-rw-r--r--docs/screenshots/classic-gallery.json21
-rw-r--r--docs/screenshots/classic-themes.pngbin0 -> 2287763 bytes
-rw-r--r--docs/screenshots/columns-atelier.pngbin0 -> 295421 bytes
-rw-r--r--docs/screenshots/columns-orchard.pngbin0 -> 294658 bytes
-rw-r--r--docs/screenshots/columns-parity.json37
-rw-r--r--docs/screenshots/columns-tag-reveal.pngbin0 -> 296255 bytes
-rw-r--r--docs/screenshots/compact-columns.pngbin0 -> 214695 bytes
-rw-r--r--docs/screenshots/daybreak.pngbin0 -> 455797 bytes
-rw-r--r--docs/screenshots/dusk.pngbin0 -> 459601 bytes
-rw-r--r--docs/screenshots/ink.pngbin0 -> 459899 bytes
-rw-r--r--docs/screenshots/orchard.pngbin0 -> 459125 bytes
-rw-r--r--docs/screenshots/paper.pngbin0 -> 457492 bytes
-rw-r--r--docs/screenshots/parity.json20
-rw-r--r--docs/screenshots/pdf-and-tty-tags.pngbin0 -> 459114 bytes
-rw-r--r--docs/screenshots/pets.pngbin0 -> 24844 bytes
-rw-r--r--docs/screenshots/theme-preferences-forge.pngbin0 -> 229694 bytes
-rw-r--r--docs/screenshots/theme-preferences.pngbin0 -> 3458848 bytes
-rw-r--r--docs/screenshots/theme-selector.pngbin0 -> 253767 bytes
-rw-r--r--docs/tags.md84
-rw-r--r--docs/themes.md124
-rw-r--r--docs/ui-review.md230
-rw-r--r--src/builtins.zig26
-rw-r--r--src/config.zig92
-rw-r--r--src/dump.zig9
-rw-r--r--src/fs.zig51
-rw-r--r--src/gui/gui.zig435
-rw-r--r--src/gui/pet.zig170
-rw-r--r--src/layout.zig327
-rw-r--r--src/macos.zig3
-rw-r--r--src/macos/Sources/AppDelegate.swift5
-rw-r--r--src/macos/Sources/PardesView.swift5
-rw-r--r--src/macos/pardes.h3
-rw-r--r--src/panes.zig158
-rw-r--r--src/pardes.zig1335
-rw-r--r--src/tag_line.zig41
-rw-r--r--src/themes/atelier.zig49
-rw-r--r--src/themes/clay.zig50
-rw-r--r--src/themes/daybreak.zig49
-rw-r--r--src/themes/dusk.zig49
-rw-r--r--src/themes/forge.zig51
-rw-r--r--src/themes/forge_black.zig51
-rw-r--r--src/themes/forge_soft.zig51
-rw-r--r--src/themes/harvest.zig50
-rw-r--r--src/themes/ink.zig49
-rw-r--r--src/themes/lagoon.zig50
-rw-r--r--src/themes/orchard.zig49
-rw-r--r--src/themes/orchard_black.zig49
-rw-r--r--src/themes/paper.zig49
-rw-r--r--src/themes/solarium.zig50
-rw-r--r--src/themes/spectrum.zig50
-rw-r--r--src/tutor.txt14
-rw-r--r--test/appearance_gallery.py213
-rw-r--r--test/collapse_layout.py94
-rw-r--r--test/column_tags.py306
-rw-r--r--test/font_size.py61
-rw-r--r--test/fs.py7
-rw-r--r--test/image_harness.zig49
-rw-r--r--test/look_placement.py143
-rw-r--r--test/macos-snapshots/boot.snap2
-rw-r--r--test/macos-snapshots/keys.snap2
-rw-r--r--test/macos-snapshots/rotate.snap2
-rw-r--r--test/macos-snapshots/trackpad.snap8
-rw-r--r--test/output.zig87
-rw-r--r--test/panes.zig220
-rw-r--r--test/pdf.zig30
-rw-r--r--test/snapshots/argv.golden28
-rw-r--r--test/snapshots/argv.snap14
-rw-r--r--test/snapshots/badutf.golden14
-rw-r--r--test/snapshots/badutf.snap8
-rw-r--r--test/snapshots/boot.golden70
-rw-r--r--test/snapshots/boot.snap4
-rw-r--r--test/snapshots/builtins.golden73
-rw-r--r--test/snapshots/builtins.snap9
-rw-r--r--test/snapshots/chordcut.golden165
-rw-r--r--test/snapshots/chordcut.snap132
-rw-r--r--test/snapshots/cmdword.golden45
-rw-r--r--test/snapshots/cmdword.snap22
-rw-r--r--test/snapshots/collapse.golden80
-rw-r--r--test/snapshots/collapse.snap36
-rw-r--r--test/snapshots/cornerdrag-left.golden100
-rw-r--r--test/snapshots/cornerdrag-left.snap8
-rw-r--r--test/snapshots/cornerdrag.golden150
-rw-r--r--test/snapshots/cornerdrag.snap22
-rw-r--r--test/snapshots/cursorline.golden102
-rw-r--r--test/snapshots/cursorline.snap12
-rw-r--r--test/snapshots/doccol.golden33
-rw-r--r--test/snapshots/doccol.snap24
-rw-r--r--test/snapshots/dump.golden26
-rw-r--r--test/snapshots/dump.snap6
-rw-r--r--test/snapshots/edit.golden72
-rw-r--r--test/snapshots/edit.snap6
-rw-r--r--test/snapshots/exec-bigdrag.golden9
-rw-r--r--test/snapshots/exec-bigdrag.snap30
-rw-r--r--test/snapshots/exec.golden31
-rw-r--r--test/snapshots/exec.snap24
-rw-r--r--test/snapshots/fileedit.golden61
-rw-r--r--test/snapshots/fileedit.snap19
-rw-r--r--test/snapshots/filewatch.golden69
-rw-r--r--test/snapshots/filewatch.snap22
-rw-r--r--test/snapshots/find.golden160
-rw-r--r--test/snapshots/find.snap20
-rw-r--r--test/snapshots/fsearch.golden158
-rw-r--r--test/snapshots/fsearch.snap10
-rw-r--r--test/snapshots/ghostty-mid.golden9
-rw-r--r--test/snapshots/ghostty-mid.snap14
-rw-r--r--test/snapshots/grep.golden66
-rw-r--r--test/snapshots/grep.snap16
-rw-r--r--test/snapshots/hscroll.golden40
-rw-r--r--test/snapshots/hscroll.snap20
-rw-r--r--test/snapshots/images.golden170
-rw-r--r--test/snapshots/images.snap22
-rw-r--r--test/snapshots/jumps.golden379
-rw-r--r--test/snapshots/jumps.snap6
-rw-r--r--test/snapshots/layout-close.golden51
-rw-r--r--test/snapshots/layout-close.snap18
-rw-r--r--test/snapshots/layout-open.golden41
-rw-r--r--test/snapshots/layout-open.snap36
-rw-r--r--test/snapshots/leader.golden109
-rw-r--r--test/snapshots/leader.snap8
-rw-r--r--test/snapshots/load.golden72
-rw-r--r--test/snapshots/load.snap4
-rw-r--r--test/snapshots/logquiet.golden7
-rw-r--r--test/snapshots/logquiet.snap4
-rw-r--r--test/snapshots/look-center.golden67
-rw-r--r--test/snapshots/look-center.snap26
-rw-r--r--test/snapshots/look-dir.golden11
-rw-r--r--test/snapshots/look-dir.snap10
-rw-r--r--test/snapshots/look-file-1col.golden29
-rw-r--r--test/snapshots/look-file-1col.snap15
-rw-r--r--test/snapshots/look-file.golden94
-rw-r--r--test/snapshots/look-file.snap10
-rw-r--r--test/snapshots/lookloaded.golden51
-rw-r--r--test/snapshots/lookloaded.snap31
-rw-r--r--test/snapshots/lookpanes.golden136
-rw-r--r--test/snapshots/lookpanes.snap38
-rw-r--r--test/snapshots/lookrange.golden226
-rw-r--r--test/snapshots/lookrange.snap18
-rw-r--r--test/snapshots/lsp-client-edit.golden45
-rw-r--r--test/snapshots/lsp-client-edit.snap6
-rw-r--r--test/snapshots/lsp-client.golden33
-rw-r--r--test/snapshots/lsp-client.snap6
-rw-r--r--test/snapshots/lsp-rename.golden21
-rw-r--r--test/snapshots/lsp-rename.snap6
-rw-r--r--test/snapshots/lsp.golden33
-rw-r--r--test/snapshots/lsp.snap10
-rw-r--r--test/snapshots/lspcomplete.golden60
-rw-r--r--test/snapshots/lspcomplete.snap32
-rw-r--r--test/snapshots/lspcompletemoved.golden7
-rw-r--r--test/snapshots/lspcompletemoved.snap6
-rw-r--r--test/snapshots/lspdebug.golden15
-rw-r--r--test/snapshots/lspdebug.snap10
-rw-r--r--test/snapshots/lsprelpath.golden194
-rw-r--r--test/snapshots/lsprelpath.snap16
-rw-r--r--test/snapshots/markup.golden116
-rw-r--r--test/snapshots/markup.snap4
-rw-r--r--test/snapshots/mini.golden257
-rw-r--r--test/snapshots/mini.snap8
-rw-r--r--test/snapshots/modal.golden104
-rw-r--r--test/snapshots/modal.snap6
-rw-r--r--test/snapshots/msg.golden60
-rw-r--r--test/snapshots/msg.snap6
-rw-r--r--test/snapshots/multicursor.golden128
-rw-r--r--test/snapshots/multicursor.snap10
-rw-r--r--test/snapshots/nested-optout.golden35
-rw-r--r--test/snapshots/nested-optout.snap4
-rw-r--r--test/snapshots/nested.golden39
-rw-r--r--test/snapshots/nested.snap6
-rw-r--r--test/snapshots/ninep.golden343
-rw-r--r--test/snapshots/ninep.snap4
-rw-r--r--test/snapshots/pipe.golden19
-rw-r--r--test/snapshots/pipe.snap2
-rw-r--r--test/snapshots/psearch.golden110
-rw-r--r--test/snapshots/psearch.snap16
-rw-r--r--test/snapshots/reflow.golden7
-rw-r--r--test/snapshots/reflow.snap4
-rw-r--r--test/snapshots/respawn.golden9
-rw-r--r--test/snapshots/respawn.snap8
-rw-r--r--test/snapshots/restore.golden19
-rw-r--r--test/snapshots/restore.snap4
-rw-r--r--test/snapshots/rsearch.golden51
-rw-r--r--test/snapshots/rsearch.snap50
-rw-r--r--test/snapshots/savepane.golden19
-rw-r--r--test/snapshots/savepane.snap4
-rw-r--r--test/snapshots/scroll.golden170
-rw-r--r--test/snapshots/scroll.snap10
-rw-r--r--test/snapshots/scrolloff.golden97
-rw-r--r--test/snapshots/scrolloff.snap10
-rw-r--r--test/snapshots/selarg.golden21
-rw-r--r--test/snapshots/selarg.snap32
-rw-r--r--test/snapshots/selregex.golden118
-rw-r--r--test/snapshots/selregex.snap2
-rw-r--r--test/snapshots/shellset.golden18
-rw-r--r--test/snapshots/shellset.snap2
-rw-r--r--test/snapshots/shrinktag.golden47
-rw-r--r--test/snapshots/shrinktag.snap32
-rw-r--r--test/snapshots/splitparent.golden39
-rw-r--r--test/snapshots/splitparent.snap12
-rw-r--r--test/snapshots/stepgrain.golden118
-rw-r--r--test/snapshots/stepgrain.snap6
-rw-r--r--test/snapshots/syntax.golden200
-rw-r--r--test/snapshots/syntax.snap10
-rw-r--r--test/snapshots/tag.golden31
-rw-r--r--test/snapshots/tag.snap23
-rw-r--r--test/snapshots/tagalign.golden69
-rw-r--r--test/snapshots/tagalign.snap52
-rw-r--r--test/snapshots/tagalign2col.golden36
-rw-r--r--test/snapshots/tagalign2col.snap40
-rw-r--r--test/snapshots/tagbottom.golden253
-rw-r--r--test/snapshots/tagbottom.snap48
-rw-r--r--test/snapshots/tagbottomimage.golden188
-rw-r--r--test/snapshots/tagbottomimage.snap33
-rw-r--r--test/snapshots/tagbottomshort.golden41
-rw-r--r--test/snapshots/tagbottomshort.snap10
-rw-r--r--test/snapshots/tagcmd.golden21
-rw-r--r--test/snapshots/tagcmd.snap4
-rw-r--r--test/snapshots/tagnav.golden85
-rw-r--r--test/snapshots/tagnav.snap21
-rw-r--r--test/snapshots/tagpath.golden97
-rw-r--r--test/snapshots/tagpath.snap68
-rw-r--r--test/snapshots/theme.golden652
-rw-r--r--test/snapshots/theme.snap108
-rw-r--r--test/snapshots/themesel.golden824
-rw-r--r--test/snapshots/themesel.snap85
-rw-r--r--test/snapshots/tinywin.golden44
-rw-r--r--test/snapshots/tinywin.snap8
-rw-r--r--test/snapshots/topbarexec.golden34
-rw-r--r--test/snapshots/topbarexec.snap8
-rw-r--r--test/snapshots/tty.golden49
-rw-r--r--test/snapshots/tty.snap2
-rw-r--r--test/snapshots/ttyclick.golden29
-rw-r--r--test/snapshots/ttyclick.snap14
-rw-r--r--test/snapshots/ttyedit.golden41
-rw-r--r--test/snapshots/ttyedit.snap6
-rw-r--r--test/snapshots/ttyfollow.golden55
-rw-r--r--test/snapshots/ttyfollow.snap10
-rw-r--r--test/snapshots/ttyhelp.golden65
-rw-r--r--test/snapshots/ttyhelp.snap4
-rw-r--r--test/snapshots/ttylook.golden107
-rw-r--r--test/snapshots/ttylook.snap6
-rw-r--r--test/snapshots/ttyonly.golden70
-rw-r--r--test/snapshots/ttyonly.snap2
-rw-r--r--test/snapshots/ttypaste.golden11
-rw-r--r--test/snapshots/ttypaste.snap2
-rw-r--r--test/snapshots/ttyprompt.golden25
-rw-r--r--test/snapshots/ttyprompt.snap2
-rw-r--r--test/snapshots/ttytaken.golden85
-rw-r--r--test/snapshots/ttytaken.snap22
-rw-r--r--test/snapshots/tutor.golden27
-rw-r--r--test/snapshots/tutor.snap6
-rw-r--r--test/snapshots/wheeldrift.golden73
-rw-r--r--test/snapshots/wheeldrift.snap22
-rw-r--r--test/snapshots/winch.golden18
-rw-r--r--test/snapshots/winch.snap4
-rw-r--r--test/snapshots/windownav.golden35
-rw-r--r--test/snapshots/windownav.snap4
-rw-r--r--test/snapshots/windowops.golden180
-rw-r--r--test/snapshots/windowops.snap20
-rw-r--r--test/snapshots/wrap.golden56
-rw-r--r--test/snapshots/wrap.snap12
-rw-r--r--test/snapshots/yankpaste.golden37
-rw-r--r--test/snapshots/yankpaste.snap12
-rw-r--r--test/tag_cleanup.py73
-rw-r--r--test/ui_review.py195
-rw-r--r--test/web_harness.mjs2
271 files changed, 11301 insertions, 4893 deletions
diff --git a/README.md b/README.md
index 1fdb73bb..49bcdb29 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,20 @@ One core, five frontends. The core owns editing, layout, rendering, and the
filesystem namespace. Frontends translate native input into `pardes.Event`,
present `pardes.Surface`, and perform host effects such as spawning processes.
+Fifteen [native Pardes themes](docs/themes.md) coordinate the editor, search,
+diagnostics and embedded terminal: `orchard` (the near-black default), `dusk`,
+`ink`, `paper`, `daybreak`, and the Acme-inspired `atelier`. `ink` and
+`daybreak` provide high contrast dark and light choices. Six classic-inspired
+adaptations add `forge`, `lagoon`, `solarium`, `spectrum`, `harvest`, and `clay`.
+`forge_black` and `orchard_black` offer pure-black variations; `forge_soft`
+offers a deliberately softer contrast. Execute `ThemeSel` to choose native
+themes first, followed by the existing legacy/imported collection. `FocusTint` toggles
+the active pane and column tag tints (on by default), and `SyntaxBold` toggles bold
+syntax keywords (off by default), in both GUI and TTY.
+
+SDL also supports `Font <name>:<size>` and optional pixel companions in the
+unused workspace tag: `Pet cat`, `Pet frog`, or `Pet off`.
+
`Mini path` opens a braille minimap with syntax colors: two text columns by four
lines per cell. It reads through the normal filesystem namespace; run it again
to refresh. Mini snapshots survive Dump/Restore without rereading the source.
@@ -206,6 +220,7 @@ sketch; `docs/design.pdf` is a retained rendering/search fixture and may lag it.
| `docs/design.typ` | architecture: the seams, the data model, the build graph |
| `docs/detached.md` | one core, many frontends, over a unix socket |
| `docs/config.md` | build options and runtime configuration |
+| `docs/tags.md` | editable workspace, column and pane tags; filename drafts |
| `docs/fs.md` | default 9P service, Look resolution, and named mounts |
| `docs/lsp.md` | in-process ZLS and external language servers |
| `docs/lsp-evaluation.md` | why that backend, measured against the alternatives |
diff --git a/docs/config.md b/docs/config.md
index 0a6765b8..79a5e631 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -23,7 +23,7 @@ which `Config` reports as `no per-user config path`.
`Config` (`SPC f c`, or the word executed anywhere) opens one refreshable
`+Config` pane. It reports the startup path and every live config-like value:
-theme, colors, wrapping, tag position, debug mode, the requested shell and the
+theme, colors, focus tint, syntax weight, wrapping, tag position, debug mode, the requested shell and the
executable actually resolved at the last spawn, requested/effective GUI font
and size, tagline scale, panel transition,
scene effects, hover delay, platform, native-image support, and (on SDL) whether
@@ -65,7 +65,7 @@ The format is one existing builtin command per line, using the same spelling
and argument parsing as commands executed inside pardes:
```text
-Theme acme
+Theme orchard
Font DejaVuSansMono-Regular
TaglineSize 82
Shell zsh
@@ -83,7 +83,7 @@ everything after the name as the argument. On a native build that is `Theme`,
(`Peek`, `Poke`, `Hexdump` and `Gpio` take one too, but they exist only where
`builtins.Board.enabled` holds, and that build has no config file.)
-`Theme <name>` wants one of the 228 names in the ring. Do not derive the
+`Theme <name>` wants one of the names in the compiled ring. Do not derive the
spelling — read it off `ThemeSel` (`SPC t t`), which lists every one as the
exact `Theme <name>` line that selects it. `slug` in `tools/gen_themes.zig`
lowercases, folds punctuation runs to a single `_` and then TRIMS leading and
@@ -94,6 +94,28 @@ and `ayu_mirage` is helix's `ayu_mirage.toml`. The suffix goes on all of them
rather than only the eight that clash today, so a name cannot move when either
project gains or loses a file. A name that is not in the ring is ignored.
+The fifteen [native Pardes themes](themes.md) lead the ring: `orchard` (the
+default), `dusk`, `ink`, `paper`, `daybreak`, `atelier`, `forge`, `lagoon`,
+`solarium`, `spectrum`, `harvest`, `clay`, `forge_black`, `forge_soft`, and
+`orchard_black`. `ThemeSel` lists them first under Pardes themes, followed by
+a separate legacy/imported section. They add coordinated
+focus, search, diagnostic and terminal colors; `ink` and `daybreak` are high
+contrast dark and light options. The original `helix`, `dark` and `acme`
+themes and all imported names remain available.
+
+`FocusTint` toggles the focused pane and column tag tints; it is on by default.
+Workspace, column and pane command text can be edited directly; see
+[editable tags](tags.md) for naming and saved-workspace behavior.
+`ColumnTags` toggles the column command row in both GUI and TTY; it is on by
+default. Add `ColumnTags` to startup configuration to reclaim that row on a
+compact screen. Hiding it preserves your custom column commands.
+`SyntaxBold` toggles bold syntax keywords; it is off by default. These
+settings are shared by GUI and TTY, and `Config` reports their current
+states. Like `Colors` and `Wrap`, these commands take no argument and invert
+the current value. A `FocusTint` line in a fresh startup configuration disables
+the tint; a `SyntaxBold` line enables the stronger keyword weight. Those two
+appearance controls leave focus, selections and editing behavior unchanged.
+
## Crash records
A panic appends to `crashes` in that same directory, beside `init`, and only
@@ -172,8 +194,14 @@ format, and it is `pardes.Theme` serialised by `std.zon.stringify`: the theme
name, thirteen required RGB roles (`sel_bg`, `sel_fg`, `tag_bg`, `tag_fg`,
`box`, `box_dim`, `kw`, `str`, `num`, `comment`, `lineno`, `scroll_track`,
`scroll_thumb`), nullable `bg`/`fg`, and either a 16-color RGB `palette` or
-`null`. RGB values are three-byte arrays, and hex literals are accepted. There
-is no inheritance or partial override layer.
+`null`. Nine optional nullable RGB roles extend this format:
+`tag_active_bg`, `tag_active_fg`, `border`, `search_bg`, `search_fg`,
+`diagnostic_error`, `diagnostic_warning`, `diagnostic_info`, and
+`diagnostic_hint`. Missing new roles use backward-compatible defaults, so
+previously exported files remain valid. [Theme customization](themes.md)
+describes each role and its fallback. RGB values are three-byte arrays, and
+hex literals are accepted. The original fields remain required; there is no
+inheritance or partial override layer.
`Filter` in a terminal's tag projects that pane's ANSI colors through the
active theme, and does it in two stages. The default foreground and background
@@ -202,8 +230,24 @@ terminal's font belongs to its emulator and a browser's to the page — so a
resolve the name by walking the font directories on every lookup, so a face
installed a moment ago is findable.
+Use `Font <name>:<size>` to change face and size together, for example
+`Font MartianMono-NrRg:18` in the startup file or an editable tag. Fractional
+sizes such as `:18.5` are supported; the accepted range is 8–72 (pixels in SDL,
+points on macOS). `Font <name>` without a suffix preserves the current size.
+Invalid sizes or unknown faces leave the current font unchanged.
+
+The SDL GUI also has a tiny optional workspace-tag companion: `Pet cat`,
+`Pet frog`, or `Pet off` (the default). Its original pixel sprite walks and
+idles in the trailing blank area of the global tag only. It hides while that
+tag is being edited, when the tag is full, or when the font leaves too little
+room; it never replaces text, receives clicks, or appears in pane/column tags.
+Animation runs at ten steps per second, uses theme ink, and requires no image
+assets or shaders. Put `Pet cat` in the startup configuration to keep it;
+`Pet off` disables the companion and its animation. Other hosts ignore the
+startup command. `Config` reports the current choice in SDL.
+
`Font` is asynchronous at the renderer boundary. `Config` therefore keeps
-requested name/path, pending state, and the effective face/point-or-pixel size
+requested name/path/size, pending state, and the effective face/point-or-pixel size
as separate facts; a failed request never gets reported as the face on screen.
Taglines use a distinct face size in both native GUI renderers. Execute
`TaglineSize <percent>` to change it live, for example `TaglineSize 70`; the
@@ -221,7 +265,8 @@ same compiled percentage to its DOM glyphs but has no runtime setter.
Both native GUIs join the reduced-height global and pane tagline bands with
`gui_topbar_pane_border_px` physical pixels. Set it to zero for a direct join.
`gui_topbar_pane_border_rgb` can pin an RGB color; its default `null` follows
-the active theme's scrollbar-track color. With `Tagbottom` enabled, a tagline
+the theme's `border` role in SDL (falling back to `scroll_track` for older
+themes), and `scroll_track` in the macOS shell. With `Tagbottom` enabled, a tagline
on the final grid row is bottom-aligned so the same unused half-band does not
show beneath it. The rule itself lives in the core
(`pardes.taglineBandOffset`), and the macOS shell reaches it over the C ABI
@@ -270,7 +315,14 @@ PanelScramble
PanelType
```
-All panel transitions start off. Slide uses cubic ease-out and zoom uses an
+All panel transitions start off. To disable one, execute its builtin again:
+`PanelDissolve` turns off an active dissolve, and `PanelAscii` turns off an
+active ASCII transition. `Config` shows the active command under
+`Panel transition`. Remove that command from your startup configuration to
+keep it off after restarting. Executing a different transition enables that
+one instead; these commands are toggles, not an unconditional animation-off command.
+
+Slide uses cubic ease-out and zoom uses an
overshooting ease-out-back. Dissolve and ASCII compare the last successfully
presented grid with the new one. Dissolve switches visually changed cells at
stable noise thresholds.
diff --git a/docs/design.typ b/docs/design.typ
index 8a5b9381..88bb49d6 100644
--- a/docs/design.typ
+++ b/docs/design.typ
@@ -1920,17 +1920,24 @@ system clipboard, which is helix's five words — `SPC y/Y/p/P/R`, out via
cannot clobber what the desktop was holding. A paste from an outer terminal
arrives bracketed, as one `paste` event.
-*Tag.* Live prefix (mode indicator, cwd or path) + editable tail with the
-full modal editor. Save leads the tail of every pane holding text of its own:
-`Save New Newtty Del` for a file or an output buffer,
-`Save New Newtty Del Filter` for a terminal, and the plain `New Newtty Del`
-for an image or a PDF, with `*` after an unsaved file's name; an image tag
+*Tag.* Compact name/status prefix + editable command tail. File names support
+staged edits: Enter commits a new buffer save target, Escape cancels, and no
+disk rename or write happens until explicit Save. Terminal cwd and image/PDF
+status stay generated. Save leads the tail of every pane holding text of its own:
+`Save Tty Del Collapse` for a file or an output buffer,
+`Save Tty Del Togglettymode Filter Collapse` for a terminal, and `Tty Del Collapse`
+for an image. PDFs use `Tty Del PdfSections PdfTint Collapse`, without tint status text.
+`Collapse` toggles a pane between its tagline alone and its expanded height;
+hidden body contents and running terminals are retained.
+An unsaved file has `*` after its name; an image tag
reports
`img petscii:<on|off> palette:<commodore|terminal> ascii:<on|off> <path>`
before the ordinary tail (its renderer toggles are builtins under `SPC t
p/l/a`). Topbar:
-`New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill` —
-execute-only (left click inert);
+`Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill` —
+editable by left click, with keyboard command navigation and Exec/Look gestures.
+An additional editable tag in each column supplies local New, Tty, Find,
+Grep and Joincol commands. ColumnTags hides that row when space is tight;
Colors and Crt left it for their leader paths.
*Panes.* Terminal: ghostty-vt, 16 MiB scrollback, OSC 133 prompt semantics,
diff --git a/docs/helix-keys.md b/docs/helix-keys.md
index dcd5b7cb..b999a25c 100644
--- a/docs/helix-keys.md
+++ b/docs/helix-keys.md
@@ -118,7 +118,7 @@ language-backend queries, and the shell pipe.
| `Enter` (normal) | acme **look** chord: EXPLICIT selection, else file-ish word under cursor | pardes-specific, keep (helix normal-mode Enter unbound). Covers helix `gf`. Implicit motion residue falls back to the cursor word | pardes-specific |
| `Tab` (normal) | acme **execute** chord | pardes-specific, keep; explicit-selection rule as Enter | pardes-specific |
| `:` (normal, body) | focuses the pane's OWN tag as a one-line editor in **normal** mode, parked at the first EDITABLE column: motions (`w` `b` `e` `W` `B` `E`, `0` `$` `^`, arrows, `Home`/`End`) walk the whole rendered tag, `y` yanks the selection, `Enter`/`Tab` look/execute it (else the file-ish word under the cursor), `i`/`a`/`I`/`A` enter insert, `Esc` hands the body back. `h`/`j`/`k`/`l` are NOT motion here — a tagline is a place in the LAYOUT, so they run the same `Left`/`Down`/`Up`/`Right` builtins and land on the neighbouring pane's TAGLINE, still in normal mode (nothing that way = stay put, EXCEPT `k` off the topmost tagline — see the next row); the arrows keep the in-tag motion | helix `:` is command mode (section C); pardes' commands are acme words that live in the tag. `tag_col`/`tag_anchor` are columns of the RENDERED tag (prefix ++ tail) — one coordinate space, so the live mode+path prefix is selectable, yankable and executable, while every edit op (typing, `Backspace`, `i`/`a`/`I`/`A`) measures from the first editable column and is inert inside it | pardes-specific |
-| `k` (tag normal, topmost tagline) | focuses the TOPBAR — row 0, the global tagline (`config.topbar_str`, today `New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill`, plus `Restore <path>` once a dump exists). It is its own one-line normal mode: `h`/`l` and the arrows by grapheme (row 0 has no window left or right to walk to), `w`/`b`/`e`/`W`/`B`/`E` and `0`/`$`/`^` by word, `Enter`/`Tab` runs the word under the cursor through the same dispatch a MIDDLE click on it uses, `j` drops back onto the topmost pane's tagline, `Esc` leaves. No insert mode and no selection — the bar is chrome with no tail to own | pardes-specific. The topbar is not a pane, so `focusDir` can never reach it: this is a fallback on the `.Up` branch of the tagline hop, from a TAGLINE only (a body's `SPC w k`/`Ctrl-w k` keep their pane-to-pane meaning). Its whole state is one global `topbar_col: ?u16` (row 0 has no pane to hang it on), cleared by any mouse press and BEFORE the chord dispatch, because `Kill` up here frees the session the way `Del` frees a pane. The motion vocabulary is literally the tag's — both call `lineMotion` | pardes-specific |
+| `k` (tag normal, topmost tagline) | focuses the column tag, then another `k` reaches the workspace tag at row 0 (`Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill`, plus `Restore <path>` once a dump exists). With `ColumnTags` disabled it goes directly to the workspace. `j` walks back down. Header arrows and `h`/`l` move by grapheme; word motions and `0`/`$`/`^` work too. In normal mode `Enter`/`Tab` executes; `i`/`a`/`I`/`A` enter editing, where Enter is Look and Tab is Exec. Left-click, drag selection, typing, and paste edit either header; Esc leaves | Column commands target that column's active pane, or its first pane when coming from elsewhere. Workspace and column text are independently editable and persist in dumps. See [editable tags](tags.md) | pardes-specific |
| `Ctrl-w` + `h/j/k/l`/arrows | directional pane focus prefix — normal/tty modes only | pardes' own window handling (helix window mode skipped, section C). Runs the SAME `Left`/`Down`/`Up`/`Right` builtins `SPC w h/j/k/l` runs; kept alongside the leader because a pane in raw **tty** mode never sees `SPC` (the shell owns it), so this is the only keyboard way out of one. Insert mode owns `Ctrl-w` = delete-word-back, so a tag being TYPED into swallows it; from a tag in normal mode (`:`) it moves focus to the neighbour's BODY, while the bare letters `h/j/k/l` there move to its TAGLINE (next row) | pardes-specific |
| `Alt-n` | new terminal below (any mode) | shadows helix `Alt-n` TS sibling-select — skipped anyway (tree-sitter) | pardes-specific |
| `Alt-c` | move active terminal to a fresh column (any mode) | helix `Alt-c` is change-noyank; the pardes window op wins (do-not-touch contract). `Alt-d` + `i` covers the behavior | waived (`alt-c-window-op`) |
diff --git a/docs/screenshots/agave-lsp.txt b/docs/screenshots/agave-lsp.txt
new file mode 100644
index 00000000..9a46b911
--- /dev/null
+++ b/docs/screenshots/agave-lsp.txt
@@ -0,0 +1,38 @@
+backend: zls-inproc+lsp-client
+zls: 0.16.1-dev+3e0d0820 (compiled in — no server process, no JSON-RPC)
+zig lib dir: /usr/lib/zig [OK]
+offsets: utf-8 walk caps: 512 files, 2000 rows
+
+dependency imports gd can follow (8):
+ zls /home/goblin/00-projects/0x4200.cafe/02-pardes-code/zig-pkg/zls-0.16.1-dev-rmm5ftfOJgAzIdWUGVB08ycFbud2O3viKnGF1HZgfKZJ/src/zls.zig
+ tree-sitter /home/goblin/00-projects/0x4200.cafe/02-pardes-code/zig-pkg/tree_sitter-0.26.0-8heIf3CaAQB4SSumoGzq3gLSz2rkvXxcKFyskRWqDGBz/src/root.zig
+ zstbi /home/goblin/00-projects/0x4200.cafe/02-pardes-code/zig-pkg/zstbi-0.11.0-dev-L0Ea_3GWBwAh7m54XX055vwLKPTPij5hyqyeq92MXPE2/src/zstbi.zig
+ mvzr /home/goblin/00-projects/0x4200.cafe/02-pardes-code/zig-pkg/mvzr-0.3.9-ZSOky6t2AQCA7efmm5EYbPb5sOdbXa4EFsUgYbQ6hZv9/src/mvzr.zig
+ mupdf /home/goblin/00-projects/0x4200.cafe/02-pardes-code/src/pdf.zig
+ ghostty-vt /home/goblin/00-projects/0x4200.cafe/02-pardes-code/zig-pkg/ghostty-1.3.2-dev-5UdBCzeJJQXw_vG5Hsfx0DYUmF7Exs_9yctijqOIfp7W/src/lib_vt.zig
+ vaxis /home/goblin/00-projects/0x4200.cafe/02-pardes-code/zig-pkg/vaxis-0.6.0-BWNV_CrbCQCscGpzsAlR402rYQ_tV3aAl081c2iRRkka/src/main.zig
+ uucode /home/goblin/00-projects/0x4200.cafe/02-pardes-code/zig-pkg/uucode-0.2.0-ZZjBPlK5VADj7fdoq7G8LIHzD5o6FSkcBXXrRWr4jnrA/src/root.zig
+asked from: /home/goblin/00-projects/00-solana/agave/02-upstream/gossip/src/crds_value.rs
+
+answers: definition, declaration, type_definition, implementation, references, hover, document_symbols, workspace_symbols, diagnostics, workspace_diagnostics, rename, code_action, format, select_refs, completion
+refuses: incoming_calls, outgoing_calls, supertypes, subtypes
+
+last queries (0 total, keeping 24):
+ (none yet — press gd somewhere, then ask again)
+
+protocol servers (lsp-client):
+ rust-analyzer ready root /home/goblin/00-projects/00-solana/agave/02-upstream utf8 pull-diags call-hier docs 1 diag-files 0 [PARDES_LSP_RS=/home/goblin/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/rust-analyzer]
+ .rs
+ clangd off [PARDES_LSP_C=(disabled)]
+ .c .h .cc .cpp .hpp .cxx .hxx
+ gopls off [PARDES_LSP_GO=(disabled)]
+ .go
+ typescript-language-server off [PARDES_LSP_TS=(disabled)]
+ .ts .tsx .js .jsx .mjs .cjs
+ pyright off [PARDES_LSP_PY=(disabled)]
+ .py
+
+client queries (3 total, keeping 24):
+ document_symbols rust-analyzer crds_value.rs 52 row(s)
+ hover rust-analyzer crds_value.rs 0 row(s)
+ definition rust-analyzer crds_value.rs 1 row(s)
diff --git a/docs/screenshots/atelier.png b/docs/screenshots/atelier.png
new file mode 100644
index 00000000..f889647a
--- /dev/null
+++ b/docs/screenshots/atelier.png
Binary files differ
diff --git a/docs/screenshots/before.png b/docs/screenshots/before.png
new file mode 100644
index 00000000..f2e3d506
--- /dev/null
+++ b/docs/screenshots/before.png
Binary files differ
diff --git a/docs/screenshots/classic-gallery.json b/docs/screenshots/classic-gallery.json
new file mode 100644
index 00000000..0b1092dd
--- /dev/null
+++ b/docs/screenshots/classic-gallery.json
@@ -0,0 +1,21 @@
+{
+ "themes": [
+ "forge",
+ "lagoon",
+ "solarium",
+ "spectrum",
+ "harvest",
+ "clay"
+ ],
+ "pets": [
+ "cat",
+ "frog",
+ "off"
+ ],
+ "os_windows": [
+ "20971567"
+ ],
+ "font_effective_pixels": 18,
+ "tagline_percent": 80,
+ "source_unchanged": true
+} \ No newline at end of file
diff --git a/docs/screenshots/classic-themes.png b/docs/screenshots/classic-themes.png
new file mode 100644
index 00000000..f0fe4089
--- /dev/null
+++ b/docs/screenshots/classic-themes.png
Binary files differ
diff --git a/docs/screenshots/columns-atelier.png b/docs/screenshots/columns-atelier.png
new file mode 100644
index 00000000..2727df2f
--- /dev/null
+++ b/docs/screenshots/columns-atelier.png
Binary files differ
diff --git a/docs/screenshots/columns-orchard.png b/docs/screenshots/columns-orchard.png
new file mode 100644
index 00000000..0fa179a5
--- /dev/null
+++ b/docs/screenshots/columns-orchard.png
Binary files differ
diff --git a/docs/screenshots/columns-parity.json b/docs/screenshots/columns-parity.json
new file mode 100644
index 00000000..9e18f2d4
--- /dev/null
+++ b/docs/screenshots/columns-parity.json
@@ -0,0 +1,37 @@
+{
+ "commands": [
+ "python3 -B test/column_tags.py zig-out/column-review/bin/pardes-gui /home/goblin/.cache/ct-sdl --project /home/goblin/00-projects/00-solana/agave/02-upstream",
+ "python3 -B test/column_tags.py zig-out/column-review/bin/pardes /home/goblin/.cache/ct-tty --project /home/goblin/00-projects/00-solana/agave/02-upstream --tty"
+ ],
+ "checks_per_host": 11,
+ "input": "Real keyboard and SGR mouse bytes through each host PTY parser; 9P state observation",
+ "comparison": "Core grid text and foreground/background colors; owned output directory names normalized ct-sdl/ct-tty to ct-run",
+ "limitations": [
+ "SDL captures are native GPU PNGs; TTY captures are core grids, not independent terminal-emulator screenshots.",
+ "This helper does not automate SDL pixel-coordinate mouse events.",
+ "Unicode editing and persistence are verified separately; presentation tags use ASCII because selected font lacks CJK glyph coverage."
+ ],
+ "frames": {
+ "columns-orchard": {
+ "cols": 150, "rows": 48,
+ "matching_color_cells": 7200, "total_cells": 7200,
+ "matching_text_rows": 48,
+ "cursor_sdl": {"x": 82, "y": 3, "bar": false},
+ "cursor_tty": {"x": 82, "y": 3, "bar": false}
+ },
+ "columns-atelier": {
+ "cols": 150, "rows": 48,
+ "matching_color_cells": 7200, "total_cells": 7200,
+ "matching_text_rows": 48,
+ "cursor_sdl": {"x": 82, "y": 3, "bar": false},
+ "cursor_tty": {"x": 82, "y": 3, "bar": false}
+ },
+ "columns-tag-reveal": {
+ "cols": 150, "rows": 48,
+ "matching_color_cells": 7200, "total_cells": 7200,
+ "matching_text_rows": 48,
+ "cursor_sdl": {"x": 74, "y": 2, "bar": true},
+ "cursor_tty": {"x": 74, "y": 2, "bar": true}
+ }
+ }
+}
diff --git a/docs/screenshots/columns-tag-reveal.png b/docs/screenshots/columns-tag-reveal.png
new file mode 100644
index 00000000..ce55adbc
--- /dev/null
+++ b/docs/screenshots/columns-tag-reveal.png
Binary files differ
diff --git a/docs/screenshots/compact-columns.png b/docs/screenshots/compact-columns.png
new file mode 100644
index 00000000..61b07ad7
--- /dev/null
+++ b/docs/screenshots/compact-columns.png
Binary files differ
diff --git a/docs/screenshots/daybreak.png b/docs/screenshots/daybreak.png
new file mode 100644
index 00000000..09cba567
--- /dev/null
+++ b/docs/screenshots/daybreak.png
Binary files differ
diff --git a/docs/screenshots/dusk.png b/docs/screenshots/dusk.png
new file mode 100644
index 00000000..53c55313
--- /dev/null
+++ b/docs/screenshots/dusk.png
Binary files differ
diff --git a/docs/screenshots/ink.png b/docs/screenshots/ink.png
new file mode 100644
index 00000000..171c6427
--- /dev/null
+++ b/docs/screenshots/ink.png
Binary files differ
diff --git a/docs/screenshots/orchard.png b/docs/screenshots/orchard.png
new file mode 100644
index 00000000..66057fa5
--- /dev/null
+++ b/docs/screenshots/orchard.png
Binary files differ
diff --git a/docs/screenshots/paper.png b/docs/screenshots/paper.png
new file mode 100644
index 00000000..7294869f
--- /dev/null
+++ b/docs/screenshots/paper.png
Binary files differ
diff --git a/docs/screenshots/parity.json b/docs/screenshots/parity.json
new file mode 100644
index 00000000..c2e636e3
--- /dev/null
+++ b/docs/screenshots/parity.json
@@ -0,0 +1,20 @@
+{
+ "comparison": "Every row-major cell resolved to (grapheme, foreground color, background color), using each capture's own style table; indices are not compared.",
+ "gui_artifacts": "/home/goblin/.cache/pardes-ui-review-final",
+ "tty_artifacts": "/home/goblin/.cache/pardes-ui-review-final-tty",
+ "capture_files": "theme-<name>.json",
+ "gui_command": "python3 -B test/ui_review.py zig-out/ui-review/bin/pardes-gui /home/goblin/.cache/pardes-ui-review-final --project /home/goblin/00-projects/00-solana/agave/02-upstream --skip-lsp --theme orchard --themes orchard dusk ink paper daybreak atelier",
+ "tty_command": "python3 -B test/ui_review.py zig-out/ui-review/bin/pardes /home/goblin/.cache/pardes-ui-review-final-tty --project /home/goblin/00-projects/00-solana/agave/02-upstream --tty --skip-lsp --theme orchard --themes orchard dusk ink paper daybreak atelier",
+ "themes": [
+ {"name": "orchard", "cols": 150, "rows": 48, "compared_cells": 7200, "matching_cells": 7200},
+ {"name": "dusk", "cols": 150, "rows": 48, "compared_cells": 7200, "matching_cells": 7200},
+ {"name": "ink", "cols": 150, "rows": 48, "compared_cells": 7200, "matching_cells": 7200},
+ {"name": "paper", "cols": 150, "rows": 48, "compared_cells": 7200, "matching_cells": 7200},
+ {"name": "daybreak", "cols": 150, "rows": 48, "compared_cells": 7200, "matching_cells": 7200},
+ {"name": "atelier", "cols": 150, "rows": 48, "compared_cells": 7200, "matching_cells": 7200}
+ ],
+ "limitations": [
+ "TTY evidence is the real core grid and styles, not an independently rendered emulator screenshot.",
+ "Comparisons exclude SDL pixel decorations, rasterization, font-role metadata and terminal-emulator rendering."
+ ]
+}
diff --git a/docs/screenshots/pdf-and-tty-tags.png b/docs/screenshots/pdf-and-tty-tags.png
new file mode 100644
index 00000000..66c3a008
--- /dev/null
+++ b/docs/screenshots/pdf-and-tty-tags.png
Binary files differ
diff --git a/docs/screenshots/pets.png b/docs/screenshots/pets.png
new file mode 100644
index 00000000..b9a83d66
--- /dev/null
+++ b/docs/screenshots/pets.png
Binary files differ
diff --git a/docs/screenshots/theme-preferences-forge.png b/docs/screenshots/theme-preferences-forge.png
new file mode 100644
index 00000000..3497c291
--- /dev/null
+++ b/docs/screenshots/theme-preferences-forge.png
Binary files differ
diff --git a/docs/screenshots/theme-preferences.png b/docs/screenshots/theme-preferences.png
new file mode 100644
index 00000000..48bb0d57
--- /dev/null
+++ b/docs/screenshots/theme-preferences.png
Binary files differ
diff --git a/docs/screenshots/theme-selector.png b/docs/screenshots/theme-selector.png
new file mode 100644
index 00000000..883a2801
--- /dev/null
+++ b/docs/screenshots/theme-selector.png
Binary files differ
diff --git a/docs/tags.md b/docs/tags.md
new file mode 100644
index 00000000..87cee2ff
--- /dev/null
+++ b/docs/tags.md
@@ -0,0 +1,84 @@
+# Editable tags
+
+Pardes has three levels of command text: the workspace tag, one tag per
+column, and each pane's tag. Column commands run in that column's active
+pane (or its first pane when focus comes from another column). This makes
+`New`, `Tty`, `Find`, and `Grep` available beside the work they act on.
+`New` appears only in the column tag by default; pane tags keep their own
+save, terminal, close, and collapse commands. `Tty` opens a new embedded terminal.
+Column command text starts flush with the column's left edge, just like the
+workspace tag; pane bodies retain their scrollbars and line-number gutters.
+
+When Look opens the first document and its source column is too narrow for
+a new column, it splits below the originating pane, just like `Tty`, instead
+of inserting at the top of the leftmost column. The originating terminal is
+kept. As with `Tty`, a tagline-only source uses a roomier split parent.
+
+`Collapse` reduces a pane to just its tagline, giving all its body space to
+the nearest expanded pane above, or below if none is above. Other panes keep
+their heights. Execute it again to reclaim its former height from that one
+neighbor, as far as available space allows. If every pane is collapsed, the
+unused area stays blank.
+Its text and terminal process are kept;
+the command stays available in the visible tag. Every default pane tag includes
+`Collapse`, including file, terminal, image, and PDF panes.
+
+Left-click a tag to place its caret; drag to select text, then type to
+replace it. Arrow keys, Home, End, Backspace and Delete edit the line.
+Tags reveal the caret horizontally when text is wider than their column.
+Escape returns to the body, keeping command-text edits. The existing Exec
+and Look gestures still apply; the workspace tag is no longer an inert
+left-click target. Pasted text goes to the focused tag, not to the file or
+embedded shell beneath it.
+
+Normal tag navigation now visits pane, column, and workspace tags in order:
+from the top pane's `:` tag, `k` reaches the column and another `k` reaches
+the workspace; `j` walks back down. Enter or Tab on a header command in
+normal mode executes it, as before. `i`/`a`/`I`/`A` switch to editing the
+header. In insert mode, Enter is Look and Tab is Exec, as in pane tags.
+
+Pane filenames and commands now have a single separator space rather than
+generated right-alignment padding. Intentionally customized spacing is kept.
+
+## File names
+
+Editing a file pane's name creates a draft. Enter confirms the new buffer
+name; Escape or leaving the tag cancels the draft. Confirmation changes the
+buffer's save target and marks it unsaved. It does **not** rename, create or
+overwrite a disk file. A subsequent explicit `Save` writes the buffer to its
+committed name. Executing a pane-tag command confirms a valid name draft
+first, so a visible draft cannot silently save to the previous name.
+
+Terminal working directories and generated image/PDF status remain managed
+by their corresponding commands. Their command tails are editable just like
+file command tails.
+
+PDF tags follow the same filename-first layout: `manual.pdf [1/12] Tty Del
+PdfSections PdfTint Collapse`. Sections and tint commands remain in the editable
+tail, without displaying the current tint state. `PdfFit` (`SPC t z`) remains
+available, as do the shortcuts for `PdfTint` (`SPC t i`) and `PdfSections`
+(`SPC t s`, or `f` on a PDF).
+
+Terminal tags include `Togglettymode`, which toggles between normal editor mode and raw
+terminal input using the same transition as Ctrl-B. It also works while editing
+the tag: the command leaves tag editing and toggles the parked body mode.
+Executing it on a non-terminal pane does nothing.
+
+## Saved workspaces
+
+`Dump` and `Restore` preserve customized workspace and column tags, including
+intentionally empty tags. New columns start with the standard column tag.
+Closing a column keeps surviving columns' tags; `Joincol` keeps the destination
+column's tag. Old dumps without these optional fields retain the defaults.
+The automatic `Restore` shortcut does not overwrite a customized workspace
+tag.
+
+The column row stays above panes with `TagBottom` enabled. On screens shorter
+than three rows it is omitted so a pane still has room. SDL and TTY share the
+same tag text, editing and layout; SDL additionally uses compact font sizing
+and subtle pixel separators.
+
+`ColumnTags` toggles the column row (on by default) without deleting its text.
+`FocusTint` controls active-column and active-pane emphasis. SDL also honors
+the shared bold, underline, and strikethrough attributes, including diagnostic
+underlines and the optional `SyntaxBold` keyword weight.
diff --git a/docs/themes.md b/docs/themes.md
new file mode 100644
index 00000000..7d71d0dd
--- /dev/null
+++ b/docs/themes.md
@@ -0,0 +1,124 @@
+# Pardes themes
+
+Pardes ships fifteen native palettes: six originals, six classic-inspired
+adaptations and three contrast variants, designed for tags, text, search, diagnostics and embedded
+terminals together. `orchard` is the initial theme.
+Execute `Theme <name>` anywhere, or open `ThemeSel` with `SPC t t` and select
+a theme's command. Put the same command in your [startup configuration](config.md)
+to keep a preference. `NextColor` cycles through the native themes first,
+then the retained `helix`, `dark` and `acme` themes and imported palettes.
+`ThemeSel` groups the new palettes under `Pardes themes`, followed by
+`Legacy and imported themes`; its navigation skips the section headings.
+See the [Agave visual review](ui-review.md) for the original six-palette gallery.
+
+| Theme | Character | Page | Accent |
+| --- | --- | --- | --- |
+| `orchard` | Near-black evergreen; bright leaf comments and plum syntax | `#0d1410` | `#adcc91` |
+| `dusk` | Soft plum charcoal; copper comments and gentle text | `#39323b` | `#e4b39b` |
+| `ink` | Pure black; bright, distinct signals and ice-blue comments | `#000000` | `#86d8ff` |
+| `paper` | Neutral uncoated paper; graphite and teal | `#f5f3ed` | `#3c6b56` |
+| `daybreak` | High contrast light; white and deep blue ink | `#ffffff` | `#075f91` |
+| `atelier` | Acme homage; butter-yellow paper and blue-green tags | `#fffdeb` | `#3e7a68` |
+| `forge` | Dark Plus-inspired near-black, blue and peach; slate-blue tags | `#0c0c0e` | `#a5c4ee` |
+| `lagoon` | Softer Material-inspired slate; vivid sea-glass comments | `#34464c` | `#89c7b4` |
+| `solarium` | Softer Solarized-inspired blue-green; golden comments and teal tags | `#173e45` | `#d5bc72` |
+| `spectrum` | Monokai-inspired near-black and candy colors; golden comments | `#100e11` | `#ffd866` |
+| `harvest` | Autumn-inspired near-black earth, ember and leaf green | `#100e0b` | `#cfba8b` |
+| `clay` | Gruvbox-inspired near-black and earthy brights; amber comments | `#10100e` | `#8ec07c` |
+| `forge_black` | Pure-black Forge; luminous text and cool slate tags | `#000000` | `#a5c4ee` |
+| `forge_soft` | Neutral-slate Forge; gentler text, still vivid blue comments | `#35383e` | `#a5c4ee` |
+| `orchard_black` | Pure-black Orchard; luminous garden ink and bright leaf comments | `#000000` | `#adcc91` |
+
+The six adaptations retain recognizable classic syntax identities, but are
+not exact ports. Their Acme influence is deliberate: quiet command strips,
+thin boundaries, and a search surface
+distinct from selection. Forge uses cool-neutral chrome instead of green
+tints. Active pane and column tags use a restrained tone-on-tone shift, not
+a light/dark inversion: dark palettes keep dark tags, and light palettes
+keep light tags. A slight text lift and the focus marker retain the cue
+without turning the entire command strip into a highlight.
+Comments are colorful first-class text, while line numbers stay quiet;
+the current line number gets a small color emphasis and bold weight, never a bright tag-colored
+block. These are appearance changes only;
+tag editing, commands and terminal interaction are unchanged.
+
+Dark backgrounds make an explicit choice: near-black with bright text, or
+the gentler slate/plum/blue-green of `forge_soft`, `dusk`, `lagoon` and
+`solarium`. The softer group keeps body text around 5.5–6.7:1 contrast; the
+near-black group exceeds 14:1. Try `Theme forge_black` and `Theme forge_soft`
+back-to-back to compare the extremes without changing the syntax identity.
+Light paper and the Acme homage remain available.
+
+Their local references are `vendor/themes/dark_plus.toml`,
+`material_oceanic.toml` (and its `material_deep_ocean.toml` parent),
+`solarized_dark.toml`, `monokai_pro.toml`, `autumn.toml`, and the Gruvbox Dark
+entry in `gruvbox.json`. The original imported themes remain selectable under
+their existing names; the adaptations have distinct Pardes names and do not
+claim upstream affiliation. Existing vendor provenance and licenses remain
+with those sources.
+
+All fifteen palettes specify their own ANSI colors, so indexed terminal output
+belongs to the same palette as the editor. Explicit true-color output can
+still carry an application's own colors; the existing terminal `Filter`
+command projects those colors through the theme. The older `dark` palette
+continues to inherit the surrounding terminal's default background and text.
+
+The native palettes keep normal text, syntax colors, comments,
+diagnostics and ANSI foregrounds at a calculated sRGB contrast ratio of at
+least 4.5:1 against the page. `ink` and `daybreak` raise that floor to 7:1.
+Comments additionally stay above 5:1. Decorative line numbers sit between
+2.5:1 and 4:1, with current numbers capped at 4.5:1; they deliberately do not
+compete with source text. ANSI bright black is independent of the comment
+color, so making comments vivid does not recolor gray terminal output.
+Tag, active-tag, selection and search text are checked against their respective
+surfaces at the same thresholds. Active/inactive tag backgrounds differ by
+no more than 1.6:1, keeping focus changes quiet. ANSI black is exempt because applications
+also use it as a background. These are palette checks, not a guarantee about
+arbitrary terminal escape sequences, reversed colors or shader effects.
+
+## Make a theme your own
+
+Run `DumpThemes` to export complete `.zon` files below the configuration
+directory's `themes/builtin/`. Copy a native file to `themes/mine.zon`, change
+its `.name`, and run:
+
+```text
+ThemeFile themes/mine.zon
+```
+
+On hosts with live document reload, saving a valid theme file updates it
+immediately. An incomplete save keeps the last valid version. Selecting a
+built-in theme stops the custom theme watch.
+
+Pardes roles extend the original editor palette with independent choices
+for its UI. Each value is an RGB triple, for example
+`.search_bg = .{ 0x57, 0x47, 0x2a }`. New roles are optional and accept `null`,
+so existing exported themes remain valid.
+
+| Optional role | Purpose | When absent |
+| --- | --- | --- |
+| `tag_active_bg`, `tag_active_fg` | Focused pane tag surface and text | `tag_bg`, `tag_fg` |
+| `border` | Quiet separators | `scroll_track` |
+| `lineno_active` | Restrained current line number foreground | `lineno` |
+| `search_bg`, `search_fg` | Search matches, independent of selection | `sel_bg`, `sel_fg` |
+| `diagnostic_error` | Error text | `fg`, or `tag_fg` for an inherited foreground |
+| `diagnostic_warning` | Warning text | Same foreground fallback |
+| `diagnostic_info` | Informational diagnostic text | Same foreground fallback |
+| `diagnostic_hint` | Hint text | Same foreground fallback |
+
+These colors are shared by the GUI and TTY. Tags and their active tint retain
+the same text, command execution, drag targets and focus behavior. Selection
+and search have separate palette roles because they communicate different
+states. Theme changes use the existing chrome transition; body and terminal
+colors switch directly so syntax and ANSI content stay coherent.
+
+`FocusTint` toggles the focused pane's tag tint, which is on by default.
+`SyntaxBold` toggles bold syntax keywords, which are off by default. Both
+commands take no argument, work in GUI and TTY, and report their states in
+`Config`. Use them in the startup configuration to reverse the defaults.
+
+The original required roles remain unchanged: nullable `bg` and `fg`,
+`sel_bg`, `sel_fg`, `tag_bg`, `tag_fg`, `box`, `box_dim`, `kw`, `str`, `num`,
+`comment`, `lineno`, `scroll_track`, `scroll_thumb`, and a nullable 16-entry
+`palette`. `ThemeFile` loads a complete theme, with no inheritance or partial
+override syntax. The exported native files are the easiest starting point.
diff --git a/docs/ui-review.md b/docs/ui-review.md
new file mode 100644
index 00000000..e43ef9b7
--- /dev/null
+++ b/docs/ui-review.md
@@ -0,0 +1,230 @@
+# Visual review
+
+## Contrast choices and local collapse
+
+The fifteen native palettes now give comments vivid color and keep line
+numbers subdued. The current number uses muted ink and bold weight instead
+of a tag-colored background block, in SDL and TTY. Active pane and column
+tags use a small tonal shift without reversing their light/dark polarity.
+Column tag text starts at the column edge without the former two-cell inset.
+Forge has neutral coal
+and silver-blue chrome. `forge_black` and `orchard_black` use pure black;
+`forge_soft` joins `dusk`, `lagoon` and `solarium` as deliberately softer
+alternatives. Light and Acme-inspired choices remain available.
+
+`ThemeSel` opens with the native collection, followed by a separate legacy
+and imported section. Keyboard navigation skips both section headings.
+
+`Collapse` now transfers all released rows to one expanded pane, preferring
+the nearest one above and falling back below. Unrelated pane heights stay
+unchanged. Expansion borrows from one neighbor too, limited by its available
+body space. Tests cover exact unchanged sibling rectangles, repeated inverse
+toggles, already-folded neighbors, tiny resizes, drag expansion and Dump/Restore.
+
+The refreshed builds pass 791 TTY and 822 SDL unit tests, with one skipped
+in each suite, plus all 98 interaction snapshots. Snapshot review found only
+the intended style changes, the expanded grouped theme picker, and flush-left
+column text/carets (including newly visible text in one- and two-cell columns).
+
+The isolated 9P harness `test/collapse_layout.py` passes seven collapse/expand
+pairs on each host, checking rendered tag boundaries and unchanged contents.
+The live OS gallery checks all fifteen native themes for bold current-line
+numbers, unchanged gutter backgrounds and no active-tag polarity inversion.
+Both hosts pass all twelve column input checks, including first-cell execution,
+editing and caret reveal. Agave source bytes stay unchanged and no input is
+sent to the user's session.
+
+- [Six contrast studies, OS screenshot crops](screenshots/theme-preferences.png)
+- [Neutral Forge, full workspace](screenshots/theme-preferences-forge.png)
+- [Native-first ThemeSel, full workspace](screenshots/theme-selector.png)
+
+## Compact rails, classic palettes and workspace pets
+
+`New` now belongs to column tags only. Pane tags keep their local save,
+terminal and close actions: `Tty` opens a terminal, and `Togglettymode`
+switches editor/raw input using the same transition as Ctrl-B. Historical
+default pane tails upgrade during Restore; explicitly customized text remains
+owned by the user.
+
+SDL paints adjacent tag backgrounds to their full row height, leaving only
+the thin separator. Square scroll markers share the column's left edge, and
+a one-pixel continuous line joins its column tag, pane tags and bodies.
+Pointer targets and the TTY grid are unchanged.
+
+`Font MartianMono-NrRg:18` now applies both face and size. The isolated
+`test/font_size.py` checks startup sizing, fractional sizing, retaining the
+size when omitted, and rejecting invalid requests without partial changes.
+
+Six [classic-inspired themes](themes.md) add `forge`, `lagoon`, `solarium`,
+`spectrum`, `harvest` and `clay`. ANSI colors retain their terminal meanings
+instead of borrowing a similarly positioned syntax color. Optional SDL
+`Pet cat` and `Pet frog` companions walk, idle and reverse in the unused
+workspace tag; `Pet off` is the default. Editing that tag hides the pet.
+The original pixel sprites use no external assets or input handlers.
+
+`test/appearance_gallery.py` recreates a two-column Agave review with stacked
+right-hand panes, an embedded terminal, Font 18 and TaglineSize 80. It checks
+all six new themes, font and pet reports, changing pet frames, and unchanged
+Agave source bytes. Its `--live-window` mode captures the owned SDL window
+through the OS, identified by its child PID. It never resizes or sends input
+to the user's existing Pardes window.
+
+- [Compact columns, native OS capture](screenshots/compact-columns.png)
+- [Six classic adaptations, screenshot contact sheet](screenshots/classic-themes.png)
+- [Cat and frog, enlarged nearest-neighbor screenshot crops](screenshots/pets.png)
+- [Gallery checks](screenshots/classic-gallery.json)
+
+The full suites passed 807 SDL and 776 TTY tests, with one skipped in each;
+all 97 interaction snapshots passed. A private mount namespace redirected
+test-only `/tmp` writes after the host's temporary-file quota was exhausted,
+without deleting files or changing the user's `/tmp`. These counts include
+the pet/geometry/font/command changes; palette corrections additionally pass
+the native contrast tests.
+
+## PDF and terminal tag cleanup
+
+PDFs now use `filename.pdf [page/total] Tty Del PdfSections PdfTint Collapse`,
+keeping sections and tint commands visible without the long generated
+control/status prefix. Terminal tags add `Togglettymode`, sharing Ctrl-B's actual mode
+transition, including when invoked from an edited tag.
+
+`test/tag_cleanup.py` verifies the compact PDF tag, middle-click `Togglettymode`, Ctrl-B,
+and tag-edit/Tab execution through real host input and 9P observations on both
+SDL and TTY. The PDF source stays unchanged. The full unit suites pass 773 TTY
+tests and 797 SDL tests; SDL image/PDF and Kitty PDF rendering harnesses pass.
+
+[Native PDF and terminal screenshot](screenshots/pdf-and-tty-tags.png).
+
+## Column and editable-tag follow-up
+
+The follow-up adds editable workspace and column command rows, compact pane
+tags, staged buffer-name edits, caret reveal for long tags, and `ColumnTags`
+to reclaim the extra row when needed. See [editable tags](tags.md) for the
+exact interaction and save-target rules.
+
+`test/column_tags.py` exercises isolated SDL and TTY sessions against the same
+Agave source. It sends actual host input bytes while observing through 9P:
+header typing and selection replacement, UTF-8 deletion, inactive-column
+`New`/`Tty`, pane-tail edits, filename cancellation, terminal input, and
+custom-tag Dump/Restore. Source bytes remain unchanged. Input goes through
+the host PTY parser; compact SDL pixel coordinates are covered separately by
+round-trip mapping tests, not claimed as physical SDL mouse automation.
+All 11 live checks passed on each frontend. All 7,200 foreground/background
+cells and 48 text rows matched for the three final frames after normalizing
+only the isolated `ct-sdl`/`ct-tty` directory names.
+
+The screenshots below are native GPU captures, after removing test-only
+Unicode markers through normal tag editing. The tested CJK text has correct
+grid/editing behavior, but the selected font lacks its glyph; this is not
+claimed as complete font-fallback coverage.
+
+- [Two-column Orchard workspace](screenshots/columns-orchard.png)
+- [Two-column Atelier workspace](screenshots/columns-atelier.png)
+- [Long tag revealing its actions and caret](screenshots/columns-tag-reveal.png)
+- [Final SDL/TTY parity evidence](screenshots/columns-parity.json)
+
+The final unit suites passed 771 TTY tests and 795 SDL tests. Native image and PDF harnesses
+passed, including continuous PDF layout and reload. The PDF fixture gains one
+screen row to preserve its original document area; its pixel assertions are
+unchanged.
+
+Existing terminal snapshots were migrated by adding one screen row and moving
+pane mouse coordinates down one row, preserving their original body area.
+Raw SGR mouse sequences were migrated too. The tag-padding/name/navigation
+fixtures were explicitly rewritten for the new behavior. Review found 86
+fixtures with identical text tokens after removing the new column row and
+normalizing spacing; the remaining differences were reviewed for tag edits,
+nested editor chrome, resize handles, and debug overlays. All 97 scripts
+passed both when regenerating the reviewed goldens and in a subsequent
+independent run with retries disabled.
+
+## Initial palette pass
+
+The UI pass was exercised against Agave's real `gossip/src/crds_value.rs`,
+using isolated named Pardes sessions and the existing Python 9P client.
+The workflow opened Find and Grep results, ran harmless commands in an
+embedded terminal, requested Rust document symbols and hover, and sent `gd`
+through the host's actual terminal input parser. Agave source bytes were
+checked unchanged after the session.
+
+Native SDL screenshots use the GPU capture path. TTY captures contain the
+real core grid and its styles; they are not screenshots of an independent
+terminal emulator. Resolving cells to their grapheme, foreground and
+background yielded **7,200 of 7,200 matching cells** at 150 × 48 for each of
+`orchard`, `dusk`, `ink`, `paper`, `daybreak`, and `atelier`.
+
+Rust-analyzer returned 52 document-symbol rows and one definition result.
+The initial baseline hover timed out; the updated run returned no hover
+text for the declaration. No hover popup is claimed as verified. Agave's
+gossip crate is feature-gated, and workspace loading was still substantial;
+the exact cause of that empty result was not established.
+
+## Reproduce
+
+Run from the Pardes checkout, using an existing SDL binary and an Agave
+checkout. The output directory is private and also holds isolated startup
+configuration. ImageMagick and an X11 display are required for PNG captures;
+the LSP pass additionally needs rust-analyzer (located through rustup unless
+`--rust-analyzer` is supplied).
+
+```sh
+python3 -B test/ui_review.py zig-out/ui-review/bin/pardes-gui \
+ /tmp/pardes-ui-review --project /path/to/agave \
+ --theme orchard --themes orchard dusk ink paper daybreak atelier
+```
+
+For subsequent palette captures, add `--skip-lsp`. To repeat LSP work without
+rebuilding dependencies, use `--cargo-target /path/to/previous/cargo-target`.
+Cargo runs offline and stores build output in that isolated directory.
+For the TTY pass, use the TTY binary and add `--tty`. The script requires
+Find/Grep results and observed terminal output, fails missing or malformed
+SDL captures, and writes `report.json` with the actual outcomes. LSP absence
+or failure is recorded separately rather than passing as a successful popup.
+
+Review artifacts from this pass:
+
+- [Baseline workspace](screenshots/before.png)
+- [Orchard: mild dark](screenshots/orchard.png)
+- [Dusk: warm dark](screenshots/dusk.png)
+- [Ink: high contrast dark](screenshots/ink.png)
+- [Paper: mild light](screenshots/paper.png)
+- [Daybreak: high contrast light](screenshots/daybreak.png)
+- [Atelier: Acme homage](screenshots/atelier.png)
+- [Cell parity evidence](screenshots/parity.json)
+- [Actual Rust LSP responses](screenshots/agave-lsp.txt)
+
+![Orchard with Agave source, terminal and search](screenshots/orchard.png)
+
+## Regression checks
+
+Both native binaries built in ReleaseFast. The full TTY and SDL unit suites
+passed with the inherited nesting variables `PARDES_FORWARD_LOOK`, `PARDES_9P`
+and `PARDES_PANE` removed from the test process. Those variables exposed an
+existing environment-ownership issue in native subprocess tests: libc's
+environment was changed while the Zig test I/O retained the old slice. This
+pass does not change that environment code or skip the affected tests.
+
+The appearance checks cover native palette contrast, old ThemeFile documents,
+wrapped search matches, selection precedence, immediate body colors during
+theme fades, light-theme carets and both quiet and bold syntax preferences.
+The 9P walkthrough also verifies `FocusTint` and `SyntaxBold` through `Config`.
+
+All 97 terminal snapshot scripts passed without retries after reviewing and
+refreshing 32 appearance goldens. Of those, 27 preserve identical visible text,
+cursor positions and grid geometry; the remaining five contain the new default
+theme name or the expanded theme list. SDL image and PDF harnesses also passed,
+including continuous PDF layout and idle document reload. The PDF color fixture
+explicitly selects legacy `helix` to preserve its fixed pixel expectations.
+
+## Possible interaction follow-ups
+
+These were not needed for the appearance pass:
+
+- A way to reveal an abbreviated pane path on demand could recover title
+ space in deep workspaces. The full path should remain selectable and
+ available to Look; replacing it outright would weaken an existing workflow.
+- Show a query's busy state until its response arrives, and distinguish an
+ empty answer from a timeout. The first full-workspace Rust hover provided
+ little visible feedback while indexing; explicit status would tell users
+ whether to wait or change their selection. This needs clear cancellation
+ and stale-response behavior before changing the interaction.
diff --git a/src/builtins.zig b/src/builtins.zig
index e55a418f..9208b9f8 100644
--- a/src/builtins.zig
+++ b/src/builtins.zig
@@ -436,6 +436,20 @@ pub const Filter = struct {
}
};
+/// Switch this terminal between raw program input and normal editor mode.
+pub const Togglettymode = struct {
+ pub fn run(c: Ctx) void {
+ c.p.toggleTty(c.id);
+ }
+};
+
+/// Fold a pane to its tag, or restore its share of the column.
+pub const Collapse = struct {
+ pub fn run(c: Ctx) void {
+ layout.toggleCollapse(c.p, c.id);
+ }
+};
+
pub const Delcol = struct {
pub fn run(c: Ctx) void {
c.p.removeColumn(c.id) catch |err| c.p.reportError(c.id, "close column", err);
@@ -444,7 +458,7 @@ pub const Delcol = struct {
/// A shell in the calling pane's directory, raw from the first frame. On every
/// pane's tagline: the fast path from wherever you are to a prompt there.
-pub const Newtty = struct {
+pub const Tty = struct {
pub fn run(c: Ctx) void {
c.p.spawnTty(c.id);
}
@@ -509,6 +523,16 @@ pub const EffectCode = struct {
}
};
+/// An optional SDL workspace-tag companion; never consumes input or text cells.
+pub const Pet = struct {
+ pub const takes_arg = true;
+ pub const enabled = pardes.platform == .gui;
+ pub fn run(c: Ctx) void {
+ const name = std.mem.trim(u8, c.arg orelse return, " \t\r\n");
+ c.p.settings.pet = std.meta.stringToEnum(@TypeOf(c.p.settings.pet), name) orelse return;
+ }
+};
+
pub const Mini = struct {
pub const takes_arg = true;
pub const output: OutputTraits = .{ .name = "Mini", .doc = true };
diff --git a/src/config.zig b/src/config.zig
index 5dcfef01..282e63da 100644
--- a/src/config.zig
+++ b/src/config.zig
@@ -43,6 +43,8 @@ pub const leader_path = paths: {
.Subtypes = "lT",
.Del = "d",
.Filter = null,
+ .Togglettymode = null,
+ .Collapse = null,
.Kill = null,
.ClipYank = "y",
.ClipYankMain = "Y",
@@ -51,7 +53,7 @@ pub const leader_path = paths: {
.ClipReplace = "R",
.Save = "fs",
.New = "fn",
- .Newtty = "nt",
+ .Tty = "nt",
.Find = "ff",
.Grep = "fg",
.Config = "fc",
@@ -64,6 +66,9 @@ pub const leader_path = paths: {
.Debug = "td",
.Msg = null,
.Colors = "tc",
+ .FocusTint = null,
+ .ColumnTags = null,
+ .SyntaxBold = null,
.Wrap = "tw",
.Tagbottom = "tb",
.NextColor = "tn",
@@ -92,6 +97,7 @@ pub const leader_path = paths: {
table.set(.Font, null);
table.set(.TaglineSize, null);
}
+ if (pardes.platform == .gui) table.set(.Pet, null);
if (builtins.capabilities.panel_transitions) {
table.set(.PanelSlide, "as");
table.set(.PanelZoom, "az");
@@ -215,13 +221,12 @@ pub const tty_blank: enum { prompt, prompt_and_input } = .prompt;
// Projected colors below this contrast use the theme's more legible anchor.
pub const tty_filter_min_contrast: f64 = 1.5;
-pub const topbar_str = "New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill";
+pub const topbar_str = "Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill";
-pub const pane_builtins_str = "New Newtty Del";
-pub const file_pane_builtins_str = "Save New Newtty Del";
-pub const terminal_pane_builtins_str = "Save New Newtty Del Filter";
-
-pub const tag_right_pad: u16 = 20;
+pub const pane_builtins_str = "Tty Del Collapse";
+pub const pdf_pane_builtins_str = "Tty Del PdfSections PdfTint Collapse";
+pub const file_pane_builtins_str = "Save Tty Del Collapse";
+pub const terminal_pane_builtins_str = "Save Tty Del Togglettymode Filter Collapse";
// Each mode badge is one codepoint.
pub const tag_normal = " ";
@@ -529,6 +534,10 @@ pub const Runtime = struct {
wrap: bool = true,
tag_bottom: bool = false,
debug: bool = false,
+ focus_tint: bool = true,
+ column_tags: bool = true,
+ syntax_bold: bool = false,
+ pet: enum { off, cat, frog } = .off,
// Effective values change only after a host acknowledges the request.
shell: struct {
@@ -540,6 +549,7 @@ pub const Runtime = struct {
font: struct {
requested_path: Text(limits.host_path_cap) = .{},
requested_name: Text(255) = .{},
+ requested_size_hundredths: u16 = 0, // zero preserves the renderer's current size
effective_name: Text(255) = .{},
pending: bool = false,
effective_size_hundredths: u16 = 0,
@@ -582,12 +592,30 @@ pub const Runtime = struct {
pub const FontSizeUnit = enum { unknown, pixels, points };
- // Validate both strings before changing either member of the request.
- pub fn requestFont(state: *Runtime, path: []const u8, name: []const u8) bool {
+ pub const FontSpec = struct {
+ name: []const u8,
+ size_hundredths: u16 = 0,
+
+ pub fn parse(argument: []const u8) ?FontSpec {
+ const text = std.mem.trim(u8, argument, " \t\r\n");
+ if (text.len == 0) return null;
+ const colon = std.mem.indexOfScalar(u8, text, ':') orelse return .{ .name = text };
+ const name = std.mem.trim(u8, text[0..colon], " \t");
+ if (name.len == 0) return null;
+ const size = std.fmt.parseFloat(f32, text[colon + 1 ..]) catch return null;
+ if (!std.math.isFinite(size) or size < 8 or size > 72) return null;
+ return .{ .name = name, .size_hundredths = @intFromFloat(@round(size * 100)) };
+ }
+ };
+
+ // Validate the complete request before changing any member.
+ pub fn requestFont(state: *Runtime, path: []const u8, name: []const u8, size_hundredths: u16) bool {
if (path.len > state.font.requested_path.bytes.len or
name.len > state.font.requested_name.bytes.len) return false;
+ if (size_hundredths != 0 and (size_hundredths < 800 or size_hundredths > 7200)) return false;
std.debug.assert(state.font.requested_path.set(path));
std.debug.assert(state.font.requested_name.set(name));
+ state.font.requested_size_hundredths = size_hundredths;
state.font.pending = true;
return true;
}
@@ -601,7 +629,7 @@ pub const Runtime = struct {
pub const Capability = std.meta.FieldEnum(Capabilities);
- pub const Toggle = enum { colors, wrap, tag_bottom, debug };
+ pub const Toggle = enum { colors, wrap, tag_bottom, debug, focus_tint, column_tags, syntax_bold };
pub const Scene = std.meta.FieldEnum(layout.SceneEffect);
pub const Action = union(enum) {
@@ -640,6 +668,9 @@ pub const Runtime = struct {
.{ .word = "Wrap", .action = .{ .toggle = .wrap } },
.{ .word = "Tagbottom", .action = .{ .toggle = .tag_bottom } },
.{ .word = "Debug", .action = .{ .toggle = .debug } },
+ .{ .word = "FocusTint", .action = .{ .toggle = .focus_tint } },
+ .{ .word = "ColumnTags", .action = .{ .toggle = .column_tags } },
+ .{ .word = "SyntaxBold", .action = .{ .toggle = .syntax_bold } },
.{ .word = "Theme", .action = .theme },
.{ .word = "Shell", .action = .shell },
.{ .word = "Font", .action = .font, .availability = .font_picker },
@@ -718,6 +749,9 @@ pub const Runtime = struct {
.wrap => state.wrap = !state.wrap,
.tag_bottom => state.tag_bottom = !state.tag_bottom,
.debug => state.debug = !state.debug,
+ .focus_tint => state.focus_tint = !state.focus_tint,
+ .column_tags => state.column_tags = !state.column_tags,
+ .syntax_bold => state.syntax_bold = !state.syntax_bold,
},
.shell => {
const value = std.mem.trim(u8, argument orelse return false, " \t\r\n");
@@ -778,6 +812,9 @@ pub const Runtime = struct {
.wrap => state.wrap,
.tag_bottom => state.tag_bottom,
.debug => state.debug,
+ .focus_tint => state.focus_tint,
+ .column_tags => state.column_tags,
+ .syntax_bold => state.syntax_bold,
};
try out.print("{s}: {s}\n", .{ setting.word, onOff(value) });
},
@@ -801,7 +838,11 @@ pub const Runtime = struct {
},
.font => if (!setting.enabled(context.capabilities))
try out.print("{s}: unsupported\n", .{setting.word})
- else
+ else {
+ if (state.font.requested_size_hundredths == 0)
+ try out.print("{s} requested size: unchanged\n", .{setting.word})
+ else
+ try out.print("{s} requested size: {d}.{d:0>2}\n", .{ setting.word, state.font.requested_size_hundredths / 100, state.font.requested_size_hundredths % 100 });
try out.print(
"{s} requested: {s}\n" ++
"{s} requested path: {s}\n" ++
@@ -822,7 +863,8 @@ pub const Runtime = struct {
state.font.effective_size_hundredths % 100,
@tagName(state.font.effective_size_unit),
},
- ),
+ );
+ },
.tagline_size => if (!context.capabilities.tagline_font_size)
try out.print("{s}: unsupported\n", .{setting.word})
else if (!setting.enabled(context.capabilities))
@@ -865,6 +907,8 @@ pub const Runtime = struct {
else
try out.writeAll("Look hover delay: off\n");
try out.print("Native images: {s}\n", .{onOff(context.native_images)});
+ if (std.mem.eql(u8, context.platform, "gui"))
+ try out.print("Pet: {s}\n", .{@tagName(state.pet)});
}
test "setting names are unique and argument metadata follows actions" {
@@ -912,11 +956,26 @@ pub const Runtime = struct {
test "font request tuple rejects atomically" {
var state: Runtime = .{};
- try std.testing.expect(requestFont(&state, "/fonts/old.ttf", "Old"));
+ try std.testing.expect(requestFont(&state, "/fonts/old.ttf", "Old", 1200));
var too_long: [256]u8 = @splat('x');
- try std.testing.expect(!requestFont(&state, "/fonts/new.ttf", &too_long));
+ try std.testing.expect(!requestFont(&state, "/fonts/new.ttf", &too_long, 1800));
+ try std.testing.expect(!requestFont(&state, "/fonts/new.ttf", "New", 799));
try std.testing.expectEqualStrings("/fonts/old.ttf", state.font.requested_path.get());
try std.testing.expectEqualStrings("Old", state.font.requested_name.get());
+ try std.testing.expectEqual(@as(u16, 1200), state.font.requested_size_hundredths);
+ }
+
+ test "font specification accepts optional size and rejects invalid suffixes" {
+ const plain = FontSpec.parse(" Example Mono ").?;
+ try std.testing.expectEqualStrings("Example Mono", plain.name);
+ try std.testing.expectEqual(@as(u16, 0), plain.size_hundredths);
+ const sized = FontSpec.parse("Example Mono:12.5").?;
+ try std.testing.expectEqualStrings("Example Mono", sized.name);
+ try std.testing.expectEqual(@as(u16, 1250), sized.size_hundredths);
+ try std.testing.expectEqual(@as(u16, 800), FontSpec.parse("Mono:8").?.size_hundredths);
+ try std.testing.expectEqual(@as(u16, 7200), FontSpec.parse("Mono:72").?.size_hundredths);
+ for ([_][]const u8{ "", ":12", "Mono:", "Mono:abc", "Mono:0", "Mono:-12", "Mono:7.99", "Mono:72.01", "Mono:nan", "Mono:inf", "Mono:12:13" }) |bad|
+ try std.testing.expect(FontSpec.parse(bad) == null);
}
test "Config report observes every simple setting and all live context" {
@@ -960,6 +1019,9 @@ pub const Runtime = struct {
.wrap => "Wrap: off\n",
.tag_bottom => "Tagbottom: on\n",
.debug => "Debug: on\n",
+ .focus_tint => "FocusTint: off\n",
+ .column_tags => "ColumnTags: off\n",
+ .syntax_bold => "SyntaxBold: on\n",
},
.shell => "Shell requested (new panes): fish\n",
.tagline_size => "TaglineSize: 73%\n",
@@ -989,6 +1051,7 @@ pub const Runtime = struct {
try std.testing.expect(state.font.requested_name.set("Wanted Mono"));
try std.testing.expect(state.font.requested_path.set("/fonts/wanted.ttf"));
+ state.font.requested_size_hundredths = 1850;
try std.testing.expect(state.font.effective_name.set("Effective Mono"));
state.font.pending = true;
state.font.effective_size_hundredths = 1375;
@@ -1000,6 +1063,7 @@ pub const Runtime = struct {
const report = storage[0..out.end];
for ([_][]const u8{
"Theme: acme\n",
+ "Font requested size: 18.50\n",
"Font requested: Wanted Mono\n",
"Font requested path: /fonts/wanted.ttf\n",
"Font effective: Effective Mono\n",
diff --git a/src/dump.zig b/src/dump.zig
index 93bf08cc..ff46205f 100644
--- a/src/dump.zig
+++ b/src/dump.zig
@@ -109,6 +109,7 @@ pub const Pane = struct {
cols: u16 = 0,
rows: u16 = 0,
vweight: f32 = 1,
+ collapsed: bool = false,
/// Exact editable tail when the user touched it. Null retains the live
/// default; a present empty slice deliberately restores an empty tail.
tag_tail: ?[]const u8 = null,
@@ -118,6 +119,7 @@ pub const Pane = struct {
};
pub const Column = struct {
+ tag: ?[]const u8 = null,
weight: f32 = 1,
panes: []const usize = &.{},
};
@@ -130,13 +132,20 @@ pub const State = struct {
screen: Size,
active: usize = 0,
topbar: []const u8 = "",
+ topbar_custom: ?[]const u8 = null,
theme: []const u8 = "dark",
columns: []const Column = &.{},
panes: []const Pane = &.{},
mounts: []const Mount = &.{},
};
+fn validateTag(bar: []const u8) !void {
+ if (bar.len > limits.max_tag_tail or std.mem.indexOfAny(u8, bar, "\r\n\x00") != null or !std.unicode.utf8ValidateSlice(bar)) return error.BadDumpTag;
+}
+
pub fn validate(state: State) !void {
+ if (state.topbar_custom) |bar| try validateTag(bar);
+ for (state.columns) |column| if (column.tag) |bar| try validateTag(bar);
if (!std.mem.eql(u8, state.magic, magic)) return error.BadDumpMagic;
if (state.version != version) return error.BadDumpVersion;
if (state.panes.len == 0 or state.panes.len > max_panes) return error.BadDumpPanes;
diff --git a/src/fs.zig b/src/fs.zig
index 50b56f76..63d2ed3a 100644
--- a/src/fs.zig
+++ b/src/fs.zig
@@ -2911,6 +2911,36 @@ fn writeCtl(p: *Pardes, req: Req, serial: u32) Reply {
return .{ .tag = req.tag, .written = @intCast(req.data.len) };
}
+/// Change a buffer's absolute name without writing or renaming a disk file.
+/// Tag editing preserves user commands; the 9P name operation resets its tail.
+pub fn nameBuffer(p: *Pardes, id: usize, full: []const u8, preserve_tag: bool) !void {
+ const pane = p.panes[id] orelse return error.NoPane;
+ const f = fileOf(pane) orelse return error.NotFile;
+ if (!std.fs.path.isAbsolute(full) or full.len == 0 or full.len >= 4096)
+ return error.InvalidName;
+ for (full) |c| if (c < ' ') return error.InvalidName;
+ if (std.mem.eql(u8, f.path, full)) return;
+ const copy = try p.gpa.dupe(u8, full);
+ p.gpa.free(f.path);
+ f.path = copy;
+ if (panes.Output.fileTraits(f.output).saves) {
+ f.output = null;
+ pane.clearCwd();
+ if (!preserve_tag) {
+ pane.tag_init = false;
+ pane.tag_tail_len = 0;
+ }
+ f.saved_revision = f.revision -% 1;
+ f.watch_after_save = localPath(full) != null;
+ }
+ if (f.highlights.len > 0) p.tree_sitter_gpa.free(f.highlights);
+ f.highlights = &.{};
+ f.highlight_start = 0;
+ f.syntax_dirty = true;
+ p.invalidateLookHover(id);
+ p.emit(.{ .watch = .{ .pane = @intCast(id), .on = false } });
+}
+
fn ctlVerb(p: *Pardes, id: usize, line: []const u8, apply: bool, dirty: *bool) u16 {
const pane = p.panes[id] orelse return E.INVAL;
const pf = &p.fs.panes[id];
@@ -2935,23 +2965,7 @@ fn ctlVerb(p: *Pardes, id: usize, line: []const u8, apply: bool, dirty: *bool) u
if (std.mem.eql(u8, f.path, full)) return 0;
if (panes.Output.fileTraits(f.output).saves) dirty.* = true;
if (!apply) return 0;
- const copy = p.gpa.dupe(u8, full) catch return E.NOMEM;
- p.gpa.free(f.path);
- f.path = copy;
- if (panes.Output.fileTraits(f.output).saves) {
- f.output = null;
- pane.clearCwd();
- pane.tag_init = false;
- pane.tag_tail_len = 0;
- f.saved_revision = f.revision -% 1;
- f.watch_after_save = localPath(full) != null;
- }
- if (f.highlights.len > 0) p.tree_sitter_gpa.free(f.highlights);
- f.highlights = &.{};
- f.highlight_start = 0;
- f.syntax_dirty = true;
- p.invalidateLookHover(id);
- p.emit(.{ .watch = .{ .pane = @intCast(id), .on = false } });
+ nameBuffer(p, id, full, false) catch return E.NOMEM;
return 0;
}
for (refused_verbs) |w| if (verbIs(line, w)) return E.INVAL;
@@ -3711,7 +3725,8 @@ test "index prints winctlprint's five fields then the tag" {
@memcpy(got[0..a.bytes.len], a.bytes);
const line = got[0..a.bytes.len];
- const tag = tagOf(p, pane);
+ const tag = try gpa.dupe(u8, tagOf(p, pane));
+ defer gpa.free(tag);
var want: std.ArrayList(u8) = .empty;
defer want.deinit(gpa);
try want.print(gpa, "{d:>11} {d:>11} {d:>11} {d:>11} {d:>11} {s}\n", .{
diff --git a/src/gui/gui.zig b/src/gui/gui.zig
index f7b9fc7e..0b2bdd18 100644
--- a/src/gui/gui.zig
+++ b/src/gui/gui.zig
@@ -12,6 +12,7 @@ const message = pardes.Pardes.Message;
const file_watch = @import("../file_watch.zig");
const deck = @import("deck.zig");
const crt = @import("crt.zig");
+const pet = @import("pet.zig");
const fonts = @import("../fonts.zig"); // the Font builtin's half of the seam
const selection_pipe = @import("../selection_pipe.zig");
@@ -82,6 +83,22 @@ const Slot = struct { u: u32, v: u32 };
const GlyphKey = struct {
codepoint: u32,
role: pardes.FontRole,
+ decoration: GlyphDecoration = .{},
+};
+
+const GlyphDecoration = struct {
+ bold: bool = false,
+ underline: @FieldType(pardes.CellStyle, "ul") = .off,
+ strikethrough: bool = false,
+
+ fn fromCell(cell: *const pardes.Cell) GlyphDecoration {
+ if (cell.default or cell.style.invisible) return .{};
+ return .{ .bold = cell.style.bold, .underline = cell.style.ul, .strikethrough = cell.style.strikethrough };
+ }
+
+ fn drawsBlank(decoration: GlyphDecoration) bool {
+ return decoration.underline != .off or decoration.strikethrough;
+ }
};
const TaglineRaster = struct {
@@ -191,7 +208,9 @@ test "a persistent scene presents a new panel's frame zero before advancing it"
for (second.panelTracks()) |track| try std.testing.expectEqual(@as(u16, 1), track.frame);
}
-const max_overlay_vertices: usize = 18 + touch_click_flash_vertices + max_touch_points * (1100 + max_touch_trail_points * overlay_circle_vertices);
+// Per pane: background, rule, two grip strokes, and two square rails.
+const pane_chrome_vertices: usize = 6 * 6;
+const max_overlay_vertices: usize = 24 + pet.max_vertices + pardes.MAX_COLS * 6 + pardes.MAX_PANES * pane_chrome_vertices + touch_click_flash_vertices + max_touch_points * (1100 + max_touch_trail_points * overlay_circle_vertices);
const font_px_step: f32 = 2.0;
const font_px_min: f32 = 8.0;
@@ -238,15 +257,25 @@ test "FreeType atlas raster is grayscale, bounded, and clears blank cells" {
var ink: usize = 0;
var soft: usize = 0;
+ var regular_coverage: usize = 0;
for (0..@intCast(cell_h)) |y| {
for (0..@intCast(cell_w)) |x| {
const coverage = bitmap[y * @as(usize, @intCast(stride)) + x];
if (coverage > 0) ink += 1;
if (coverage > 0 and coverage < 255) soft += 1;
+ regular_coverage += coverage;
}
}
try std.testing.expect(ink > 0);
try std.testing.expect(soft > 0);
+ decorateGlyph(&bitmap, @intCast(stride), @intCast(cell_w), @intCast(cell_h), ascent, .{ .bold = true });
+ var bold_coverage: usize = 0;
+ for (0..@intCast(cell_h)) |y| {
+ for (0..@intCast(cell_w)) |x| bold_coverage += bitmap[y * @as(usize, @intCast(stride)) + x];
+ for (bitmap[y * @as(usize, @intCast(stride)) + @as(usize, @intCast(cell_w)) ..][0..@intCast(stride - cell_w)]) |guard|
+ try std.testing.expectEqual(@as(u8, 0xaa), guard);
+ }
+ try std.testing.expect(bold_coverage > regular_coverage);
try std.testing.expectEqual(
@as(c_int, 0),
@@ -353,7 +382,8 @@ test "glyph atlas cache separates body and tagline roles" {
defer glyphs.deinit();
try glyphs.put(.{ .codepoint = 'A', .role = .body }, .{ .u = 0, .v = 0 });
try glyphs.put(.{ .codepoint = 'A', .role = .tagline }, .{ .u = 10, .v = 0 });
- try std.testing.expectEqual(@as(usize, 2), glyphs.count());
+ try glyphs.put(.{ .codepoint = 'A', .role = .body, .decoration = .{ .bold = true } }, .{ .u = 20, .v = 0 });
+ try std.testing.expectEqual(@as(usize, 3), glyphs.count());
try std.testing.expectEqual(@as(u32, 0), glyphs.get(.{ .codepoint = 'A', .role = .body }).?.u);
try std.testing.expectEqual(@as(u32, 10), glyphs.get(.{ .codepoint = 'A', .role = .tagline }).?.u);
}
@@ -1735,6 +1765,7 @@ const Gui = struct {
space_slot: Slot = .{ .u = 0, .v = 0 },
touch: Touch = .{},
+ pet_state: pet.State = .{},
live_ctrl: bool = false,
live_alt: bool = false,
@@ -3674,6 +3705,8 @@ fn pollFrame(ctx: ?*anyopaque) void {
if (g.font_bytes.len != 0) s.gpa.free(g.font_bytes);
g.font = nf;
g.font_bytes = bytes; // FreeType borrows them for the face lifetime
+ if (core.settings.font.requested_size_hundredths != 0)
+ g.px = @as(f32, @floatFromInt(core.settings.font.requested_size_hundredths)) / 100;
setGuiFontName(g, core.settings.font.requested_name.get());
refitFont(g, core);
acknowledgeGuiFont(g, core);
@@ -3699,7 +3732,7 @@ fn present(ctx: ?*anyopaque, surface: *const pardes.Surface) void {
core,
frame,
core.theme().bg,
- config.gui_topbar_pane_border_rgb orelse core.chromeTheme().scroll_track,
+ config.gui_topbar_pane_border_rgb orelse core.chromeTheme().border,
core.chromeTheme().tag_bg,
core.settings.scene_effects,
core.settings.debug,
@@ -5065,8 +5098,9 @@ fn resolveCell(g: *Gui, cell: *const pardes.Cell, role: pardes.FontRole, is_curs
}
const cp = if (blank) ' ' else cellCodepoint(cell);
+ const decoration = GlyphDecoration.fromCell(cell);
return .{
- .slot = if (cp == ' ') g.space_slot else ensureGlyph(g, cp, role),
+ .slot = if (cp == ' ' and !decoration.drawsBlank()) g.space_slot else ensureGlyph(g, cp, role, decoration),
.fg = fg,
.bg = bg,
.role = role,
@@ -5088,6 +5122,39 @@ fn cellInstanceCount(core: ?*const pardes.Pardes, cell: *const pardes.Cell, row:
return if (drawnFontRole(core, cell, row) == .tagline) 2 else 1;
}
+fn taglineBaseRgb(core: *const pardes.Pardes, col: u16, row: u16) [3]u8 {
+ const chrome = core.chromeTheme();
+ if (!core.settings.focus_tint) return chrome.tag_bg;
+ if (row >= pardes.TOPBAR_H and row < pardes.TOPBAR_H + core.columnBarHeight()) {
+ for (0..core.ncol) |column| for (core.col_panes[column][0..core.col_n[column]]) |id| {
+ if (id != core.active) continue;
+ const x = core.col_x[column];
+ if (col >= x and col - x < core.col_w[column]) return chrome.tag_active_bg;
+ };
+ }
+ const r = core.rects[core.active];
+ const tag_y = if (core.settings.tag_bottom) r.y + r.h -| pardes.BOX_H else r.y;
+ return if (r.h > 0 and row == tag_y and col >= r.x and col - r.x < r.w) chrome.tag_active_bg else chrome.tag_bg;
+}
+
+test "compact column and pane underlays share focus tint without tinting the global tag" {
+ const core = try pardes.Pardes.init(std.testing.allocator, .{ .cols = 120, .rows = 24 });
+ defer core.deinit();
+ _ = try core.newShell(1, "");
+ try std.testing.expect(pardes.layout.splitColumn(core, 0, 1, false));
+ pardes.test_api.sync(core);
+ core.active = 1;
+ const active = core.rects[1];
+ const inactive = core.rects[0];
+ const chrome = core.chromeTheme();
+ try std.testing.expectEqual(chrome.tag_bg, taglineBaseRgb(core, active.x, 0));
+ try std.testing.expectEqual(chrome.tag_active_bg, taglineBaseRgb(core, active.x, pardes.TOPBAR_H));
+ try std.testing.expectEqual(chrome.tag_bg, taglineBaseRgb(core, inactive.x, pardes.TOPBAR_H));
+ try std.testing.expectEqual(chrome.tag_active_bg, taglineBaseRgb(core, active.x, active.y));
+ core.settings.focus_tint = false;
+ try std.testing.expectEqual(chrome.tag_bg, taglineBaseRgb(core, active.x, pardes.TOPBAR_H));
+}
+
fn emitSurfaceCell(
g: *Gui,
core: ?*const pardes.Pardes,
@@ -5107,7 +5174,12 @@ fn emitSurfaceCell(
) void {
const role = drawnFontRole(core, cell, row);
if (role == .tagline) {
- emitInstance(g, instances, next.*, col, row, body_layout, win_w, win_h, track, .tagline, tagline_base, old_layer, false, page);
+ var band_base = tagline_base.*;
+ if (core) |p| band_base.style.bg = .{ .rgb = taglineBaseRgb(p, col, row) };
+ // The smaller font changes the ink, not the chrome's coverage. Painting
+ // this underlay at tagline height leaves page-colored gutters between
+ // adjacent workspace, column and pane tags at TaglineSize < 100.
+ emitInstance(g, instances, next.*, col, row, body_layout, win_w, win_h, track, .body, &band_base, old_layer, false, page);
next.* += 1;
const tag_layout = taglineLayoutForCell(g, core, col, row, track);
emitInstance(g, instances, next.*, col, row, tag_layout, win_w, win_h, track, .tagline, cell, old_layer, is_cursor, page);
@@ -5118,6 +5190,29 @@ fn emitSurfaceCell(
next.* += 1;
}
+test "small tagline fonts leave no background gutters between adjacent tags" {
+ const core = try pardes.Pardes.init(std.testing.allocator, .{ .cols = 80, .rows = 24 });
+ defer core.deinit();
+ var g: Gui = undefined;
+ g.cell_w = 10;
+ g.cell_h = 20;
+ g.tagline_width = 8;
+ g.tagline_height = 16;
+ g.space_slot = .{ .u = 0, .v = 0 };
+ const cell: pardes.Cell = .{ .default = false, .style = .{ .font_role = .tagline } };
+ var instances: [6]CellInstance = undefined;
+ var next: u32 = 0;
+ for (0..3) |row| {
+ emitSurfaceCell(&g, core, &instances, &next, 0, @intCast(row), fixedCellLayout(&g), 800, 480, null, &cell, &cell, false, false, Ground.opaqueRgb(bg_default));
+ const base = instances[row * 2];
+ const ink = instances[row * 2 + 1];
+ try std.testing.expectApproxEqAbs(@as(f32, 20.0 / 480.0 * 2), base.y0 - base.y1, 0.0001);
+ try std.testing.expectApproxEqAbs(@as(f32, 16.0 / 480.0 * 2), ink.y0 - ink.y1, 0.0001);
+ try std.testing.expect(ink.y0 <= base.y0 and ink.y1 >= base.y1);
+ if (row > 0) try std.testing.expectApproxEqAbs(instances[(row - 1) * 2].y1, base.y0, 0.0001);
+ }
+}
+
fn emitInstance(
g: *Gui,
instances: [*]CellInstance,
@@ -5219,10 +5314,11 @@ test "insert cursor overlays without replacing the character beneath it" {
.y_off = 0,
.w = 10,
.h = 20,
- });
+ }, .{ 32, 48, 64 });
try std.testing.expectEqual(@as(usize, 6), builder.len);
try std.testing.expectApproxEqAbs(@as(f32, -0.32), vertices[0].y, 0.0001);
try std.testing.expectApproxEqAbs(@as(f32, -0.48), vertices[2].y, 0.0001);
+ try std.testing.expectApproxEqAbs(@as(f32, 32.0 / 255.0), vertices[0].r, 0.0001);
}
fn palColor(idx: u8) [3]u8 {
@@ -5284,8 +5380,8 @@ fn syncTaglineFont(g: *Gui, core: *const pardes.Pardes) void {
resetGlyphAtlas(g);
}
-fn ensureGlyph(g: *Gui, cp: u32, role: pardes.FontRole) Slot {
- const key: GlyphKey = .{ .codepoint = cp, .role = role };
+fn ensureGlyph(g: *Gui, cp: u32, role: pardes.FontRole, decoration: GlyphDecoration) Slot {
+ const key: GlyphKey = .{ .codepoint = cp, .role = role, .decoration = decoration };
if (g.glyphs.get(key)) |s| return s;
if (g.pen_x + g.cell_w > atlas_w) {
g.pen_x = 0;
@@ -5300,12 +5396,82 @@ fn ensureGlyph(g: *Gui, cp: u32, role: pardes.FontRole) Slot {
const raster_w = if (role == .tagline) g.tagline_width else g.cell_w;
const raster_h = if (role == .tagline) g.tagline_height else g.cell_h;
_ = c.ui_font_raster(face, scale, @intCast(cp), out, @intCast(atlas_w), @intCast(raster_w), @intCast(raster_h), baseline);
+ decorateGlyph(out, atlas_w, raster_w, raster_h, baseline, decoration);
g.glyphs.put(key, s) catch return g.space_slot;
g.pen_x += g.cell_w;
g.atlas_dirty = true;
return s;
}
+// Decorations stay inside the existing atlas slot, so text advance, caret and
+// selection geometry are identical to the regular glyph. The cached mask keeps
+// this work out of steady-state rendering and also decorates terminal spaces.
+fn decorateGlyph(out: [*]u8, stride: usize, width: usize, height: usize, baseline: i32, decoration: GlyphDecoration) void {
+ if (width == 0 or height == 0) return;
+ if (decoration.bold) {
+ // A fractional one-pixel embolden preserves counters at small UI sizes.
+ // Right-to-left traversal reads the original left neighbour each time.
+ for (0..height) |y| {
+ var x = width - 1;
+ while (x > 0) : (x -= 1) {
+ const previous = out[y * stride + x - 1];
+ const target = &out[y * stride + x];
+ target.* = @max(target.*, @as(u8, @intCast(@as(u16, previous) * 3 / 4)));
+ }
+ }
+ }
+ if (decoration.underline != .off) {
+ const base: usize = @intCast(@max(0, baseline));
+ const row = @min(base + 1, height - 1);
+ for (0..width) |x| {
+ switch (decoration.underline) {
+ .off => unreachable,
+ .single => out[row * stride + x] = 255,
+ .double => {
+ const upper = @min(base + 1, height -| 3);
+ out[upper * stride + x] = 255;
+ out[@min(upper + 2, height - 1) * stride + x] = 255;
+ },
+ .curly => out[(row -| @as(usize, if (x % 4 < 2) 1 else 0)) * stride + x] = 255,
+ .dotted => if (x % 3 == 0) {
+ out[row * stride + x] = 255;
+ },
+ .dashed => if (x % 6 < 4) {
+ out[row * stride + x] = 255;
+ },
+ }
+ }
+ }
+ if (decoration.strikethrough) {
+ const row = @min(height - 1, @as(usize, @intCast(@max(0, baseline))) * 2 / 3);
+ @memset(out[row * stride ..][0..width], 255);
+ }
+}
+
+test "glyph decorations render spaces and stay inside their atlas slot" {
+ const stride = 9;
+ const width = 5;
+ const height = 7;
+ for ([_]GlyphDecoration{
+ .{ .underline = .single },
+ .{ .underline = .double },
+ .{ .underline = .curly },
+ .{ .underline = .dotted },
+ .{ .underline = .dashed },
+ .{ .strikethrough = true },
+ }) |decoration| {
+ var mask: [stride * (height + 1)]u8 = @splat(0xa5);
+ for (0..height) |y| @memset(mask[y * stride ..][0..width], 0);
+ decorateGlyph(&mask, stride, width, height, 5, decoration);
+ try std.testing.expect(inkBounds(&mask, stride, width, height) != null);
+ for (0..height) |y| for (mask[y * stride + width ..][0 .. stride - width]) |guard|
+ try std.testing.expectEqual(@as(u8, 0xa5), guard);
+ for (mask[stride * height ..]) |guard| try std.testing.expectEqual(@as(u8, 0xa5), guard);
+ }
+ const hidden: pardes.Cell = .{ .default = false, .style = .{ .invisible = true, .ul = .single } };
+ try std.testing.expect(!GlyphDecoration.fromCell(&hidden).drawsBlank());
+}
+
fn uploadAtlas(g: *Gui, cmd: *c.SDL_GPUCommandBuffer) void {
const ptr = c.SDL_MapGPUTransferBuffer(g.device, g.atlas_xfer, false) orelse return;
const dst: [*]u8 = @ptrCast(ptr);
@@ -5709,6 +5875,7 @@ fn addCursorBar(
bar: bool,
visual_height: f32,
layout: CellLayout,
+ rgb: [3]u8,
) void {
if (!bar) return;
const x0 = layout.x_off + @as(f32, @floatFromInt(x)) * layout.w;
@@ -5721,9 +5888,9 @@ fn addCursorBar(
x0 + @max(1.0, layout.w / 8.0),
y0 + height,
.{
- .r = @as(f32, @floatFromInt(fg_default[0])) / 255.0,
- .g = @as(f32, @floatFromInt(fg_default[1])) / 255.0,
- .b = @as(f32, @floatFromInt(fg_default[2])) / 255.0,
+ .r = @as(f32, @floatFromInt(rgb[0])) / 255.0,
+ .g = @as(f32, @floatFromInt(rgb[1])) / 255.0,
+ .b = @as(f32, @floatFromInt(rgb[2])) / 255.0,
.a = 1.0,
},
);
@@ -5745,6 +5912,7 @@ fn buildOverlay(
const win_w: f32 = @floatFromInt(sw);
const win_h: f32 = @floatFromInt(sh);
var builder = OverlayBuilder{ .vertices = g.overlay_vertices, .win_w = win_w, .win_h = win_h };
+ appendWorkspacePet(g, core, surface, &builder);
if (topbarPaneBorderHeight(surface, g.cell_h, g.tagline_height)) |height| {
const y0: f32 = @floatFromInt(g.cell_h - height / 2);
const rgb = topbar_pane_border_rgb;
@@ -5755,6 +5923,10 @@ fn buildOverlay(
.a = 1.0,
});
}
+ if (core) |p| if (p.columnBarHeight() > 0) {
+ const y = @as(f32, @floatFromInt(pardes.TOPBAR_H + p.columnBarHeight())) * layout.h;
+ builder.addRect(0, y - 1, win_w, y, overlayRgb(p.chromeTheme().border));
+ };
const grid_bottom = @as(f32, @floatFromInt(surface.rows)) * layout.h;
if (grid_bottom < win_h and bottomTaglinePresent(surface)) {
const rgb = tagline_rgb;
@@ -5766,6 +5938,7 @@ fn buildOverlay(
});
}
if (transient_on) {
+ if (core) |p| appendPaneChrome(g, p, surface, layout, &builder);
if (surface.cursor) |cursor| {
if (cursor.x < surface.cols and cursor.y < surface.rows) {
const cell = surface.cells[@as(usize, cursor.y) * surface.cols + cursor.x];
@@ -5778,7 +5951,7 @@ fn buildOverlay(
taglineLayoutForCell(g, core, cursor.x, cursor.y, null)
else
layout;
- addCursorBar(&builder, cursor.x, cursor.y, cursor.bar, visual_height, cursor_layout);
+ addCursorBar(&builder, cursor.x, cursor.y, cursor.bar, visual_height, cursor_layout, cursorColor(core, &cell, role));
}
}
}
@@ -5786,6 +5959,244 @@ fn buildOverlay(
return @intCast(builder.len);
}
+fn appendWorkspacePet(g: *Gui, core: ?*const pardes.Pardes, surface: *const pardes.Surface, builder: *OverlayBuilder) void {
+ const p = core orelse return;
+ const kind: pet.Kind = @enumFromInt(@intFromEnum(p.settings.pet));
+ if (kind == .off or surface.rows == 0 or surface.cols == 0) {
+ g.pet_state = .{};
+ return;
+ }
+ // Read only the rendered global row. No pane/column tags, status text or
+ // mouse targets are changed, and editing the workspace parks the pet.
+ var occupied: usize = 0;
+ for (surface.cells[0..surface.cols], 0..) |*cell, i| {
+ if (cellCodepoint(cell) != ' ') occupied = i + 1;
+ }
+ const editing = p.topbar_col != null and p.header_column == null;
+ const band_top: f32 = @floatFromInt(taglineBandOffset(0, builder.win_h, g.cell_h, g.tagline_height));
+ const region = if (occupied >= surface.cols) null else pet.lane(
+ occupied,
+ @floatFromInt(g.tagline_width),
+ builder.win_w,
+ band_top,
+ @floatFromInt(g.tagline_height),
+ editing,
+ );
+ // SDL's regular pump already wakes at least every 16 ms. Quantization in
+ // sample keeps this independent of input, render rate and scene effects,
+ // without creating another timer or forcing core animation ticks.
+ const pose = g.pet_state.sample(kind, c.SDL_GetTicks(), region) orelse return;
+ const ink = overlayRgb(p.chromeTheme().tag_fg);
+ const eye = overlayRgb(p.chromeTheme().tag_bg);
+ for (0..pet.height) |y| for (0..pet.width) |x| {
+ const color = pet.pixel(kind, pose, x, y);
+ if (color == 0) continue;
+ const x0 = pose.x + @as(f32, @floatFromInt(x)) * pose.scale;
+ const y0 = pose.y + @as(f32, @floatFromInt(y)) * pose.scale;
+ builder.addRect(x0, y0, x0 + pose.scale, y0 + pose.scale, if (color == 2) eye else ink);
+ };
+}
+
+test "pet overlay stays beyond workspace text and vanishes while its tag is edited" {
+ std.testing.refAllDecls(pet);
+ const core = try pardes.Pardes.init(std.testing.allocator, .{ .cols = 80, .rows = 24 });
+ defer core.deinit();
+ core.settings.pet = .cat;
+ var cells: [80]pardes.Cell = @splat(.{});
+ const surface: pardes.Surface = .{ .cols = 80, .rows = 1, .cells = &cells };
+ for ("Workspace Commands", 0..) |ch, i| {
+ cells[i].text[0] = ch;
+ cells[i].len = 1;
+ cells[i].default = false;
+ }
+ var g: Gui = undefined;
+ g.pet_state = .{};
+ g.cell_h = 20;
+ g.tagline_height = 16;
+ g.tagline_width = 8;
+ var vertices: [pet.max_vertices]OverlayVertex = undefined;
+ var builder: OverlayBuilder = .{ .vertices = &vertices, .win_w = 800, .win_h = 480 };
+ appendWorkspacePet(&g, core, &surface, &builder);
+ try std.testing.expect(builder.len > 0);
+ for (vertices[0..builder.len]) |v| {
+ const x = (v.x + 1) * 400;
+ const y = (1 - v.y) * 240;
+ try std.testing.expect(x >= 20 * 8 - 0.01);
+ try std.testing.expect(y >= 0 and y < 20);
+ }
+ core.topbar_col = 0;
+ core.header_column = null;
+ builder.len = 0;
+ appendWorkspacePet(&g, core, &surface, &builder);
+ try std.testing.expectEqual(@as(usize, 0), builder.len);
+}
+
+fn cursorColor(core: ?*const pardes.Pardes, cell: *const pardes.Cell, role: pardes.FontRole) [3]u8 {
+ if (core) |p| return if (role == .tagline) switch (cell.style.fg) {
+ .rgb => |rgb| rgb,
+ else => p.chromeTheme().tag_fg,
+ } else p.theme().fg orelse fg_default;
+ return switch (cell.style.fg) {
+ .rgb => |rgb| rgb,
+ .index => |index| palColor(index),
+ // Detached frames carry explicit page backgrounds but blank cells need
+ // not carry foreground ink. Keep their insertion caret visible too.
+ .default => switch (cell.style.bg) {
+ .rgb => |rgb| if ((@as(u16, rgb[0]) * 3 + @as(u16, rgb[1]) * 6 + rgb[2]) / 10 > 140)
+ .{ 32, 32, 32 }
+ else
+ fg_default,
+ else => fg_default,
+ },
+ };
+}
+
+test "detached insertion caret contrasts with blank light and dark pages" {
+ var cell: pardes.Cell = .{ .default = false, .style = .{ .bg = .{ .rgb = .{ 248, 246, 237 } } } };
+ try std.testing.expectEqual([3]u8{ 32, 32, 32 }, cursorColor(null, &cell, .body));
+ cell.style.bg = .{ .rgb = .{ 24, 28, 32 } };
+ try std.testing.expectEqual(fg_default, cursorColor(null, &cell, .body));
+ cell.style.fg = .{ .rgb = .{ 122, 188, 160 } };
+ try std.testing.expectEqual([3]u8{ 122, 188, 160 }, cursorColor(null, &cell, .body));
+}
+
+fn overlayRgb(rgb: [3]u8) OverlayColor {
+ return .{
+ .r = @as(f32, @floatFromInt(rgb[0])) / 255.0,
+ .g = @as(f32, @floatFromInt(rgb[1])) / 255.0,
+ .b = @as(f32, @floatFromInt(rgb[2])) / 255.0,
+ .a = 1,
+ };
+}
+
+fn cellBackgroundIs(cell: *const pardes.Cell, rgb: [3]u8) bool {
+ return !cell.default and switch (cell.style.bg) {
+ .rgb => |bg| std.mem.eql(u8, &bg, &rgb),
+ else => false,
+ };
+}
+
+// The canonical surface still owns scrollbar positions and hit targets. Only
+// their pixel ink is inset here; no layout, selection or mouse coordinates move.
+fn appendPaneChrome(
+ g: *const Gui,
+ core: *const pardes.Pardes,
+ surface: *const pardes.Surface,
+ layout: CellLayout,
+ builder: *OverlayBuilder,
+) void {
+ const chrome = core.chromeTheme();
+ const page = overlayRgb(core.theme().bg orelse bg_default);
+ for (core.panes, core.rects) |slot, r| {
+ if (slot == null or r.w <= config.GUTTER or r.h <= pardes.BOX_H) continue;
+ if (@as(u32, r.x) + r.w > surface.cols or @as(u32, r.y) + r.h > surface.rows) continue;
+ const tag_y = if (core.settings.tag_bottom) r.y + r.h - pardes.BOX_H else r.y;
+ const body_y = if (core.settings.tag_bottom) r.y else r.y + pardes.BOX_H;
+ const body_end = body_y + r.h - pardes.BOX_H;
+ const x0 = @as(f32, @floatFromInt(r.x)) * layout.w;
+ const x1 = x0 + @as(f32, @floatFromInt(r.w)) * layout.w;
+ const tag_cell = &surface.cells[@as(usize, tag_y) * surface.cols + r.x];
+ const tag_cells = surface.cells[@as(usize, tag_y) * surface.cols + r.x ..][0..r.w];
+ const tag_visible = for (tag_cells) |*cell| {
+ if (cellFontRole(cell) != .tagline) break false;
+ } else true;
+ if (tag_visible) {
+ const rule_y = @as(f32, @floatFromInt(tag_y + @as(u16, if (core.settings.tag_bottom) 0 else 1))) * layout.h;
+ builder.addRect(x0, rule_y - @as(f32, if (core.settings.tag_bottom) 0 else 1), x1, rule_y + @as(f32, if (core.settings.tag_bottom) 1 else 0), overlayRgb(chrome.border));
+
+ // A quiet grip gives the normal-mode move box a purpose at rest.
+ // Insert and terminal badges retain their existing visible glyphs.
+ if (tag_cell.printableAscii() == ' ' and g.tagline_height >= 6 and g.tagline_width >= 3) {
+ const tag_layout = taglineLayoutForCell(g, core, r.x, tag_y, null);
+ const center_x = tag_layout.x_off + (@as(f32, @floatFromInt(r.x)) + @as(f32, @floatFromInt(config.GUTTER)) / 2) * tag_layout.w;
+ const center_y = @as(f32, @floatFromInt(tag_y)) * layout.h +
+ @as(f32, @floatFromInt(taglineBandOffset(tag_y, builder.win_h, g.cell_h, g.tagline_height))) +
+ @as(f32, @floatFromInt(g.tagline_height)) / 2;
+ const half_w = @max(1, @min(3, tag_layout.w - 2));
+ const ink = overlayRgb(switch (tag_cell.style.fg) {
+ .rgb => |rgb| rgb,
+ else => chrome.tag_fg,
+ });
+ builder.addRect(@floor(center_x - half_w), @floor(center_y - 2), @floor(center_x + half_w), @floor(center_y - 1), ink);
+ builder.addRect(@floor(center_x - half_w), @floor(center_y + 1), @floor(center_x + half_w), @floor(center_y + 2), ink);
+ }
+ }
+
+ // Do not paint over resize previews or debug text occupying the rail.
+ var thumb_start: ?u16 = null;
+ var thumb_end: u16 = body_y;
+ var row = body_y;
+ while (row < body_end) : (row += 1) {
+ const cell = &surface.cells[@as(usize, row) * surface.cols + r.x];
+ if (cell.printableAscii() != ' ') break;
+ if (cellBackgroundIs(cell, chrome.scroll_thumb)) {
+ if (thumb_start == null) thumb_start = row;
+ thumb_end = row + 1;
+ } else if (!cellBackgroundIs(cell, chrome.scroll_track)) break;
+ }
+ if (row != body_end) continue;
+ const y0 = @as(f32, @floatFromInt(body_y)) * layout.h;
+ const y1 = @as(f32, @floatFromInt(body_end)) * layout.h;
+ builder.addRect(x0, y0, x0 + layout.w, y1, page);
+ appendSquareRail(builder, x0, y0, y1, layout.w, false, overlayRgb(chrome.scroll_track));
+ if (thumb_start) |first| {
+ const thumb_y0 = @as(f32, @floatFromInt(first)) * layout.h;
+ const thumb_y1 = @as(f32, @floatFromInt(thumb_end)) * layout.h;
+ appendSquareRail(builder, x0, thumb_y0, thumb_y1, layout.w, true, overlayRgb(chrome.scroll_thumb));
+ }
+ }
+ appendColumnSpines(core, surface.rows, layout, builder);
+}
+
+fn appendSquareRail(builder: *OverlayBuilder, x: f32, y0: f32, y1: f32, cell_w: f32, thumb: bool, color: OverlayColor) void {
+ const width = @min(cell_w, if (thumb) @max(2, @floor(cell_w * 0.5)) else 2);
+ builder.addRect(x, y0, x + width, y1, color);
+}
+
+fn appendColumnSpines(core: *const pardes.Pardes, rows: u16, layout: CellLayout, builder: *OverlayBuilder) void {
+ const y0 = @as(f32, @floatFromInt(pardes.TOPBAR_H)) * layout.h;
+ const y1 = @as(f32, @floatFromInt(rows)) * layout.h;
+ if (y1 <= y0) return;
+ // A single boundary spans all panes, including their tags. Its left edge
+ // agrees with the square scroll markers and existing move-box hit area.
+ for (core.col_x[0..core.ncol], core.col_w[0..core.ncol]) |col, width| {
+ if (width == 0) continue;
+ const x = @as(f32, @floatFromInt(col)) * layout.w;
+ builder.addRect(x, y0, x + 1, y1, overlayRgb(core.chromeTheme().border));
+ }
+}
+
+test "square scroll markers share the column edge and have no rounded end inset" {
+ var vertices: [12]OverlayVertex = undefined;
+ var builder: OverlayBuilder = .{ .vertices = &vertices, .win_w = 800, .win_h = 480 };
+ appendSquareRail(&builder, 400, 40, 480, 10, false, overlayRgb(.{ 40, 40, 40 }));
+ appendSquareRail(&builder, 400, 80, 160, 10, true, overlayRgb(.{ 100, 100, 100 }));
+ try std.testing.expectEqual(@as(usize, 12), builder.len);
+ try std.testing.expectEqual(vertices[0].x, vertices[6].x);
+ try std.testing.expectApproxEqAbs(@as(f32, 1 - 80.0 / 480.0 * 2), vertices[6].y, 0.0001);
+ try std.testing.expectApproxEqAbs(@as(f32, 1 - 160.0 / 480.0 * 2), vertices[8].y, 0.0001);
+ try std.testing.expectApproxEqAbs(@as(f32, 5.0 / 800.0 * 2), vertices[7].x - vertices[6].x, 0.0001);
+}
+
+test "column spines remain continuous across every pane tag and body" {
+ const core = try pardes.Pardes.init(std.testing.allocator, .{ .cols = 80, .rows = 24 });
+ defer core.deinit();
+ _ = try core.newShell(1, "");
+ try std.testing.expect(pardes.layout.splitColumn(core, 0, 1, false));
+ pardes.test_api.sync(core);
+ var vertices: [12]OverlayVertex = undefined;
+ var builder: OverlayBuilder = .{ .vertices = &vertices, .win_w = 800, .win_h = 480 };
+ appendColumnSpines(core, 24, .{ .w = 10, .h = 20, .x_off = 0, .y_off = 0 }, &builder);
+ try std.testing.expectEqual(@as(usize, 12), builder.len);
+ for (0..2) |col| {
+ const first = vertices[col * 6];
+ const bottom = vertices[col * 6 + 2];
+ try std.testing.expectApproxEqAbs(@as(f32, 1 - 20.0 / 480.0 * 2), first.y, 0.0001);
+ try std.testing.expectEqual(@as(f32, -1), bottom.y);
+ try std.testing.expectApproxEqAbs(@as(f32, @floatFromInt(core.col_x[col])) * 10.0 / 800.0 * 2 - 1, first.x, 0.0001);
+ }
+}
+
fn appendTouchOverlay(g: *Gui, builder: *OverlayBuilder, debug_on: bool) void {
if (!debug_on) {
g.touch.click_flash_frames = 0;
diff --git a/src/gui/pet.zig b/src/gui/pet.zig
new file mode 100644
index 00000000..2b031f0e
--- /dev/null
+++ b/src/gui/pet.zig
@@ -0,0 +1,170 @@
+//! Original code-native pixel companions. Pure, bounded geometry and a 10 Hz
+//! animation clock: no textures, allocation, input handling or editor state.
+const std = @import("std");
+
+pub const Kind = enum { off, cat, frog };
+pub const width = 12;
+pub const height = 9;
+pub const max_vertices = width * height * 6;
+pub const Lane = struct { left: f32, right: f32, top: f32, scale: f32 };
+pub const Pose = struct { x: f32, y: f32, scale: f32, left: bool, walking: bool, frame: u8 };
+
+/// Only the trailing blank part of the global tag is eligible. The caller
+/// supplies its last occupied cell, including any wide-grapheme continuation.
+pub fn lane(occupied: usize, cell_w: f32, screen_w: f32, top: f32, band_h: f32, editing: bool) ?Lane {
+ if (editing or cell_w <= 0 or band_h < height + 2) return null;
+ const scale = @min(3, @floor((band_h - 2) / height));
+ const left = @as(f32, @floatFromInt(occupied + 2)) * cell_w;
+ const right = screen_w - 2 * cell_w - width * scale;
+ if (right - left < 4 * scale) return null;
+ return .{ .left = left, .right = right, .top = top + band_h - height * scale - 1, .scale = scale };
+}
+
+pub const State = struct {
+ kind: Kind = .off,
+ tick: ?u64 = null,
+ x: f32 = 0,
+ left: bool = false,
+ idle: u8 = 12,
+ frame: u8 = 0,
+
+ pub fn sample(s: *State, kind: Kind, now_ms: u64, area: ?Lane) ?Pose {
+ const region = area orelse {
+ s.* = .{};
+ return null;
+ };
+ if (kind == .off) {
+ s.* = .{};
+ return null;
+ }
+ const tick = now_ms / 100;
+ if (s.kind != kind or s.tick == null) {
+ s.* = .{ .kind = kind, .tick = tick, .x = region.left };
+ }
+ s.x = std.math.clamp(s.x, region.left, region.right);
+ // Coming back from suspension never launches the pet across the tag.
+ const steps = @min(tick -| s.tick.?, 2);
+ s.tick = tick;
+ for (0..steps) |_| {
+ s.frame +%= 1;
+ if (s.idle > 0) {
+ s.idle -= 1;
+ continue;
+ }
+ const speed: f32 = if (kind == .cat) 1.8 else 1.3;
+ s.x += (if (s.left) -speed else speed) * region.scale;
+ if (s.x >= region.right or s.x <= region.left) {
+ s.x = std.math.clamp(s.x, region.left, region.right);
+ s.left = !s.left;
+ s.idle = if (kind == .cat) 18 else 24;
+ }
+ }
+ return .{ .x = @floor(s.x), .y = region.top, .scale = region.scale, .left = s.left, .walking = s.idle == 0, .frame = s.frame };
+ }
+};
+
+const cat = [_][]const u8{
+ " # # ",
+ " #####",
+ " ##o##",
+ " # ######",
+ " # ######## ",
+ " ######### ",
+ " ######## ",
+ " ## ## ",
+ " # # ",
+};
+const frog = [_][]const u8{
+ " ",
+ " ## ## ",
+ " #o####o# ",
+ " ######## ",
+ " ###### ",
+ " ######## ",
+ " ########## ",
+ " ## ## ",
+ "### ###",
+};
+
+/// 0 transparent, 1 theme ink, 2 eye cutout. Walk legs and idle blinks are
+/// generated in this fixed 12x9 tile; neither can spill into an adjacent row.
+pub fn pixel(kind: Kind, pose: Pose, x_in: usize, y: usize) u2 {
+ if (x_in >= width or y >= height or kind == .off) return 0;
+ const x = if (pose.left) width - 1 - x_in else x_in;
+ const alternate = (pose.frame / 2) % 2 == 1;
+ // An idle companion still looks alive during its first pause: a slow
+ // two-pixel tail-tip flick, or the frog's throat gently inflating. These
+ // remain inside the tile and mirror with the rest of the animal.
+ const breathing = (pose.frame / 4) % 2 == 1;
+ if (!pose.walking and breathing) {
+ if (kind == .cat and y == 3 and x <= 1)
+ return @intFromBool(x == 0);
+ if (kind == .frog and y == 4 and (x == 2 or x == 9)) return 1;
+ }
+ if (pose.walking and alternate and y >= 7) {
+ if (kind == .cat) return @intFromBool((y == 7 and (x == 3 or x == 7)) or (y == 8 and (x == 2 or x == 8)));
+ return @intFromBool((y == 7 and (x == 2 or x == 9)) or (y == 8 and (x <= 2 or x >= 9)));
+ }
+ const ch = (if (kind == .cat) cat else frog)[y][x];
+ return switch (ch) {
+ '#' => 1,
+ 'o' => if (!pose.walking and pose.frame % 30 >= 27) 1 else 2,
+ else => 0,
+ };
+}
+
+test "pet stays in trailing workspace blanks and disappears during editing" {
+ try std.testing.expect(lane(20, 8, 200, 0, 16, false) == null);
+ try std.testing.expect(lane(3, 8, 200, 0, 16, true) == null);
+ try std.testing.expect(lane(3, 8, 200, 0, 10, false) == null);
+ const region = lane(3, 8, 200, 2, 20, false).?;
+ try std.testing.expect(region.left >= 5 * 8);
+ var state: State = .{};
+ var moved = false;
+ var reversed = false;
+ for (0..2000) |i| {
+ const pose = state.sample(.cat, i * 100, region).?;
+ try std.testing.expect(pose.x >= region.left and pose.x + width * pose.scale <= 200 - 16);
+ try std.testing.expect(pose.y >= 2 and pose.y + height * pose.scale < 22);
+ moved = moved or pose.walking;
+ reversed = reversed or pose.left;
+ }
+ try std.testing.expect(moved and reversed);
+ try std.testing.expect(state.sample(.cat, 300000, null) == null);
+ try std.testing.expect(state.sample(.off, 300100, region) == null);
+}
+
+test "pet clock is fixed rate and sprites bounded in both directions" {
+ const region = lane(1, 8, 400, 0, 16, false).?;
+ var state: State = .{};
+ const start = state.sample(.frog, 1000, region).?;
+ try std.testing.expectEqualDeep(start, state.sample(.frog, 1099, region).?);
+ for ([_]Kind{ .cat, .frog }) |kind| for ([_]bool{ false, true }) |left| {
+ const pose: Pose = .{ .x = 0, .y = 0, .scale = 1, .left = left, .walking = true, .frame = 3 };
+ var count: usize = 0;
+ for (0..height) |y| for (0..width) |x| {
+ count += @intFromBool(pixel(kind, pose, x, y) != 0);
+ };
+ try std.testing.expect(count > 20 and count <= width * height);
+ try std.testing.expectEqual(@as(u2, 0), pixel(kind, pose, width, height));
+ };
+}
+
+test "pet initial idle visibly animates without walking or leaving its tile" {
+ const region = lane(1, 8, 400, 0, 16, false).?;
+ for ([_]Kind{ .cat, .frog }) |kind| {
+ var state: State = .{};
+ const initial = state.sample(kind, 0, region).?;
+ var later = initial;
+ for (1..5) |tick| later = state.sample(kind, tick * 100, region).?;
+ try std.testing.expect(!initial.walking and !later.walking);
+ try std.testing.expectEqual(initial.x, later.x);
+ try std.testing.expectEqual(initial.y, later.y);
+ var changes: usize = 0;
+ for (0..height) |y| for (0..width) |x| {
+ changes += @intFromBool(pixel(kind, initial, x, y) != pixel(kind, later, x, y));
+ };
+ try std.testing.expectEqual(@as(usize, 2), changes);
+ try std.testing.expectEqual(@as(u2, 0), pixel(kind, later, width, height));
+ }
+}
diff --git a/src/layout.zig b/src/layout.zig
index 51944856..6c5f4474 100644
--- a/src/layout.zig
+++ b/src/layout.zig
@@ -669,7 +669,7 @@ pub fn movePlacement(p: *Pardes, id: usize, cur_x: u16, cur_y: u16) ?MovePlaceme
const sib = if (src.idx > 0) p.col_panes[src.col][src.idx - 1] else p.col_panes[src.col][src.idx + 1];
heights[sib] +|= p.rects[id].h;
}
- var y: u16 = TOPBAR_H;
+ var y: u16 = TOPBAR_H + p.columnBarHeight();
var last: ?MovePlacement = null;
for (0..p.col_n[tc]) |k| {
const pid = p.col_panes[tc][k];
@@ -723,7 +723,9 @@ pub fn setColumnWeights(p: *Pardes, col: usize, heights: *const [MAX_PANES]u16)
if (col >= p.ncol) return;
for (0..p.col_n[col]) |k| {
const pid = p.col_panes[col][k];
- if (p.panes[pid]) |pane| pane.vweight = @floatFromInt(@max(1, heights[pid]));
+ if (p.panes[pid]) |pane| if (!pane.collapsed) {
+ pane.vweight = @floatFromInt(@max(1, heights[pid]));
+ };
}
}
@@ -736,6 +738,17 @@ pub fn applyRowSplit(p: *Pardes, cc: usize, k: usize, cur_y: u16) void {
const combined: f32 = @floatFromInt(ra.h + rb.h);
var nt: f32 = @floatFromInt(if (p.settings.tag_bottom) cur_y -| ra.y else (cur_y + 1) -| ra.y);
nt = std.math.clamp(nt, @as(f32, BOX_H), @max(@as(f32, BOX_H), combined - BOX_H));
+ if (combined <= 0) return;
+ // Dragging a folded tag open is an explicit resize, so switch this pair
+ // back to visible-height weights without consuming other folded weights.
+ if ((a.collapsed and nt > BOX_H) or (b.collapsed and combined - nt > BOX_H)) {
+ snapColWeights(p, cc);
+ a.vweight = @floatFromInt(@max(1, ra.h));
+ b.vweight = @floatFromInt(@max(1, rb.h));
+ if (nt > BOX_H) a.collapsed = false;
+ if (combined - nt > BOX_H) b.collapsed = false;
+ }
+ if (a.collapsed or b.collapsed) return;
const pair = a.vweight + b.vweight;
a.vweight = pair * (nt / combined);
b.vweight = pair - a.vweight;
@@ -770,8 +783,11 @@ pub fn removePane(p: *Pardes, id: usize) void {
p.col_panes[j] = p.col_panes[j + 1];
p.col_n[j] = p.col_n[j + 1];
p.col_weight[j] = p.col_weight[j + 1];
+ p.col_tags[j] = p.col_tags[j + 1];
}
p.ncol -= 1;
+ p.col_tags[p.ncol] = .{};
+ p.topbar_col = null;
}
}
@@ -788,8 +804,11 @@ pub fn joinCol(p: *Pardes) void {
p.col_panes[j] = p.col_panes[j + 1];
p.col_n[j] = p.col_n[j + 1];
p.col_weight[j] = p.col_weight[j + 1];
+ p.col_tags[j] = p.col_tags[j + 1];
}
p.ncol -= 1;
+ p.col_tags[p.ncol] = .{};
+ p.topbar_col = null;
}
pub fn canSplitColumn(p: *Pardes, source_id: usize) bool {
@@ -833,8 +852,11 @@ pub fn splitColumn(p: *Pardes, source_id: usize, id: usize, before: bool) bool {
p.col_panes[j] = p.col_panes[j - 1];
p.col_n[j] = p.col_n[j - 1];
p.col_weight[j] = p.col_weight[j - 1];
+ p.col_tags[j] = p.col_tags[j - 1];
}
p.col_weight[c] = new_weight;
+ p.col_tags[c] = .{};
+ p.topbar_col = null;
p.col_panes[c][0] = id;
p.col_n[c] = 1;
p.ncol += 1;
@@ -844,7 +866,9 @@ pub fn splitColumn(p: *Pardes, source_id: usize, id: usize, before: bool) bool {
pub fn snapColWeights(p: *Pardes, c: usize) void {
for (0..p.col_n[c]) |k| {
const pid = p.col_panes[c][k];
- if (p.panes[pid]) |pp| pp.vweight = @floatFromInt(@max(1, p.rects[pid].h));
+ if (p.panes[pid]) |pp| if (!pp.collapsed) {
+ pp.vweight = @floatFromInt(@max(1, p.rects[pid].h));
+ };
}
}
@@ -886,11 +910,11 @@ pub fn splitBelow(p: *Pardes, src_id: usize, nw: *Pane) void {
const keep = std.math.clamp(cur, 1, @max(1, body -| (BOX_H + 3)));
if (findPane(p, src_id)) |f| for (0..p.col_n[f.col]) |k| {
const pid = p.col_panes[f.col][k];
- if (p.panes[pid]) |pp| if (pp != nw) {
+ if (p.panes[pid]) |pp| if (pp != nw and !pp.collapsed) {
pp.vweight = @floatFromInt(@max(1, p.rects[pid].h));
};
};
- src.vweight = @floatFromInt(BOX_H + keep);
+ if (!src.collapsed) src.vweight = @floatFromInt(BOX_H + keep);
nw.vweight = @floatFromInt(@max(1, src_h -| (BOX_H + keep)));
if (nw.file) |f| if (!panes.Output.fileTraits(f.output).doc) {
// trimmed: every row ends in a newline, and the empty line after
@@ -924,6 +948,81 @@ pub fn columnBoundary(width: u16, prefix: u128, total: u128) u16 {
return @intCast(@min(@as(u128, width), pixels));
}
+pub fn toggleCollapse(p: *Pardes, id: usize) void {
+ const pane = p.panes[id] orelse return;
+ const at = findPane(p, id) orelse return;
+ compute(p);
+ const was_collapsed = pane.collapsed;
+ const old_height = p.rects[id].h;
+ const remembered_height = pane.vweight;
+ // Convert only visible panes to row weights. The toggle then changes one
+ // pair, rather than letting the column redistribute the released space.
+ snapColWeights(p, at.col);
+ const neighbor = collapseNeighbor(p, at.col, at.idx);
+ if (was_collapsed) {
+ if (neighbor) |other| {
+ const wanted: u16 = @intFromFloat(@min(@as(f32, @floatFromInt(std.math.maxInt(u16))), @max(1, @round(remembered_height))));
+ const give = @min(wanted -| old_height, p.rects[other].h -| BOX_H);
+ p.panes[other].?.vweight -= @floatFromInt(give);
+ pane.vweight = @floatFromInt(@max(1, old_height + give));
+ }
+ pane.collapsed = false;
+ } else {
+ // A folded pane's weight stores its former height, including its tag,
+ // so Dump/Restore and a later expansion retain a useful target size.
+ pane.vweight = @floatFromInt(@max(1, old_height));
+ pane.collapsed = true;
+ if (neighbor) |other|
+ p.panes[other].?.vweight += @floatFromInt(old_height -| BOX_H);
+ }
+ compute(p);
+}
+
+fn collapseNeighbor(p: *Pardes, col: usize, index: usize) ?usize {
+ var above = index;
+ while (above > 0) {
+ above -= 1;
+ const id = p.col_panes[col][above];
+ if (p.panes[id]) |pane| if (!pane.collapsed) return id;
+ }
+ for (p.col_panes[col][index + 1 .. p.col_n[col]]) |id|
+ if (p.panes[id]) |pane| if (!pane.collapsed) return id;
+ return null;
+}
+
+fn computeCollapsedColumn(p: *Pardes, c: usize, x: u16, width: u16, folded: usize) void {
+ var y: u16 = TOPBAR_H + p.columnBarHeight();
+ const available = p.screen_h -| y;
+ var expanded_left: usize = 0;
+ var weight: f32 = 0;
+ for (p.col_panes[c][0..p.col_n[c]]) |id| if (p.panes[id]) |pane| {
+ if (!pane.collapsed) {
+ expanded_left += 1;
+ weight += pane.vweight;
+ }
+ };
+ const expanded_height = available -| @as(u16, @intCast(folded));
+ var budget = expanded_height;
+ var folded_left = folded;
+ for (p.col_panes[c][0..p.col_n[c]]) |id| {
+ const pane = p.panes[id] orelse continue;
+ const room = p.screen_h -| y;
+ const height: u16 = if (pane.collapsed) blk: {
+ folded_left -= 1;
+ break :blk @min(room, BOX_H);
+ } else blk: {
+ expanded_left -= 1;
+ const limit = @min(budget, room -| @as(u16, @intCast(folded_left)));
+ const share = @as(f32, @floatFromInt(expanded_height)) * pane.vweight / (if (weight > 0) weight else 1);
+ const h = if (expanded_left == 0) limit else @min(limit -| @as(u16, @intCast(expanded_left)), @max(1, @as(u16, @intFromFloat(@round(share)))));
+ budget -|= h;
+ break :blk h;
+ };
+ p.rects[id] = .{ .x = x, .y = y, .w = width, .h = height };
+ y +|= height;
+ }
+}
+
pub fn compute(p: *Pardes) void {
p.rects = @splat(.{});
if (p.ncol == 0) return;
@@ -945,14 +1044,23 @@ pub fn compute(p: *Pardes) void {
p.col_x[c] = x;
p.col_w[c] = cw;
+ var folded: usize = 0;
+ for (p.col_panes[c][0..p.col_n[c]]) |id| if (p.panes[id]) |pane| {
+ if (pane.collapsed) folded += 1;
+ };
+ if (folded > 0) {
+ computeCollapsedColumn(p, c, x, cw, folded);
+ continue;
+ }
+
var vsum: f32 = 0;
for (0..p.col_n[c]) |k| {
if (p.panes[p.col_panes[c][k]]) |pane| vsum += pane.vweight;
}
if (vsum <= 0) vsum = 1;
- var y: u16 = TOPBAR_H;
- const avail_h = p.screen_h -| TOPBAR_H;
+ var y: u16 = TOPBAR_H + p.columnBarHeight();
+ const avail_h = p.screen_h -| y;
for (0..p.col_n[c]) |k| {
const id = p.col_panes[c][k];
const pane = p.panes[id] orelse continue;
@@ -968,6 +1076,211 @@ pub fn compute(p: *Pardes) void {
pub const ascii_max_movement_frames: u16 = 12;
+test "collapse transfers height upward and restores the original layout" {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 80, .rows = 32 });
+ defer p.deinit();
+ _ = try p.newShell(1, "");
+ _ = try p.newShell(2, "");
+ insert(p, 0, 1, 1);
+ insert(p, 0, 2, 2);
+ p.panes[0].?.vweight = 3;
+ p.panes[1].?.vweight = 2;
+ compute(p);
+ const original = p.rects;
+ toggleCollapse(p, 1);
+ try std.testing.expectEqual(@as(u16, 1), p.rects[1].h);
+ try std.testing.expectEqual(@as(f32, @floatFromInt(original[1].h)), p.panes[1].?.vweight);
+ try std.testing.expectEqual(p.screen_h, p.rects[2].y + p.rects[2].h);
+ try std.testing.expect(p.rects[0].h > original[0].h);
+ try std.testing.expectEqualDeep(original[2], p.rects[2]);
+ toggleCollapse(p, 1);
+ try std.testing.expectEqualDeep(original, p.rects);
+ toggleCollapse(p, 2);
+ try std.testing.expectEqual(@as(u16, 1), p.rects[2].h);
+ try std.testing.expectEqual(p.screen_h, p.rects[2].y + p.rects[2].h);
+}
+
+test "collapse changes only one neighbor at the top middle and bottom" {
+ for (0..4) |target| {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 80, .rows = 58 });
+ defer p.deinit();
+ for (1..4) |id| {
+ _ = try p.newShell(id, "");
+ insert(p, 0, id, id);
+ }
+ for ([_]f32{ 11, 7, 5, 3 }, 0..) |weight, id| p.panes[id].?.vweight = weight;
+ compute(p);
+ const original = p.rects;
+ const recipient = if (target > 0) target - 1 else 1;
+ for (0..5) |_| {
+ toggleCollapse(p, target);
+ try std.testing.expectEqual(@as(u16, BOX_H), p.rects[target].h);
+ try std.testing.expectEqual(original[recipient].h + original[target].h - BOX_H, p.rects[recipient].h);
+ for (0..4) |id| if (id != target and id != recipient)
+ try std.testing.expectEqualDeep(original[id], p.rects[id]);
+ toggleCollapse(p, target);
+ try std.testing.expectEqualDeep(original, p.rects);
+ }
+ }
+}
+
+test "collapse skips folded neighbors and expansion reclaims only its neighbor" {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 80, .rows = 62 });
+ defer p.deinit();
+ for (1..5) |id| {
+ _ = try p.newShell(id, "");
+ insert(p, 0, id, id);
+ }
+ compute(p);
+ toggleCollapse(p, 1);
+ toggleCollapse(p, 2);
+ const original = p.rects;
+ toggleCollapse(p, 3);
+ try std.testing.expectEqual(original[0].h + original[3].h - BOX_H, p.rects[0].h);
+ try std.testing.expectEqualDeep(original[4], p.rects[4]);
+ for (1..4) |id| try std.testing.expectEqual(@as(u16, BOX_H), p.rects[id].h);
+ toggleCollapse(p, 3);
+ try std.testing.expectEqualDeep(original, p.rects);
+ // With no expanded pane above, give the space to the first one below.
+ toggleCollapse(p, 0);
+ const with_folded_above = p.rects;
+ toggleCollapse(p, 3);
+ try std.testing.expectEqual(with_folded_above[4].h + with_folded_above[3].h - BOX_H, p.rects[4].h);
+ for (0..3) |id| try std.testing.expectEqualDeep(with_folded_above[id], p.rects[id]);
+ toggleCollapse(p, 3);
+ try std.testing.expectEqualDeep(with_folded_above, p.rects);
+}
+
+test "collapse local transfers remain bounded through repeated tiny window resizes" {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 80, .rows = 58 });
+ defer p.deinit();
+ for (1..5) |id| {
+ _ = try p.newShell(id, "");
+ insert(p, 0, id, id);
+ }
+ for (0..180) |step| {
+ p.screen_h = @intCast((step * 17) % 81);
+ p.settings.column_tags = step % 2 == 0;
+ p.settings.tag_bottom = step % 3 == 0;
+ compute(p);
+ toggleCollapse(p, step % 5);
+ var used: u16 = 0;
+ for (0..5) |id| {
+ const pane = p.panes[id].?;
+ const rect = p.rects[id];
+ try std.testing.expect(std.math.isFinite(pane.vweight) and pane.vweight > 0);
+ try std.testing.expect(rect.h <= p.screen_h -| rect.y);
+ if (pane.collapsed) try std.testing.expect(rect.h <= BOX_H);
+ used += rect.h;
+ }
+ try std.testing.expect(used <= p.screen_h);
+ }
+}
+
+test "collapse expansion is limited to space available in one neighbor" {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 80, .rows = 42 });
+ defer p.deinit();
+ for (1..4) |id| {
+ _ = try p.newShell(id, "");
+ insert(p, 0, id, id);
+ }
+ compute(p);
+ toggleCollapse(p, 2);
+ snapColWeights(p, 0);
+ // An intervening resize gave most of the donor's space to another pane.
+ p.panes[0].?.vweight += p.panes[1].?.vweight - 2;
+ p.panes[1].?.vweight = 2;
+ compute(p);
+ const before = p.rects;
+ toggleCollapse(p, 2);
+ try std.testing.expectEqual(@as(u16, 2), p.rects[2].h);
+ try std.testing.expectEqual(@as(u16, BOX_H), p.rects[1].h);
+ try std.testing.expectEqualDeep(before[0], p.rects[0]);
+ try std.testing.expectEqualDeep(before[3], p.rects[3]);
+}
+
+test "collapse single and all panes leave unused column space" {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 80, .rows = 32 });
+ defer p.deinit();
+ toggleCollapse(p, 0);
+ try std.testing.expectEqual(@as(u16, 1), p.rects[0].h);
+ _ = try p.newShell(1, "");
+ insert(p, 0, 1, 1);
+ toggleCollapse(p, 1);
+ try std.testing.expectEqual(@as(u16, 1), p.rects[0].h);
+ try std.testing.expectEqual(@as(u16, 1), p.rects[1].h);
+ try std.testing.expectEqual(p.rects[0].y + 1, p.rects[1].y);
+ try std.testing.expect(p.rects[1].y + 1 < p.screen_h);
+ toggleCollapse(p, 0);
+ try std.testing.expectEqual(p.screen_h - 1, p.rects[1].y);
+}
+
+test "collapse survives tiny resizes column tags and TagBottom" {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 80, .rows = 32 });
+ defer p.deinit();
+ _ = try p.newShell(1, "");
+ _ = try p.newShell(2, "");
+ insert(p, 0, 1, 1);
+ insert(p, 0, 2, 2);
+ p.panes[1].?.collapsed = true;
+ for ([_]bool{ false, true }) |bottom| {
+ p.settings.tag_bottom = bottom;
+ for ([_]bool{ false, true }) |column_tags| {
+ p.settings.column_tags = column_tags;
+ for (0..50) |height| {
+ p.screen_h = @intCast(height);
+ compute(p);
+ var used: u16 = 0;
+ for (p.col_panes[0][0..p.col_n[0]]) |id| {
+ const rect = p.rects[id];
+ try std.testing.expect(rect.h <= p.screen_h -| rect.y);
+ used += rect.h;
+ }
+ try std.testing.expect(used <= p.screen_h);
+ if (height >= 5) try std.testing.expectEqual(@as(u16, 1), p.rects[1].h);
+ }
+ }
+ }
+ p.screen_h = 32;
+ compute(p);
+ try std.testing.expectEqual(@as(u16, 1), p.rects[1].h);
+}
+
+test "collapse can be expanded by dragging its boundary" {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 80, .rows = 32 });
+ defer p.deinit();
+ _ = try p.newShell(1, "");
+ insert(p, 0, 1, 1);
+ toggleCollapse(p, 0);
+ applyRowSplit(p, 0, 0, p.rects[0].y + 5);
+ compute(p);
+ try std.testing.expect(!p.panes[0].?.collapsed);
+ try std.testing.expectEqual(@as(u16, 6), p.rects[0].h);
+ toggleCollapse(p, 1);
+ p.settings.tag_bottom = true;
+ applyRowSplit(p, 0, 0, p.rects[1].y - 5);
+ compute(p);
+ try std.testing.expect(!p.panes[1].?.collapsed);
+ try std.testing.expectEqual(@as(u16, 6), p.rects[1].h);
+}
+
+test "collapse dump restores folded state and retained expansion weight" {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 80, .rows = 32 });
+ defer p.deinit();
+ p.panes[0].?.vweight = 7;
+ compute(p);
+ const original_height = p.rects[0].h;
+ toggleCollapse(p, 0);
+ try p.dumpState();
+ const restored = try Pardes.initFromDump(std.testing.allocator, .{ .tty_only = true, .cols = 80, .rows = 32 }, p.dump_out.?);
+ defer restored.deinit();
+ try std.testing.expect(restored.panes[0].?.collapsed);
+ try std.testing.expectEqual(@as(f32, @floatFromInt(original_height)), restored.panes[0].?.vweight);
+ try std.testing.expectEqual(@as(u16, 1), restored.rects[0].h);
+ toggleCollapse(restored, 0);
+ try std.testing.expectEqual(restored.screen_h - restored.rects[0].y, restored.rects[0].h);
+}
+
pub const Easing = enum(u8) {
linear,
smooth,
diff --git a/src/macos.zig b/src/macos.zig
index 3e4edd12..96598b90 100644
--- a/src/macos.zig
+++ b/src/macos.zig
@@ -1846,10 +1846,11 @@ export fn pardes_take_haptic() c_int {
var font_path_z: [4096:0]u8 = undefined;
-export fn pardes_font_take() ?[*:0]const u8 {
+export fn pardes_font_take(size_hundredths: *u16) ?[*:0]const u8 {
const st = &(state orelse return null);
if (comptime !pardes.font_picker) return null;
const want = st.core.takeFontRequest() orelse return null;
+ size_hundredths.* = st.core.settings.font.requested_size_hundredths;
if (want.len >= font_path_z.len) return null;
@memcpy(font_path_z[0..want.len], want);
font_path_z[want.len] = 0;
diff --git a/src/macos/Sources/AppDelegate.swift b/src/macos/Sources/AppDelegate.swift
index 2d411873..eb499f1b 100644
--- a/src/macos/Sources/AppDelegate.swift
+++ b/src/macos/Sources/AppDelegate.swift
@@ -585,8 +585,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate, PardesViewDelegate {
// is already waiting by the time the tick returns. The view re-measures
// and calls back through pardesViewDidResize, so the grid the core is
// holding follows the cell that just changed size.
- if let wanted = pardes_font_take() {
- view.adoptFont(path: String(cString: wanted))
+ var fontSize: UInt16 = 0
+ if let wanted = pardes_font_take(&fontSize) {
+ view.adoptFont(path: String(cString: wanted), sizeHundredths: fontSize)
}
if pardes_should_quit() {
diff --git a/src/macos/Sources/PardesView.swift b/src/macos/Sources/PardesView.swift
index f9afa7b1..5c5bc8ba 100644
--- a/src/macos/Sources/PardesView.swift
+++ b/src/macos/Sources/PardesView.swift
@@ -761,8 +761,9 @@ final class PardesView: NSView {
}
/// The file `Font <name>` resolved to, straight from the core.
- func adoptFont(path: String) {
- wear(size: fontSize, path: path, resolvesRequest: true)
+ func adoptFont(path: String, sizeHundredths: UInt16) {
+ let size = sizeHundredths == 0 ? fontSize : CGFloat(sizeHundredths) / 100
+ wear(size: size, path: path, resolvesRequest: true)
}
/// Cmd+ and Cmd-. Whole points, because the cell is rounded to whole
diff --git a/src/macos/pardes.h b/src/macos/pardes.h
index c28b3514..845c8096 100644
--- a/src/macos/pardes.h
+++ b/src/macos/pardes.h
@@ -486,7 +486,8 @@ pardes_haptic_e pardes_take_haptic(void);
// pardes_resize. A file the host cannot load must be rejected explicitly while
// keeping the face that works; otherwise Config would leave the request pending
// forever or claim a fallback was accepted.
-const char *pardes_font_take(void);
+// Optional size in native points; zero preserves the current size.
+const char *pardes_font_take(uint16_t *size_hundredths);
// Boot, zoom and display-scale changes observe the face already on screen;
// this never consumes a pending request. `point_hundredths` is the effective
diff --git a/src/panes.zig b/src/panes.zig
index 6db7f53b..6a5a2739 100644
--- a/src/panes.zig
+++ b/src/panes.zig
@@ -83,6 +83,8 @@ pub const Pane = struct {
serial: u32 = 0,
mode: Mode = .normal,
vweight: f32 = 1,
+ /// A folded pane keeps its expansion weight, but occupies only its tag row.
+ collapsed: bool = false,
cols: u16,
rows: u16,
greet: bool = false,
@@ -125,6 +127,12 @@ pub const Pane = struct {
tag_mode: Mode = .normal,
tag_col: u16 = 0,
tag_anchor: u16 = 0,
+ /// Filename edits are staged separately from the live buffer identity.
+ /// Enter commits the name; leaving tag editing discards the draft.
+ tag_name: [limits.host_path_cap]u8 = undefined,
+ tag_name_len: ?u16 = null,
+ /// Display columns hidden to reveal the tag caret; tag addresses stay whole.
+ tag_scroll: u16 = 0,
ed_undo: [Terminal.history_max]Terminal.Snapshot = undefined,
ed_undo_len: usize = 0,
ed_redo: [Terminal.history_max]Terminal.Snapshot = undefined,
@@ -965,6 +973,7 @@ pub const File = struct {
.cols = pane.cols,
.rows = pane.rows,
.vweight = pane.vweight,
+ .collapsed = pane.collapsed,
.file = .{
.path = file.path,
.content = file.content,
@@ -1728,7 +1737,6 @@ pub const File = struct {
pub fn drawGutter(p: *Pardes, pane: *Pane, r: pardes.Rect, tx: u16, tw: u16, body_h: u16, active: bool) void {
const s = &p.surface;
const prefix_width = gutterWidth(pane);
- const ch = p.chromeTheme();
const goff = pane.scroll();
const gcur = Terminal.gridCursor(pane);
const gcrow = if (pane.cur_pinned) pane.cur_row else @as(i32, gcur.y) + goff;
@@ -1745,10 +1753,11 @@ pub const File = struct {
while (c < prefix_width and c < tw) : (c += 1) {
const cell = s.at(tx + c, body_y + vr);
cell.default = false; // paints blank gutter rows too
- if (on_cursor) {
- cell.style.fg = .{ .rgb = ch.tag_fg };
- cell.style.bg = .{ .rgb = ch.tag_bg };
- } else cell.style.fg = .{ .rgb = ch.lineno };
+ cell.style.fg = .{ .rgb = if (on_cursor)
+ p.theme().lineno_active orelse p.theme().lineno
+ else
+ p.theme().lineno };
+ cell.style.bold = on_cursor;
}
}
}
@@ -1758,10 +1767,10 @@ pub const File = struct {
fn synStyle(p: *Pardes, sy: syntax.Syn) ?SynStyle {
return switch (sy) {
.none => null,
- .keyword => .{ .fg = p.theme().kw, .bold = true },
+ .keyword => .{ .fg = p.theme().kw, .bold = p.settings.syntax_bold },
.string => .{ .fg = p.theme().str, .bold = false },
.number => .{ .fg = p.theme().num, .bold = false },
- .comment => .{ .fg = p.theme().comment, .bold = true },
+ .comment => .{ .fg = p.theme().comment, .bold = false },
};
}
@@ -1770,7 +1779,7 @@ pub const File = struct {
pub fn recolorSyntax(p: *Pardes, pane: *Pane, f: *State, r: pardes.Rect, tx: u16, tw: u16, body_h: u16) void {
const highlights = if (f.mini) |mini| mini.colors else f.highlights;
const highlight_start = if (f.mini != null) 0 else f.highlight_start;
- if (highlights.len == 0) return;
+ if (highlights.len == 0 and f.output == null) return;
const s = &p.surface;
const prefix_width = gutterWidth(pane);
const tz_recolor = tracy.zone(@src(), "synRecolor");
@@ -1803,6 +1812,7 @@ pub const File = struct {
line.len;
}
hs = modal.graphemeStart(line, @min(hs, line.len));
+ const decoration = Output.rowDecoration(f.output, line);
var c: usize = 0;
var screen_c: usize = 0;
while (hs + c < limit and prefix_width + screen_c < tw) {
@@ -1823,6 +1833,18 @@ pub const File = struct {
}
}
}
+ // Results keep their exact live text. Only the location,
+ // matched source range and diagnostic label gain emphasis.
+ if (decoration.styleAt(p, hs + c)) |style| {
+ var fill: usize = 0;
+ while (fill < cells and prefix_width + screen_c + fill < tw) : (fill += 1) {
+ const cell = s.at(tx + @as(u16, @intCast(prefix_width + screen_c + fill)), body_y + vr);
+ if (cell.default) continue;
+ cell.style.fg = style.fg;
+ cell.style.bold = style.bold;
+ if (style.bg != .default) cell.style.bg = style.bg;
+ }
+ }
screen_c += cells;
c = grapheme_end - hs;
}
@@ -1910,6 +1932,80 @@ pub const Output = struct {
}
};
+ const RowDecoration = struct {
+ location_end: usize = 0,
+ mark_start: usize = 0,
+ mark_end: usize = 0,
+ severity: enum { none, err, warning, info, hint } = .none,
+
+ fn styleAt(row: RowDecoration, p: *const Pardes, byte: usize) ?pardes.CellStyle {
+ // Body paper changes immediately, so its ink must change with it
+ // even while the surrounding tags are still fading.
+ const chrome = pardes.ChromeTheme.fromTheme(p.theme());
+ if (byte < row.location_end) return .{ .fg = .{ .rgb = chrome.lineno } };
+ if (byte < row.mark_start or byte >= row.mark_end) return null;
+ if (row.severity == .none) return .{
+ .fg = .{ .rgb = chrome.search_fg },
+ .bg = .{ .rgb = chrome.search_bg },
+ };
+ return .{ .fg = .{ .rgb = switch (row.severity) {
+ .err => chrome.diagnostic_error,
+ .warning => chrome.diagnostic_warning,
+ .info => chrome.diagnostic_info,
+ .hint => chrome.diagnostic_hint,
+ .none => unreachable,
+ } }, .bold = true };
+ }
+ };
+
+ fn rowDecoration(output: ?State, line: []const u8) RowDecoration {
+ const origin = (output orelse return .{}).from;
+ const token_end = std.mem.indexOfAny(u8, line, " \t") orelse line.len;
+ const target = look.parsePathLine(line[0..token_end]);
+ if (target.at.line == 0 or target.end != token_end) return .{};
+ var row: RowDecoration = .{ .location_end = token_end };
+ if (token_end == line.len) return row;
+ const source_start = token_end + 1;
+ const is_search = switch (origin) {
+ .search => true,
+ .cmd => |cmd| cmd == .Grep,
+ else => false,
+ };
+ if (is_search and target.at.col > 0 and target.at.end_line == target.at.line and
+ target.at.end_col >= target.at.col)
+ {
+ row.mark_start = source_start +| (target.at.col - 1);
+ row.mark_end = @min(line.len, source_start +| target.at.end_col);
+ }
+ const is_diagnostic = switch (origin) {
+ .query => |kind| kind == .diagnostics or kind == .workspace_diagnostics,
+ else => false,
+ };
+ if (is_diagnostic) {
+ const text = line[source_start..];
+ inline for (.{ .{ "error:", .err }, .{ "warning:", .warning }, .{ "info:", .info }, .{ "hint:", .hint } }) |label| {
+ if (std.mem.startsWith(u8, text, label[0])) {
+ row.mark_start = source_start;
+ row.mark_end = source_start + label[0].len;
+ row.severity = label[1];
+ }
+ }
+ }
+ return row;
+ }
+
+ test "result decoration follows source byte ranges and diagnostic provenance" {
+ const row = rowDecoration(.{ .from = .search }, "src/a.rs:3:5-7 let abc = 1;");
+ try std.testing.expectEqualStrings("abc", "src/a.rs:3:5-7 let abc = 1;"[row.mark_start..row.mark_end]);
+ const prose = rowDecoration(.{ .from = .{ .query = .hover } }, "src/a.rs:3:5-7 error: prose");
+ try std.testing.expectEqual(@as(usize, 0), prose.mark_end);
+ const diagnostic = rowDecoration(.{ .from = .{ .query = .diagnostics } }, "src/a.rs:3:5-7 warning: unused");
+ try std.testing.expectEqual(.warning, diagnostic.severity);
+ try std.testing.expectEqualStrings("warning:", "src/a.rs:3:5-7 warning: unused"[diagnostic.mark_start..diagnostic.mark_end]);
+ const malformed = rowDecoration(.{ .from = .search }, "src/a.rs:3:99999999999999999999-99999999999999999999 text");
+ try std.testing.expect(malformed.mark_end <= "src/a.rs:3:99999999999999999999-99999999999999999999 text".len);
+ }
+
pub fn setArg(o: *State, text: []const u8) error{ArgumentTooLong}!void {
if (text.len > max_arg) return error.ArgumentTooLong;
o.arg_len = @intCast(text.len);
@@ -2215,12 +2311,23 @@ pub const Output = struct {
pub fn openThemes(p: *Pardes, id: usize) !void {
var out: std.Io.Writer.Allocating = .init(p.gpa);
errdefer out.deinit();
- for (pardes.themes) |t|
+ try out.writer.writeAll("# Pardes themes\n");
+ for (pardes.themes, 0..) |t, i| {
+ if (i == pardes.native_theme_count)
+ try out.writer.writeAll("\n# Legacy and imported themes\n");
try out.writer.print(comptime config.Runtime.findAction(.theme).?.word ++ " {s}\n", .{t.name});
+ }
const content = try out.toOwnedSlice();
try openStepped(p, id, .{ .cmd = .ThemeSel }, content);
}
+ pub fn isWalkRow(out: ?State, line: []const u8) bool {
+ const state = out orelse return true;
+ if (!std.meta.eql(state.from, Origin{ .cmd = .ThemeSel })) return true;
+ // Section labels are for reading, not stops in the command walk.
+ return std.mem.startsWith(u8, std.mem.trimStart(u8, line, " \t"), comptime config.Runtime.findAction(.theme).?.word ++ " ");
+ }
+
pub fn openFonts(p: *Pardes, id: usize) !void {
if (builtins.capabilities.font_picker) {
const arena = p.scratch.allocator();
@@ -2827,6 +2934,7 @@ pub const Image = struct {
.cols = pane.cols,
.rows = pane.rows,
.vweight = pane.vweight,
+ .collapsed = pane.collapsed,
.image = .{
.path = path,
.bytes_b64 = if (bytes.len > 0) try dump.encodeBytes(arena, bytes) else "",
@@ -3026,6 +3134,15 @@ pub const Pdf = struct {
};
pub fn legacySavedPrefix(path: []const u8, saved_tag: []const u8) ?[]const u8 {
+ if (std.mem.startsWith(u8, saved_tag, path) and std.mem.startsWith(u8, saved_tag[path.len..], " [")) {
+ const start = path.len + 2;
+ const end = std.mem.indexOfScalarPos(u8, saved_tag, start, ']') orelse return null;
+ var parts = std.mem.splitScalar(u8, saved_tag[start..end], '/');
+ _ = std.fmt.parseInt(usize, parts.next() orelse return null, 10) catch return null;
+ _ = std.fmt.parseInt(usize, parts.next() orelse return null, 10) catch return null;
+ if (parts.next() != null) return null;
+ return saved_tag[0 .. end + 1];
+ }
if (!std.mem.startsWith(u8, saved_tag, "pdf ")) return null;
const marker = " PdfSections ";
const marker_at = std.mem.indexOf(u8, saved_tag, marker) orelse return null;
@@ -6513,6 +6630,7 @@ pub const Terminal = struct {
.cols = pane.cols,
.rows = pane.rows,
.vweight = pane.vweight,
+ .collapsed = pane.collapsed,
.terminal = .{
.cwd = try arena.dupe(u8, pane.cwdSlice()),
.stream = try arena.dupe(u8, text),
@@ -6561,6 +6679,7 @@ pub const Terminal = struct {
.cols = pane.cols,
.rows = pane.rows,
.vweight = pane.vweight,
+ .collapsed = pane.collapsed,
.terminal = .{
.cwd = try arena.dupe(u8, pane.cwdSlice()),
.stream = stream[0..len],
@@ -7193,7 +7312,8 @@ pub const Terminal = struct {
test "terminal Filter keys indexed truecolor OSC and background-only cells through the theme" {
const testing = std.testing;
- const p = try Pardes.init(testing.allocator, .{ .tty_only = true, .cols = 18, .rows = 6 });
+ // Raw index assertions require a theme that inherits the ANSI palette.
+ const p = try Pardes.init(testing.allocator, .{ .startup_config = "Theme helix\n", .tty_only = true, .cols = 18, .rows = 6 });
defer p.deinit();
while (p.nextEffect()) |_| {}
const pane = p.panes[0].?;
@@ -7332,10 +7452,8 @@ pub const Terminal = struct {
}
test "terminal Filter keeps extended keys dark-to-light on a light theme" {
- const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true });
+ const p = try Pardes.init(std.testing.allocator, .{ .startup_config = "Theme acme\n", .tty_only = true });
defer p.deinit();
- // Curated order is a public theme contract: helix, dark, acme.
- p.settings.theme = 2;
try std.testing.expectEqualStrings("acme", p.theme().name);
var cache: FilterPalette = .{};
const palette = cache.get(p.theme());
@@ -7385,7 +7503,9 @@ pub const Terminal = struct {
const pane = p.panes[0].?;
try testing.expect(pane.tty_filter);
- for (0..3) |t| {
+ // Native dark/light palettes plus legacy helix/dark/acme, including
+ // the null-page fallback that only the legacy dark theme exercises.
+ for (0..9) |t| {
p.settings.theme = @intCast(t);
const stage_one = FilteredColors.init(p, pane);
// `dark` declares no background of its own, which is exactly why the
@@ -7424,7 +7544,7 @@ pub const Terminal = struct {
const tx = r.x + config.GUTTER;
const body_y = if (p.settings.tag_bottom) r.y else r.y + pardes.BOX_H;
- for (0..3) |t| {
+ for (0..9) |t| {
p.settings.theme = @intCast(t);
var fc = FilteredColors.init(p, pane);
const page = asPardesColor(fc.default_bg);
@@ -7476,7 +7596,7 @@ pub const Terminal = struct {
while (p.nextEffect()) |_| {}
const pane = p.panes[0].?;
- for (0..3) |t| {
+ for (0..9) |t| {
p.settings.theme = @intCast(t);
var fc = FilteredColors.init(p, pane);
var refused: usize = 0;
@@ -7515,8 +7635,8 @@ pub const Terminal = struct {
const r = p.rects[0];
const tx = r.x + config.GUTTER;
const body_y = if (p.settings.tag_bottom) r.y else r.y + pardes.BOX_H;
- const red: pardes.Color = .{ .index = 1 };
- const blue: pardes.Color = .{ .index = 4 };
+ const red: pardes.Color = .{ .rgb = p.theme().palette.?[1] };
+ const blue: pardes.Color = .{ .rgb = p.theme().palette.?[4] };
// tty mode projects the emulator's ansi colours cell for cell.
pane.mode = .tty;
@@ -7554,7 +7674,7 @@ pub const Terminal = struct {
const s = try p.render(frame.allocator());
try testing.expectEqualStrings(" ", s.at(tx, body_y).grapheme());
- try testing.expect(!std.meta.eql(pardes.Color{ .index = 1 }, s.at(tx, body_y).style.bg));
+ try testing.expect(!std.meta.eql(pardes.Color{ .rgb = p.theme().palette.?[1] }, s.at(tx, body_y).style.bg));
}
pub fn palColor(p: *Pardes, idx: u8) pardes.Color {
diff --git a/src/pardes.zig b/src/pardes.zig
index 8d5f0ba7..35080163 100644
--- a/src/pardes.zig
+++ b/src/pardes.zig
@@ -74,6 +74,8 @@ const column_weight_unit = layout.column_weight_unit;
const max_column_weight = layout.max_column_weight;
pub const MAX_JUMPS = 64;
pub const TOPBAR_H: u16 = 1;
+pub const COLBAR_H: u16 = 1;
+pub const TagLine = @import("tag_line.zig").Line;
pub const BOX_H: u16 = 1;
pub fn taglineBandOffset(row: u16, canvas_h: f32, cell_h: u32, tagline_h: u32) u32 {
@@ -93,6 +95,10 @@ pub fn topbarPaneBorderPixels(cell_h: u32, tagline_h: u32) u32 {
pub fn taglineOriginCol(p: *const Pardes, col: u16, row: u16, track: ?layout.Track) f32 {
if (row < TOPBAR_H) return 0;
+ if (row < TOPBAR_H + p.columnBarHeight()) {
+ for (p.col_x[0..p.ncol], p.col_w[0..p.ncol]) |x, w|
+ if (col >= x and col - x < w) return @floatFromInt(x);
+ }
if (track) |active| {
const box = active.contentBox();
const tag_y = if (p.settings.tag_bottom) box.y + box.h - @as(f32, @floatFromInt(BOX_H)) else box.y;
@@ -149,6 +155,18 @@ pub fn gridColAt(p: ?*const Pardes, x: f32, row: u16, body_w: f32, tagline_w: f3
const body = @max(body_w, 1);
const tag = @max(tagline_w, 1);
if (row < TOPBAR_H) return colFromSpan(x, tag);
+ if (p) |core| if (row < TOPBAR_H + core.columnBarHeight()) {
+ for (core.col_x[0..core.ncol], core.col_w[0..core.ncol]) |origin, width| {
+ if (width == 0) continue;
+ const left = @as(f32, @floatFromInt(origin)) * body;
+ const right = @as(f32, @floatFromInt(origin + width)) * body;
+ if (x < left or x >= right) continue;
+ return origin + @as(u16, @intFromFloat(@min(
+ @floor(@max(0, x - left) / tag),
+ @as(f32, @floatFromInt(width - 1)),
+ )));
+ }
+ };
if (p) |core| for (core.panes, 0..) |slot, id| {
if (slot == null) continue;
const r = core.rects[id];
@@ -195,6 +213,13 @@ test "a compact tagline anchors at its own pane, and both shells step from the s
const body_w: f32 = 10;
const tag_w: f32 = 8;
+ for (p.col_x[0..p.ncol], p.col_w[0..p.ncol]) |origin, width| {
+ if (width == 0) continue;
+ const col = origin;
+ try std.testing.expectEqual(@as(f32, @floatFromInt(origin)), taglineOriginCol(p, col, TOPBAR_H, null));
+ const glyph_x = @as(f32, @floatFromInt(origin)) * body_w;
+ try std.testing.expectEqual(col, gridColAt(p, glyph_x + tag_w / 2, TOPBAR_H, body_w, tag_w));
+ }
for ([_]u16{ 0, 1, 5, 40, 119 }) |col| {
const origin = taglineOriginCol(p, col, left.y, null);
const sdl = origin * (body_w - tag_w) + @as(f32, @floatFromInt(col)) * tag_w;
@@ -230,6 +255,7 @@ pub const Loc = struct {
test {}
const pane_tail = " " ++ config.pane_builtins_str;
+const pdf_pane_tail = " " ++ config.pdf_pane_builtins_str;
const file_pane_tail = " " ++ config.file_pane_builtins_str;
const terminal_pane_tail = " " ++ config.terminal_pane_builtins_str;
const dirty_marker = " *";
@@ -243,6 +269,15 @@ const legacy_terminal_pane_tail = " New Del Filter";
// ...and the terminal default from the release before Save reached it, when a
// scrollback was not yet something you could write to a path.
const prev_terminal_pane_tail = " New Newtty Del Filter";
+const pre_tty_terminal_pane_tail = " Save New Newtty Del Filter";
+const pre_column_pane_tail = " New Newtty Del";
+const pre_column_file_pane_tail = " Save New Newtty Del";
+const pre_column_pdf_pane_tail = " New Newtty Del PdfSections PdfTint";
+const pre_column_terminal_pane_tail = " Save New Newtty Del Tty Filter";
+const pre_collapse_pane_tail = " Tty Del";
+const pre_collapse_file_pane_tail = " Save Tty Del";
+const pre_collapse_pdf_pane_tail = " Tty Del PdfSections PdfTint";
+const pre_collapse_terminal_pane_tail = " Save Tty Del Togglettymode Filter";
const Builtin = builtins.registry.Builtin();
@@ -929,14 +964,14 @@ test "topbar hover highlights exactly the executable word" {
p.update(.{ .mouse = .{ .button = .none, .kind = .motion, .col = 1, .row = 0 } });
_ = frame.reset(.retain_capacity);
const hovered = try p.render(frame.allocator());
- for (0.."New".len) |col| {
+ for (0.."Newcol".len) |col| {
const cell = hovered.at(@intCast(col), 0);
try std.testing.expectEqual(Color{ .rgb = p.theme().sel_bg }, cell.style.bg);
try std.testing.expectEqual(Color{ .rgb = p.theme().sel_fg }, cell.style.fg);
}
- try std.testing.expectEqual(Color{ .rgb = p.chromeTheme().tag_bg }, hovered.at(3, 0).style.bg);
+ try std.testing.expectEqual(Color{ .rgb = p.chromeTheme().tag_bg }, hovered.at(6, 0).style.bg);
- p.update(.{ .mouse = .{ .button = .none, .kind = .motion, .col = 3, .row = 0 } });
+ p.update(.{ .mouse = .{ .button = .none, .kind = .motion, .col = 6, .row = 0 } });
_ = frame.reset(.retain_capacity);
const whitespace = try p.render(frame.allocator());
try std.testing.expectEqual(Color{ .rgb = p.chromeTheme().tag_bg }, whitespace.at(1, 0).style.bg);
@@ -947,7 +982,7 @@ test "topbar hover highlights exactly the executable word" {
try std.testing.expectEqual(Color{ .rgb = p.chromeTheme().tag_bg }, left.at(1, 0).style.bg);
}
-test "pane-tag Exec prefers New and argument builtins before shell fallback" {
+test "pane-tag Exec prefers Tty and argument builtins before shell fallback" {
const gpa = std.testing.allocator;
const p = try Pardes.init(gpa, .{ .cols = 100, .rows = 30 });
defer p.deinit();
@@ -955,12 +990,12 @@ test "pane-tag Exec prefers New and argument builtins before shell fallback" {
p.acknowledgeShell(0, "/bin/sh", false);
const pane = p.panes[0].?;
- try std.testing.expectEqualStrings(" Save New Newtty Del Filter", Pardes.curTail(pane));
+ try std.testing.expectEqualStrings(" Save Tty Del Togglettymode Filter Collapse", Pardes.curTail(pane));
const tag_x = p.rects[0].x + config.GUTTER;
const tag_y = p.rects[0].y;
const rendered = try p.tagText(p.scratch.allocator(), pane);
- const new_x = tag_x + @as(u16, @intCast(std.mem.indexOf(u8, rendered, "New").?)) + 1;
+ const new_x = tag_x + @as(u16, @intCast(std.mem.indexOf(u8, rendered, "Tty").?)) + 1;
var panes_before: usize = 0;
for (p.panes) |s| if (s != null) {
panes_before += 1;
@@ -976,7 +1011,7 @@ test "pane-tag Exec prefers New and argument builtins before shell fallback" {
panes_after += 1;
};
try std.testing.expectEqual(panes_before + 1, panes_after);
- try std.testing.expect(p.panes[p.active].?.file.?.output != null); // the scratch
+ try std.testing.expect(p.panes[p.active].?.isTerminal());
// Argument-taking builtins use the same gesture path: a tag sweep is the
// complete command line, and Theme consumes its tail without a PTY write.
@@ -1018,6 +1053,74 @@ test "pane-tag Exec prefers New and argument builtins before shell fallback" {
try std.testing.expectEqualStrings("DefinitelyNotABuiltin\r", sent[0..sent_len]);
}
+test "Collapse builtin keeps content and restores the pane from its default tag" {
+ const p = try Pardes.init(std.testing.allocator, .{ .cols = 100, .rows = 24, .tty_only = true });
+ defer p.deinit();
+ const pane = try p.setTestFile("keep this text\n");
+ p.sync();
+ const height = p.rects[0].h;
+ const revision = pane.file.?.revision;
+ for ([_][]const u8{ pane_tail, file_pane_tail, pdf_pane_tail, terminal_pane_tail }) |tail|
+ try std.testing.expect(std.mem.endsWith(u8, tail, " Collapse"));
+
+ try std.testing.expect(p.executeBuiltinLine(0, "Collapse"));
+ p.sync();
+ try std.testing.expect(pane.collapsed);
+ try std.testing.expectEqual(@as(u16, BOX_H), p.rects[0].h);
+ try std.testing.expectEqual(@as(f32, @floatFromInt(height)), pane.vweight);
+ try std.testing.expectEqual(revision, pane.file.?.revision);
+ try std.testing.expectEqualStrings("keep this text\n", pane.file.?.content);
+ try std.testing.expect((try p.render(p.scratch.allocator())).cursor == null);
+ p.enterTagEdit(pane, -1);
+ const tag_cursor = (try p.render(p.scratch.allocator())).cursor orelse return error.MissingTagCursor;
+ try std.testing.expectEqual(p.rects[0].y, tag_cursor.y);
+ Pardes.exitTagEdit(pane);
+ try std.testing.expect(p.executeBuiltinLine(0, "Collapse"));
+ p.sync();
+ try std.testing.expect(!pane.collapsed);
+ try std.testing.expectEqual(height, p.rects[0].h);
+
+ // Unedited defaults from the preceding version gain the new command.
+ pane.tag_init = false;
+ pane.tag_tail_len = 0;
+ p.restoreTailAt(pane, pre_collapse_file_pane_tail, "", .file);
+ try std.testing.expect(!pane.tag_init);
+ try std.testing.expectEqualStrings(file_pane_tail, Pardes.curTail(pane));
+}
+
+test "Togglettymode builtin and keyboard chord share mode transitions including edited tags" {
+ const p = try Pardes.init(std.testing.allocator, .{ .cols = 120, .rows = 20, .tty_only = true });
+ defer p.deinit();
+ const pane = p.panes[0].?;
+ try std.testing.expect(std.mem.indexOf(u8, Pardes.curTail(pane), " Togglettymode ") != null);
+ try std.testing.expectEqual(Pane.Mode.tty, pane.mode);
+ try std.testing.expect(p.executeBuiltinLine(0, "Togglettymode"));
+ try std.testing.expectEqual(Pane.Mode.normal, pane.mode);
+ p.update(.{ .key = .{ .cp = p.opts.tty_toggle, .ctrl = true } });
+ try std.testing.expectEqual(Pane.Mode.tty, pane.mode);
+ p.enterTagEdit(pane, -1);
+ try std.testing.expectEqual(Pane.Mode.insert, pane.mode);
+ try std.testing.expect(p.executeBuiltinLine(0, "Togglettymode"));
+ try std.testing.expectEqual(Pane.Mode.normal, pane.mode);
+ try std.testing.expect(!pane.tag_edit);
+ p.enterTagEdit(pane, -1);
+ p.update(.{ .key = .{ .cp = p.opts.tty_toggle, .ctrl = true } });
+ try std.testing.expectEqual(Pane.Mode.tty, pane.mode);
+ try std.testing.expect(!pane.tag_edit);
+
+ p.acknowledgePanelPresentation(&.{});
+ const tag = try p.tagText(p.scratch.allocator(), pane);
+ const x = p.rects[0].x + config.GUTTER + @as(u16, @intCast(std.mem.indexOf(u8, tag, "Togglettymode").?));
+ const y = p.rects[0].y;
+ p.update(.{ .mouse = .{ .button = .middle, .kind = .press, .col = x, .row = y } });
+ p.update(.{ .mouse = .{ .button = .middle, .kind = .release, .col = x, .row = y } });
+ try std.testing.expectEqual(Pane.Mode.normal, pane.mode);
+ const file = try p.setTestFile("unchanged\n");
+ try std.testing.expect(p.executeBuiltinLine(0, "Togglettymode"));
+ try std.testing.expectEqual(Pane.Mode.normal, file.mode);
+ try std.testing.expectEqualStrings("unchanged\n", file.file.?.content);
+}
+
test "Filter is ordered after Del and toggles only its terminal pane" {
const testing = std.testing;
const del = std.meta.stringToEnum(Builtin, "Del") orelse return error.MissingDelBuiltin;
@@ -1054,14 +1157,13 @@ test "Filter is ordered after Del and toggles only its terminal pane" {
try testing.expect(!second.tty_filter);
}
-test "an untouched tagline ends where its layout column's widest one does" {
+test "compact tag commands stay beside their own prefix across layout changes" {
const gpa = std.testing.allocator;
const p = try Pardes.init(gpa, .{ .cols = 100, .rows = 30 });
defer p.deinit();
while (p.nextEffect()) |_| {} // initial shell spawn/geometry
- // a second shell BELOW the first — what Alt-n does — sitting in a
- // directory too long to leave tag_right_pad columns free
+ // A longer sibling never introduces invisible padding into this tag.
const below_id = p.freeSlot().?;
const below = try p.newShell(below_id, "");
const f = layout.findPane(p, p.active).?;
@@ -1073,34 +1175,32 @@ test "an untouched tagline ends where its layout column's widest one does" {
const above = p.panes[0].?;
try std.testing.expectEqual(p.rects[0].x, p.rects[below_id].x);
- const above_tag = try p.tagText(p.scratch.allocator(), above);
+ const above_tag = try p.tagText(gpa, above);
+ defer gpa.free(above_tag);
const below_tag = try p.tagText(p.scratch.allocator(), below);
- try std.testing.expectEqual(below_tag.len, above_tag.len);
- const tail = " Save New Newtty Del Filter";
+ try std.testing.expect(below_tag.len > above_tag.len);
+ const tail = " Save Tty Del Togglettymode Filter Collapse";
try std.testing.expectEqualStrings(tail, above_tag[above_tag.len - tail.len ..]);
- try std.testing.expect(above_tag.len > @as(usize, p.rects[0].w) - config.GUTTER - config.tag_right_pad);
- try std.testing.expect(above_tag.len <= @as(usize, p.rects[0].w) - config.GUTTER);
+ try std.testing.expectEqual(above.cwdSlice().len + tail.len, above_tag.len);
p.update(.{ .resize = .{ .cols = 88, .rows = 30 } });
while (p.nextEffect()) |_| {}
- const fits = (try p.tagText(p.scratch.allocator(), above)).len;
+ try std.testing.expectEqualStrings(above_tag, try p.tagText(p.scratch.allocator(), above));
p.update(.{ .resize = .{ .cols = 87, .rows = 30 } });
while (p.nextEffect()) |_| {}
- try std.testing.expectEqual(fits - 1, (try p.tagText(p.scratch.allocator(), above)).len);
+ try std.testing.expectEqualStrings(above_tag, try p.tagText(p.scratch.allocator(), above));
p.update(.{ .resize = .{ .cols = 100, .rows = 30 } });
while (p.nextEffect()) |_| {}
p.seedTail(below);
+ try std.testing.expectEqualStrings(tail, below.tagSlice());
try std.testing.expect(below.appendTag(" lots and lots of typing out here"));
try std.testing.expectEqual(above_tag.len, (try p.tagText(p.scratch.allocator(), above)).len);
p.update(.{ .resize = .{ .cols = 100, .rows = 2 } });
while (p.nextEffect()) |_| {}
try std.testing.expectEqual(@as(u16, 0), p.rects[below_id].h);
- try std.testing.expectEqual(
- @as(usize, p.rects[0].w) - config.GUTTER - config.tag_right_pad,
- (try p.tagText(p.scratch.allocator(), above)).len,
- );
+ try std.testing.expectEqualStrings(above_tag, try p.tagText(p.scratch.allocator(), above));
}
test "legacy default tag tails upgrade while custom tails remain owned" {
@@ -1115,14 +1215,14 @@ test "legacy default tag tails upgrade while custom tails remain owned" {
});
p.restoreTail(terminal, terminal_old);
try std.testing.expect(!terminal.tag_init);
- try std.testing.expectEqualStrings(" Save New Newtty Del Filter", Pardes.curTail(terminal));
+ try std.testing.expectEqualStrings(" Save Tty Del Togglettymode Filter Collapse", Pardes.curTail(terminal));
const terminal_previous = try std.fmt.allocPrint(p.scratch.allocator(), "{s} New Del", .{
try p.tagPrefix(terminal),
});
p.restoreTail(terminal, terminal_previous);
try std.testing.expect(!terminal.tag_init);
- try std.testing.expectEqualStrings(" Save New Newtty Del Filter", Pardes.curTail(terminal));
+ try std.testing.expectEqualStrings(" Save Tty Del Togglettymode Filter Collapse", Pardes.curTail(terminal));
const terminal_prefilter = try std.fmt.allocPrint(p.scratch.allocator(), "{s}{s}", .{
try p.tagPrefix(terminal),
@@ -1130,7 +1230,7 @@ test "legacy default tag tails upgrade while custom tails remain owned" {
});
p.restoreTail(terminal, terminal_prefilter);
try std.testing.expect(!terminal.tag_init);
- try std.testing.expectEqualStrings(" Save New Newtty Del Filter", Pardes.curTail(terminal));
+ try std.testing.expectEqualStrings(" Save Tty Del Togglettymode Filter Collapse", Pardes.curTail(terminal));
const terminal_custom = try std.fmt.allocPrint(p.scratch.allocator(), "{s} Keep Del", .{
try p.tagPrefix(terminal),
@@ -1159,7 +1259,7 @@ test "legacy default tag tails upgrade while custom tails remain owned" {
.terminal = .{ .cwd = "/historical/cwd" },
});
try std.testing.expect(!terminal.tag_init);
- try std.testing.expectEqualStrings(" Save New Newtty Del Filter", Pardes.curTail(terminal));
+ try std.testing.expectEqualStrings(" Save Tty Del Togglettymode Filter Collapse", Pardes.curTail(terminal));
// This happens to be the historical FILE default, but on a terminal it is
// user-owned text and must not be swallowed by migration.
@@ -1181,7 +1281,7 @@ test "legacy default tag tails upgrade while custom tails remain owned" {
});
p.restoreTail(file, file_old);
try std.testing.expect(!file.tag_init);
- try std.testing.expectEqualStrings(" Save New Newtty Del", Pardes.curTail(file));
+ try std.testing.expectEqualStrings(" Save Tty Del Collapse", Pardes.curTail(file));
const file_custom = try std.fmt.allocPrint(p.scratch.allocator(), "{s} Save Mine Del", .{
try p.tagPrefix(file),
@@ -1202,7 +1302,7 @@ test "legacy default tag tails upgrade while custom tails remain owned" {
try std.testing.expectEqualStrings(" New Del", Pardes.curTail(file));
const image_doc = try panes.Image.create(p, 1, "/tmp/legacy image.ppm", &.{});
- try std.testing.expectEqualStrings(" New Newtty Del", Pardes.curTail(image_doc));
+ try std.testing.expectEqualStrings(" Tty Del Collapse", Pardes.curTail(image_doc));
p.restoreDumpTail(image_doc, .{
.kind = .image,
.tag = "img /tmp/legacy image.ppm Keep Del",
@@ -1236,14 +1336,14 @@ test "Joincol folds the active column into its right neighbor, keeping its panes
try std.testing.expectEqual(@as(usize, 1), p.ncol);
}
-test "Newtty spawns a raw shell in the caller's directory" {
+test "Tty spawns a raw shell in the caller's directory" {
const gpa = std.testing.allocator;
const p = try Pardes.init(gpa, .{ .tty_only = true, .cols = 100, .rows = 30 });
defer p.deinit();
while (p.nextEffect()) |_| {}
p.setCwd(0, "/tmp/newtty-dir");
- p.spawnTty(0);
+ try std.testing.expect(p.executeBuiltinLine(0, "Tty"));
const free = p.active;
try std.testing.expect(free != 0);
const nt = p.panes[free] orelse return error.NoNewPane;
@@ -1261,6 +1361,85 @@ test "Newtty spawns a raw shell in the caller's directory" {
try std.testing.expect(found);
}
+test "first document fallback splits like Tty from the originating pane" {
+ for ([_]u16{ 100, 198 }) |width| for (0..3) |from| {
+ for ([_]bool{ false, true }) |collapsed| {
+ const p = try Pardes.init(std.testing.allocator, .{ .cols = width, .rows = 62, .shells = 3 });
+ defer p.deinit();
+ const tty = try Pardes.init(std.testing.allocator, .{ .cols = width, .rows = 62, .shells = 3 });
+ defer tty.deinit();
+ if (collapsed) {
+ layout.toggleCollapse(p, from);
+ layout.toggleCollapse(tty, from);
+ }
+ p.sync();
+ tty.sync();
+ const before = p.rects;
+ const parent = layout.splitParent(p, from);
+ const at = layout.findPane(p, parent).?;
+ // The Look origin need not be the currently active pane.
+ p.active = (from + 1) % 3;
+ const free = p.freeSlot().?;
+ const doc = try p.openTutorView(free);
+ p.placeDoc(from, free, doc);
+ tty.spawnTty(from);
+ p.sync();
+ tty.sync();
+ try std.testing.expectEqual(@as(usize, 2), p.ncol);
+ try std.testing.expectEqual(free, p.active);
+ try std.testing.expectEqual(free, p.col_panes[at.col][at.idx + 1]);
+ for (0..3) |id| {
+ try std.testing.expect(p.panes[id] != null);
+ if (id != parent) try std.testing.expectEqualDeep(before[id], p.rects[id]);
+ }
+ for (0..4) |id| try std.testing.expectEqualDeep(tty.rects[id], p.rects[id]);
+ for (0..p.ncol) |col| {
+ try std.testing.expectEqualSlices(usize, tty.col_panes[col][0..tty.col_n[col]], p.col_panes[col][0..p.col_n[col]]);
+ }
+ }
+ };
+}
+
+test "first document keeps its originating shell and only opens a column when it fits" {
+ for ([_]u16{ 199, 200 }) |width| {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = width, .rows = 32 });
+ defer p.deinit();
+ const shell = p.panes[0].?;
+ const doc = try p.openTutorView(1);
+ p.placeDoc(0, 1, doc);
+ p.sync();
+ try std.testing.expectEqual(shell, p.panes[0].?);
+ try std.testing.expectEqual(@as(usize, 1), p.active);
+ if (width < 200) {
+ try std.testing.expectEqual(@as(usize, 1), p.ncol);
+ try std.testing.expectEqualSlices(usize, &.{ 0, 1 }, p.col_panes[0][0..p.col_n[0]]);
+ try std.testing.expectEqual(p.rects[0].y + p.rects[0].h, p.rects[1].y);
+ } else {
+ try std.testing.expectEqual(@as(usize, 2), p.ncol);
+ try std.testing.expectEqual(@as(usize, 1), p.col_panes[0][0]);
+ try std.testing.expectEqual(@as(usize, 0), p.col_panes[1][0]);
+ }
+ }
+}
+
+test "pane defaults keep creation of scratch panes in column tags" {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true });
+ defer p.deinit();
+ for ([_][]const u8{ pane_tail, file_pane_tail, pdf_pane_tail, terminal_pane_tail, config.topbar_str }) |tag| {
+ var words = std.mem.tokenizeScalar(u8, tag, ' ');
+ while (words.next()) |word| try std.testing.expect(!std.mem.eql(u8, word, "New"));
+ }
+ try std.testing.expectEqualStrings("New Tty Find Grep Joincol", p.columnTag(0));
+ const terminal = p.panes[0].?;
+ p.restoreTailAt(terminal, pre_column_terminal_pane_tail, "", .terminal);
+ try std.testing.expect(!terminal.tag_init);
+ try std.testing.expectEqualStrings(terminal_pane_tail, Pardes.curTail(terminal));
+ const file = try p.setTestFile("unchanged\n");
+ p.restoreTailAt(file, pre_column_file_pane_tail, "", .file);
+ try std.testing.expect(!file.tag_init);
+ try std.testing.expectEqualStrings(file_pane_tail, Pardes.curTail(file));
+}
+
test "an unsaved file marker sits between its path and builtins until Save" {
const gpa = std.testing.allocator;
const p = try Pardes.init(gpa, .{ .tty_only = true, .cols = 100, .rows = 30 });
@@ -1904,7 +2083,7 @@ test "Save on an output buffer writes its rows out and leaves the buffer alone"
defer gpa.free(rows);
// Save leads its tagline now, and the path is REQUIRED: a bare Save asks
- try std.testing.expectEqualStrings(" Save New Newtty Del", Pardes.curTail(out));
+ try std.testing.expectEqualStrings(" Save Tty Del Collapse", Pardes.curTail(out));
try std.testing.expect(p.executeBuiltinLine(id, "Save"));
try std.testing.expect(out.prompt == .save);
try std.testing.expect(out.appendTag("help.txt"));
@@ -2092,7 +2271,7 @@ test "Save reaches every tagline with text behind it and no other" {
const out = try p.setTestFile("build.zig:1:1 pub fn main\n");
out.file.?.output = .{ .from = .search };
- try std.testing.expectEqualStrings(" Save New Newtty Del", Pardes.curTail(out));
+ try std.testing.expectEqualStrings(" Save Tty Del Collapse", Pardes.curTail(out));
// A dump written before Save reached output buffers carries the generic
// tail. That is a DEFAULT and not something typed, so it upgrades.
@@ -2102,7 +2281,7 @@ test "Save reaches every tagline with text behind it and no other" {
});
p.restoreTail(out, dumped);
try std.testing.expect(!out.tag_init);
- try std.testing.expectEqualStrings(" Save New Newtty Del", Pardes.curTail(out));
+ try std.testing.expectEqualStrings(" Save Tty Del Collapse", Pardes.curTail(out));
// A scratch is an output buffer that has worn the FILE tails all along,
// so its own older default upgrades from that family too.
@@ -2115,13 +2294,13 @@ test "Save reaches every tagline with text behind it and no other" {
});
p.restoreTail(out, scratch_dumped);
try std.testing.expect(!out.tag_init);
- try std.testing.expectEqualStrings(" Save New Newtty Del", Pardes.curTail(out));
+ try std.testing.expectEqualStrings(" Save Tty Del Collapse", Pardes.curTail(out));
// An image's bytes on disk already are what they are: nothing of the
// pane's own is unwritten, so the word is absent and inert.
const img_id = p.freeSlot().?;
const img = try panes.Image.create(p, img_id, "/tmp/pardes-tag.ppm", &.{});
- try std.testing.expectEqualStrings(" New Newtty Del", Pardes.curTail(img));
+ try std.testing.expectEqualStrings(" Tty Del Collapse", Pardes.curTail(img));
try std.testing.expect(p.executeBuiltinLine(img_id, "Save"));
try std.testing.expect(img.prompt != .save);
var buf: [256]u8 = undefined;
@@ -2254,6 +2433,7 @@ test "Font keeps requested and acknowledged faces as separate plain state" {
try std.testing.expect(p.settings.font.pending);
try std.testing.expectEqualStrings(installed[0].name, p.settings.font.requested_name.get());
try std.testing.expectEqualStrings(installed[0].path, p.settings.font.requested_path.get());
+ try std.testing.expectEqual(@as(u16, 0), p.settings.font.requested_size_hundredths);
try std.testing.expectEqualStrings("", p.settings.font.effective_name.get());
// Boot/zoom/display-scale reports describe the face already being drawn;
@@ -2302,6 +2482,48 @@ test "Font keeps requested and acknowledged faces as separate plain state" {
try std.testing.expectEqualStrings(installed[0].name, p.settings.font.effective_name.get());
}
+test "Font size suffix reaches native request and invalid input leaves it intact" {
+ if (comptime !font_picker) return;
+ const p = try Pardes.init(std.testing.allocator, .{ .cols = 80, .rows = 24 });
+ defer p.deinit();
+ var arena: std.heap.ArenaAllocator = .init(std.testing.allocator);
+ defer arena.deinit();
+ const installed = fonts.list(arena.allocator(), null);
+ if (installed.len == 0) return;
+ var line: [512]u8 = undefined;
+ try std.testing.expect(p.executeBuiltinLine(p.active, try std.fmt.bufPrint(&line, "Font {s}:18.5", .{installed[0].name})));
+ try std.testing.expectEqual(@as(u16, 1850), p.settings.font.requested_size_hundredths);
+ try std.testing.expectEqualStrings(installed[0].path, p.takeFontRequest().?);
+ try std.testing.expect(p.acknowledgeFont(installed[0].name, 1850, .pixels));
+ try std.testing.expect(p.executeBuiltinLine(p.active, try std.fmt.bufPrint(&line, "Font {s}:nan", .{installed[0].name})));
+ try std.testing.expectEqual(@as(u16, 1850), p.settings.font.requested_size_hundredths);
+ try std.testing.expect(p.takeFontRequest() == null);
+ try std.testing.expect(p.executeBuiltinLine(p.active, "Font zzz-no-such-face:20"));
+ try std.testing.expectEqual(@as(u16, 1850), p.settings.font.requested_size_hundredths);
+ try std.testing.expect(p.takeFontRequest() == null);
+ try std.testing.expect(p.executeBuiltinLine(p.active, try std.fmt.bufPrint(&line, "Font {s}", .{installed[0].name})));
+ try std.testing.expectEqual(@as(u16, 0), p.settings.font.requested_size_hundredths);
+ try std.testing.expectEqual(@as(u16, 1850), p.settings.font.effective_size_hundredths);
+}
+
+test "Pet command is SDL-only optional and validates its argument" {
+ const p = try Pardes.init(std.testing.allocator, .{ .cols = 80, .rows = 24 });
+ defer p.deinit();
+ try std.testing.expectEqual(.off, p.settings.pet);
+ if (comptime platform != .gui) {
+ try std.testing.expect(std.meta.stringToEnum(builtins.registry.Builtin(), "Pet") == null);
+ return;
+ }
+ try std.testing.expect(p.executeBuiltinLine(p.active, "Pet cat"));
+ try std.testing.expectEqual(.cat, p.settings.pet);
+ try std.testing.expect(p.executeBuiltinLine(p.active, "Pet dog"));
+ try std.testing.expectEqual(.cat, p.settings.pet);
+ try std.testing.expect(p.executeBuiltinLine(p.active, "Pet frog"));
+ try std.testing.expectEqual(.frog, p.settings.pet);
+ try std.testing.expect(p.executeBuiltinLine(p.active, "Pet off"));
+ try std.testing.expectEqual(.off, p.settings.pet);
+}
+
test "startup config overrides restored styling before initFromDump returns" {
const source = try Pardes.init(std.testing.allocator, .{ .startup_config = "Theme dark\n" });
defer source.deinit();
@@ -2589,9 +2811,39 @@ pub const Theme = struct {
scroll_track: [3]u8,
scroll_thumb: [3]u8,
palette: ?[16][3]u8,
+
+ // Pardes UI roles. Optional so existing ThemeFile documents and imported
+ // editor palettes keep working; ChromeTheme resolves their legacy defaults.
+ tag_active_bg: ?[3]u8 = null,
+ tag_active_fg: ?[3]u8 = null,
+ border: ?[3]u8 = null,
+ search_bg: ?[3]u8 = null,
+ search_fg: ?[3]u8 = null,
+ diagnostic_error: ?[3]u8 = null,
+ diagnostic_warning: ?[3]u8 = null,
+ diagnostic_info: ?[3]u8 = null,
+ diagnostic_hint: ?[3]u8 = null,
+ // The current line number is a quiet foreground cue, not a tag-colored
+ // background block. Older themes fall back to their normal gutter ink.
+ lineno_active: ?[3]u8 = null,
};
const curated = struct {
+ pub const orchard = @import("themes/orchard.zig");
+ pub const dusk = @import("themes/dusk.zig");
+ pub const ink = @import("themes/ink.zig");
+ pub const paper = @import("themes/paper.zig");
+ pub const daybreak = @import("themes/daybreak.zig");
+ pub const atelier = @import("themes/atelier.zig");
+ pub const forge = @import("themes/forge.zig");
+ pub const lagoon = @import("themes/lagoon.zig");
+ pub const solarium = @import("themes/solarium.zig");
+ pub const spectrum = @import("themes/spectrum.zig");
+ pub const harvest = @import("themes/harvest.zig");
+ pub const clay = @import("themes/clay.zig");
+ pub const forge_black = @import("themes/forge_black.zig");
+ pub const forge_soft = @import("themes/forge_soft.zig");
+ pub const orchard_black = @import("themes/orchard_black.zig");
pub const helix = @import("themes/helix.zig");
pub const dark = @import("themes/dark.zig");
pub const acme = @import("themes/acme.zig");
@@ -2603,8 +2855,15 @@ fn fold(comptime C: type) [@typeInfo(C).@"struct".decls.len]Theme {
var out: [@typeInfo(C).@"struct".decls.len]Theme = undefined;
for (@typeInfo(C).@"struct".decls, 0..) |d, i| {
var t: Theme = undefined;
- for (@typeInfo(Theme).@"struct".fields) |f|
- @field(t, f.name) = @field(@field(C, d.name).theme, f.name);
+ const source = @field(C, d.name).theme;
+ for (@typeInfo(Theme).@"struct".fields) |f| {
+ @field(t, f.name) = if (@hasField(@TypeOf(source), f.name))
+ @field(source, f.name)
+ else if (f.default_value_ptr) |ptr|
+ @as(*const f.type, @ptrCast(@alignCast(ptr))).*
+ else
+ @compileError("theme " ++ d.name ++ " is missing " ++ f.name);
+ }
out[i] = t;
}
return out;
@@ -2613,6 +2872,134 @@ fn fold(comptime C: type) [@typeInfo(C).@"struct".decls.len]Theme {
pub const themes = fold(curated) ++ fold(@import("generated_themes"));
+/// Original and classic-inspired Pardes palettes precede retained imports.
+pub const native_theme_count = 15;
+
+fn themeContrast(a: [3]u8, b: [3]u8) f64 {
+ var luminance: [2]f64 = .{ 0, 0 };
+ for ([2][3]u8{ a, b }, 0..) |rgb, i| {
+ for (rgb, [3]f64{ 0.2126, 0.7152, 0.0722 }) |channel, weight| {
+ const srgb = @as(f64, @floatFromInt(channel)) / 255;
+ const linear = if (srgb <= 0.04045) srgb / 12.92 else std.math.pow(f64, (srgb + 0.055) / 1.055, 2.4);
+ luminance[i] += weight * linear;
+ }
+ }
+ return (@max(luminance[0], luminance[1]) + 0.05) / (@min(luminance[0], luminance[1]) + 0.05);
+}
+
+test "native themes keep text and UI roles readable on their own surfaces" {
+ const names = [_][]const u8{ "orchard", "dusk", "ink", "paper", "daybreak", "atelier", "forge", "lagoon", "solarium", "spectrum", "harvest", "clay", "forge_black", "forge_soft", "orchard_black" };
+ try std.testing.expectEqual(names.len, native_theme_count);
+ for (themes[0..names.len], names) |th, name| {
+ try std.testing.expectEqualStrings(name, th.name);
+ const chrome = ChromeTheme.fromTheme(&th);
+ const minimum: f64 = if (std.mem.eql(u8, name, "ink") or std.mem.eql(u8, name, "daybreak")) 7 else 4.5;
+ const text_colors = [_][3]u8{
+ th.fg.?, th.kw, th.str, th.num, th.comment,
+ chrome.diagnostic_error, chrome.diagnostic_warning, chrome.diagnostic_info, chrome.diagnostic_hint,
+ };
+ for (text_colors) |fg| try std.testing.expect(themeContrast(fg, th.bg.?) >= minimum);
+ // Gutters are orientation aids, not source text: stay visible without
+ // competing with comments or pulling attention away from the body.
+ try std.testing.expect(themeContrast(th.lineno, th.bg.?) >= 2.5);
+ try std.testing.expect(themeContrast(th.lineno, th.bg.?) <= 4);
+ try std.testing.expect(themeContrast(th.lineno_active.?, th.bg.?) >= themeContrast(th.lineno, th.bg.?));
+ try std.testing.expect(themeContrast(th.lineno_active.?, th.bg.?) <= 4.5);
+ try std.testing.expect(themeContrast(th.comment, th.bg.?) >= 5);
+ try std.testing.expect(themeContrast(th.comment, th.bg.?) >= themeContrast(th.lineno, th.bg.?) + 2);
+ try std.testing.expect(themeContrast(th.tag_fg, th.tag_bg) >= minimum);
+ try std.testing.expect(themeContrast(chrome.tag_active_fg, chrome.tag_active_bg) >= minimum);
+ // Focus stays on the same tonal surface, rather than inverting a
+ // whole command strip. Text remains readable in both states.
+ try std.testing.expect(themeContrast(chrome.tag_active_bg, th.tag_bg) <= 1.6);
+ try std.testing.expect(themeContrast(chrome.tag_active_fg, th.tag_fg) <= 1.6);
+ try std.testing.expect(themeContrast(th.sel_fg, th.sel_bg) >= minimum);
+ try std.testing.expect(themeContrast(chrome.search_fg, chrome.search_bg) >= minimum);
+ // ANSI black can intentionally match the page (for backgrounds). All
+ // other ANSI foregrounds, including bright black, remain legible.
+ for (th.palette.?[1..]) |fg| try std.testing.expect(themeContrast(fg, th.bg.?) >= minimum);
+ }
+}
+
+test "native dark palettes choose near-black or deliberately soft contrast" {
+ for (themes[0..native_theme_count]) |th| {
+ if (themeContrast(th.bg.?, .{ 0, 0, 0 }) > 10) continue; // light paper
+ const soft = std.mem.eql(u8, th.name, "dusk") or std.mem.eql(u8, th.name, "lagoon") or
+ std.mem.eql(u8, th.name, "solarium") or std.mem.eql(u8, th.name, "forge_soft");
+ if (soft) {
+ try std.testing.expect(themeContrast(th.fg.?, th.bg.?) >= 4.5);
+ try std.testing.expect(themeContrast(th.fg.?, th.bg.?) <= 7);
+ } else {
+ for (th.bg.?) |channel| try std.testing.expect(channel <= 0x14);
+ try std.testing.expect(themeContrast(th.fg.?, th.bg.?) >= 14);
+ }
+ }
+ const forge = curated.forge.theme;
+ try std.testing.expectEqual(forge.bg[0], forge.bg[1]);
+ // Forge chrome is cool-neutral, never the old green-over-blue mint cast.
+ for ([_][3]u8{ forge.tag_bg, forge.tag_active_bg, forge.box, forge.border }) |rgb|
+ try std.testing.expect(rgb[2] >= rgb[1]);
+ try std.testing.expectEqual([3]u8{ 0, 0, 0 }, @as([3]u8, curated.forge_black.theme.bg));
+ try std.testing.expectEqual([3]u8{ 0, 0, 0 }, @as([3]u8, curated.orchard_black.theme.bg));
+}
+
+test "line numbers stay quiet without a current-line tag background" {
+ const gpa = std.testing.allocator;
+ const p = try Pardes.init(gpa, .{ .tty_only = true, .cols = 80, .rows = 24 });
+ defer p.deinit();
+ const pane = try p.setTestFile("first\nsecond\n");
+ pane.cur_pinned = true;
+ pane.cur_row = 0;
+ var custom = themes[0];
+ custom.name = try gpa.dupe(u8, "quiet-gutter");
+ custom.lineno = .{ 70, 70, 70 };
+ custom.lineno_active = .{ 95, 95, 95 };
+ p.custom_theme = custom;
+ p.sync();
+ const x = p.rects[0].x + config.GUTTER;
+ const y = p.rects[0].y + BOX_H;
+ for ([_]bool{ false, true }) |focus_tint| {
+ p.settings.focus_tint = focus_tint;
+ const surface = try p.render(p.scratch.allocator());
+ try std.testing.expectEqual(Color{ .rgb = .{ 95, 95, 95 } }, surface.at(x, y).style.fg);
+ try std.testing.expectEqual(Color{ .rgb = .{ 70, 70, 70 } }, surface.at(x, y + 1).style.fg);
+ try std.testing.expectEqual(Color{ .rgb = custom.bg.? }, surface.at(x, y).style.bg);
+ try std.testing.expect(surface.at(x, y).style.bold);
+ try std.testing.expect(!surface.at(x, y + 1).style.bold);
+ }
+ // Old ThemeFile palettes need no new field, and do not regain the block.
+ p.custom_theme.?.lineno_active = null;
+ const fallback = try p.render(p.scratch.allocator());
+ try std.testing.expectEqual(Color{ .rgb = .{ 70, 70, 70 } }, fallback.at(x, y).style.fg);
+ try std.testing.expectEqual(Color{ .rgb = custom.bg.? }, fallback.at(x, y).style.bg);
+ try std.testing.expect(fallback.at(x, y).style.bold);
+ // Moving the caret clears the previous cue; editing the tag parks it.
+ pane.cur_row = 1;
+ const moved = try p.render(p.scratch.allocator());
+ try std.testing.expect(!moved.at(x, y).style.bold);
+ try std.testing.expect(moved.at(x, y + 1).style.bold);
+ p.enterTagEdit(pane, -1);
+ const tag_edit = try p.render(p.scratch.allocator());
+ try std.testing.expect(!tag_edit.at(x, y + 1).style.bold);
+}
+
+test "legacy ThemeFile documents inherit Pardes UI roles without new fields" {
+ @setEvalBranchQuota(10000);
+ var encoded: std.Io.Writer.Allocating = .init(std.testing.allocator);
+ defer encoded.deinit();
+ try std.zon.stringify.serialize(curated.helix.theme, .{ .whitespace = true }, &encoded.writer);
+ const source = try std.testing.allocator.dupeZ(u8, encoded.written());
+ defer std.testing.allocator.free(source);
+ const parsed = try std.zon.parse.fromSliceAlloc(Theme, std.testing.allocator, source, null, .{});
+ defer std.zon.parse.free(std.testing.allocator, parsed);
+ try std.testing.expectEqual(@as(?[3]u8, null), parsed.tag_active_bg);
+ try std.testing.expectEqual(@as(?[3]u8, null), parsed.search_bg);
+ const chrome = ChromeTheme.fromTheme(&parsed);
+ try std.testing.expectEqual(parsed.tag_bg, chrome.tag_active_bg);
+ try std.testing.expectEqual(parsed.sel_bg, chrome.search_bg);
+ try std.testing.expectEqual(parsed.fg.?, chrome.diagnostic_error);
+}
+
comptime {
if (themes.len > std.math.maxInt(u16) + 1)
@compileError("runtime config theme index no longer fits u16");
@@ -2667,6 +3054,15 @@ test "every line of the board's boot buffer renders whole" {
pub const ChromeTheme = struct {
tag_bg: [3]u8,
tag_fg: [3]u8,
+ tag_active_bg: [3]u8,
+ tag_active_fg: [3]u8,
+ border: [3]u8,
+ search_bg: [3]u8,
+ search_fg: [3]u8,
+ diagnostic_error: [3]u8,
+ diagnostic_warning: [3]u8,
+ diagnostic_info: [3]u8,
+ diagnostic_hint: [3]u8,
box: [3]u8,
box_dim: [3]u8,
lineno: [3]u8,
@@ -2677,6 +3073,15 @@ pub const ChromeTheme = struct {
return .{
.tag_bg = th.tag_bg,
.tag_fg = th.tag_fg,
+ .tag_active_bg = th.tag_active_bg orelse th.tag_bg,
+ .tag_active_fg = th.tag_active_fg orelse th.tag_fg,
+ .border = th.border orelse th.scroll_track,
+ .search_bg = th.search_bg orelse th.sel_bg,
+ .search_fg = th.search_fg orelse th.sel_fg,
+ .diagnostic_error = th.diagnostic_error orelse (th.fg orelse th.tag_fg),
+ .diagnostic_warning = th.diagnostic_warning orelse (th.fg orelse th.tag_fg),
+ .diagnostic_info = th.diagnostic_info orelse (th.fg orelse th.tag_fg),
+ .diagnostic_hint = th.diagnostic_hint orelse (th.fg orelse th.tag_fg),
.box = th.box,
.box_dim = th.box_dim,
.lineno = th.lineno,
@@ -3459,6 +3864,8 @@ test "tabbed file aligns syntax cursor and mouse while preserving virtual column
const gpa = std.testing.allocator;
const p = try Pardes.init(gpa, .{ .cols = 60, .rows = 12 });
defer p.deinit();
+ // Bold is an explicit preference; use it to expose the glyph boundaries.
+ try std.testing.expect(p.executeBuiltinLine(0, "SyntaxBold"));
const pane = try p.setTestFile("\treturn x\n");
const f = &pane.file.?;
f.highlights = try p.tree_sitter_gpa.alloc(u8, f.content.len);
@@ -3685,6 +4092,207 @@ test "selection drag and queued release do not enter panel pending state" {
try std.testing.expectEqual(.done, pane.sel[sel_slot].state);
}
+test "editable workspace and column tags replace selections and persist" {
+ const p = try Pardes.init(std.testing.allocator, .{ .cols = 100, .rows = 20, .tty_only = true });
+ defer p.deinit();
+ _ = try p.setTestFile("untouched\n");
+ p.acknowledgePanelPresentation(&.{});
+ try std.testing.expectEqual(TOPBAR_H + COLBAR_H, p.rects[0].y);
+ p.update(.{ .mouse = .{ .button = .left, .kind = .press, .col = 0, .row = 0 } });
+ p.update(.{ .mouse = .{ .button = .left, .kind = .drag, .col = 6, .row = 0 } });
+ p.update(.{ .mouse = .{ .button = .left, .kind = .release, .col = 6, .row = 0 } });
+ p.update(.{ .key = .{ .cp = 'H', .text = "Help" } });
+ try std.testing.expect(std.mem.startsWith(u8, p.global_tag.slice(""), "Help Joincol"));
+ p.update(.{ .key = .{ .cp = Key.escape } });
+ p.update(.{ .mouse = .{ .button = .left, .kind = .press, .col = 0, .row = TOPBAR_H } });
+ p.update(.{ .mouse = .{ .button = .left, .kind = .release, .col = 0, .row = TOPBAR_H } });
+ p.update(.{ .key = .{ .cp = 'é', .text = "é" } });
+ try std.testing.expect(std.mem.startsWith(u8, p.columnTag(0), "éNew"));
+ p.update(.{ .key = .{ .cp = Key.backspace } });
+ try std.testing.expect(std.mem.startsWith(u8, p.columnTag(0), "New"));
+ p.update(.{ .paste = "Grep " });
+ try std.testing.expect(std.mem.startsWith(u8, p.columnTag(0), "Grep New"));
+ try std.testing.expectEqualStrings("untouched\n", p.panes[0].?.file.?.content);
+ try p.dumpState();
+ const restored = try p.restore(p.dump_out.?);
+ defer restored.deinit();
+ try std.testing.expectEqualStrings(p.global_tag.slice(""), restored.global_tag.slice(""));
+ try std.testing.expectEqualStrings(p.columnTag(0), restored.columnTag(0));
+ try std.testing.expect(p.col_tags[0].set(""));
+ try p.dumpState();
+ const empty = try p.restore(p.dump_out.?);
+ defer empty.deinit();
+ try std.testing.expectEqualStrings("", empty.columnTag(0));
+}
+
+test "column tags follow their column through split and close" {
+ const p = try Pardes.init(std.testing.allocator, .{ .cols = 120, .rows = 20, .tty_only = true });
+ defer p.deinit();
+ _ = try p.setTestFile("left\n");
+ try std.testing.expect(p.col_tags[0].set("Left Find"));
+ _ = p.execute(0, "Newcol");
+ try std.testing.expectEqual(@as(usize, 2), p.ncol);
+ try std.testing.expectEqualStrings("Left Find", p.columnTag(0));
+ try std.testing.expect(p.col_tags[1].set("Right Grep"));
+ p.active = p.col_panes[0][0];
+ layout.joinCol(p);
+ try std.testing.expectEqual(@as(usize, 1), p.ncol);
+ try std.testing.expectEqualStrings("Right Grep", p.columnTag(0));
+}
+
+test "column tags render edit hover and scroll from the column edge" {
+ const p = try Pardes.init(std.testing.allocator, .{ .cols = 80, .rows = 20, .tty_only = true });
+ defer p.deinit();
+ _ = try p.setTestFile("untouched\n");
+ p.newScratchColumn(0);
+ p.sync();
+ p.acknowledgePanelPresentation(&.{});
+ var frame = std.heap.ArenaAllocator.init(std.testing.allocator);
+ defer frame.deinit();
+ for (0..p.ncol) |column| {
+ const x = p.col_x[column];
+ const width = p.col_w[column];
+ const initial = try p.render(frame.allocator());
+ for ("New", 0..) |byte, offset|
+ try std.testing.expectEqual(byte, initial.at(x + @as(u16, @intCast(offset)), TOPBAR_H).text[0]);
+ p.update(.{ .mouse = .{ .button = .none, .kind = .motion, .col = x, .row = TOPBAR_H } });
+ const hovered = try p.render(frame.allocator());
+ try std.testing.expectEqual(Color{ .rgb = p.theme().sel_bg }, hovered.at(x, TOPBAR_H).style.bg);
+ p.update(.{ .mouse = .{ .button = .left, .kind = .press, .col = x, .row = TOPBAR_H } });
+ try std.testing.expectEqual(column, p.header_column.?);
+ try std.testing.expectEqual(@as(u16, 0), p.topbar_col.?);
+ const at_start = try p.render(frame.allocator());
+ try std.testing.expectEqual(x, at_start.cursor.?.x);
+ p.update(.{ .mouse = .{ .button = .left, .kind = .drag, .col = x + 3, .row = TOPBAR_H } });
+ p.update(.{ .mouse = .{ .button = .left, .kind = .release, .col = x + 3, .row = TOPBAR_H } });
+ const selected = try p.render(frame.allocator());
+ for (0..3) |offset|
+ try std.testing.expectEqual(Color{ .rgb = p.theme().sel_bg }, selected.at(x + @as(u16, @intCast(offset)), TOPBAR_H).style.bg);
+ p.update(.{ .key = .{ .cp = 'H', .text = "Help" } });
+ try std.testing.expect(std.mem.startsWith(u8, p.columnTag(column), "Help Tty"));
+ const edited = try p.render(frame.allocator());
+ try std.testing.expectEqual(x + 4, edited.cursor.?.x);
+ // The two reclaimed cells belong to text and caret reveal, too.
+ const long: [80]u8 = @splat('a');
+ try std.testing.expect(p.col_tags[column].set(long[0 .. width - 1]));
+ p.update(.{ .key = .{ .cp = Key.end } });
+ const at_end = try p.render(frame.allocator());
+ try std.testing.expectEqual(@as(usize, 0), p.header_scroll);
+ try std.testing.expectEqual(x + width - 1, at_end.cursor.?.x);
+ p.update(.{ .key = .{ .cp = 'b', .text = "b" } });
+ const revealed = try p.render(frame.allocator());
+ try std.testing.expectEqual(@as(usize, 1), p.header_scroll);
+ try std.testing.expectEqual(x + width - 1, revealed.cursor.?.x);
+ p.update(.{ .key = .{ .cp = Key.home } });
+ const home = try p.render(frame.allocator());
+ try std.testing.expectEqual(@as(usize, 0), p.header_scroll);
+ try std.testing.expectEqual(x, home.cursor.?.x);
+ p.update(.{ .key = .{ .cp = Key.escape } });
+ p.update(.pointer_leave);
+ _ = frame.reset(.retain_capacity);
+ }
+ try std.testing.expectEqualStrings("untouched\n", p.panes[0].?.file.?.content);
+}
+
+test "column tag first-cell execution keeps New local to the clicked column" {
+ const p = try Pardes.init(std.testing.allocator, .{ .cols = 80, .rows = 20, .tty_only = true });
+ defer p.deinit();
+ _ = try p.setTestFile("untouched\n");
+ p.newScratchColumn(0);
+ p.sync();
+ for (0..2) |column| {
+ p.active = p.col_panes[1 - column][0];
+ p.acknowledgePanelPresentation(&.{});
+ const before = p.col_n;
+ p.update(.{ .mouse = .{ .button = .middle, .kind = .press, .col = p.col_x[column], .row = TOPBAR_H } });
+ p.update(.{ .mouse = .{ .button = .middle, .kind = .release, .col = p.col_x[column], .row = TOPBAR_H } });
+ try std.testing.expectEqual(before[column] + 1, p.col_n[column]);
+ try std.testing.expectEqual(before[1 - column], p.col_n[1 - column]);
+ try std.testing.expectEqual(column, layout.findPane(p, p.active).?.col);
+ }
+ try std.testing.expectEqualStrings("untouched\n", p.panes[0].?.file.?.content);
+}
+
+test "header clicks beyond text append and long UTF-8 tags reveal their caret" {
+ const p = try Pardes.init(std.testing.allocator, .{ .cols = 50, .rows = 12, .tty_only = true });
+ defer p.deinit();
+ _ = try p.setTestFile("body\n");
+ try std.testing.expect(p.col_tags[0].set("New"));
+ p.acknowledgePanelPresentation(&.{});
+ p.update(.{ .mouse = .{ .button = .left, .kind = .press, .col = 40, .row = TOPBAR_H } });
+ p.update(.{ .mouse = .{ .button = .left, .kind = .release, .col = 40, .row = TOPBAR_H } });
+ p.update(.{ .key = .{ .cp = 'x', .text = " extended" } });
+ try std.testing.expectEqualStrings("New extended", p.columnTag(0));
+ p.update(.{ .paste = " 界界界界界界界界界界界界界界界界界界界界界界界界界界界界界界" });
+ const frame = try p.render(p.scratch.allocator());
+ try std.testing.expect(p.header_scroll > 0);
+ try std.testing.expect(frame.cursor != null);
+ try std.testing.expectEqual(TOPBAR_H, frame.cursor.?.y);
+ try std.testing.expect(frame.cursor.?.x < p.screen_w);
+ p.update(.{ .key = .{ .cp = Key.home } });
+ _ = try p.render(p.scratch.allocator());
+ try std.testing.expectEqual(@as(usize, 0), p.header_scroll);
+}
+
+test "tiny screens keep pane space before adding a column tag" {
+ const p = try Pardes.init(std.testing.allocator, .{ .cols = 8, .rows = 2, .tty_only = true });
+ defer p.deinit();
+ try std.testing.expectEqual(@as(u16, 0), p.columnBarHeight());
+ try std.testing.expectEqual(TOPBAR_H, p.rects[0].y);
+ _ = try p.render(p.scratch.allocator());
+}
+
+test "ColumnTags reclaims the row and releases hidden header focus without losing commands" {
+ const p = try Pardes.init(std.testing.allocator, .{ .cols = 60, .rows = 12, .tty_only = true });
+ defer p.deinit();
+ const pane = try p.setTestFile("unchanged body\n");
+ try std.testing.expect(p.col_tags[0].set("New Help"));
+ p.acknowledgePanelPresentation(&.{});
+ const shown = p.rects[0];
+ try std.testing.expectEqual(TOPBAR_H + COLBAR_H, shown.y);
+ p.update(.{ .mouse = .{ .button = .left, .kind = .press, .col = config.GUTTER, .row = TOPBAR_H } });
+ p.update(.{ .mouse = .{ .button = .left, .kind = .release, .col = config.GUTTER, .row = TOPBAR_H } });
+ try std.testing.expect(p.header_column != null and p.topbar_col != null);
+
+ p.update(.{ .command = "ColumnTags" });
+ try std.testing.expect(!p.settings.column_tags);
+ try std.testing.expectEqual(@as(u16, 0), p.columnBarHeight());
+ try std.testing.expectEqual(TOPBAR_H, p.rects[0].y);
+ try std.testing.expectEqual(shown.h + COLBAR_H, p.rects[0].h);
+ try std.testing.expect(p.header_column == null and p.topbar_col == null);
+ try std.testing.expect(p.header_anchor == null and !p.header_drag);
+ try std.testing.expectEqualStrings("New Help", p.columnTag(0));
+
+ p.update(.{ .command = "ColumnTags" });
+ try std.testing.expect(p.settings.column_tags);
+ try std.testing.expectEqual(shown, p.rects[0]);
+ p.acknowledgePanelPresentation(&.{});
+ p.update(.{ .mouse = .{ .button = .left, .kind = .press, .col = config.GUTTER, .row = TOPBAR_H } });
+ p.update(.{ .mouse = .{ .button = .left, .kind = .release, .col = config.GUTTER, .row = TOPBAR_H } });
+ try std.testing.expect(p.header_column != null);
+ p.update(.{ .resize = .{ .cols = 60, .rows = 2 } });
+ try std.testing.expect(p.settings.column_tags);
+ try std.testing.expectEqual(@as(u16, 0), p.columnBarHeight());
+ try std.testing.expectEqual(TOPBAR_H, p.rects[0].y);
+ try std.testing.expect(p.header_column == null and p.topbar_col == null);
+ p.update(.{ .resize = .{ .cols = 60, .rows = 12 } });
+ try std.testing.expectEqual(shown, p.rects[0]);
+ try std.testing.expectEqualStrings("New Help", p.columnTag(0));
+ try std.testing.expectEqualStrings("unchanged body\n", pane.file.?.content);
+}
+
+test "normal header Enter executes its command rather than searching for it" {
+ const p = try Pardes.init(std.testing.allocator, .{ .cols = 100, .rows = 12, .tty_only = true });
+ defer p.deinit();
+ _ = try p.setTestFile("body\n");
+ p.topbar_col = @intCast(std.mem.indexOf(u8, config.topbar_str, "Dump").?);
+ p.header_insert = false;
+ p.update(.{ .key = .{ .cp = Key.enter } });
+ try std.testing.expect(p.topbar_col == null);
+ try std.testing.expect(p.dump_out != null);
+ try std.testing.expectEqual(@as(usize, 1), p.col_n[0]);
+}
+
pub const Mouse = struct {
// sel indexing relies on left/middle/right being 0/1/2
pub const Button = enum { left, middle, right, wheel_up, wheel_down, wheel_left, wheel_right, none };
@@ -5041,6 +5649,8 @@ pub const Pardes = struct {
col_weight: [MAX_COLS]u64 = @splat(column_weight_unit),
col_panes: [MAX_COLS][MAX_PANES]usize = undefined,
col_n: [MAX_COLS]usize = @splat(0),
+ col_tags: [MAX_COLS]TagLine = @splat(.{}),
+ global_tag: TagLine = .{},
// derived each sync
rects: [MAX_PANES]Rect = @splat(.{}),
col_x: [MAX_COLS]u16 = undefined,
@@ -5087,6 +5697,11 @@ pub const Pardes = struct {
leader_keys: [4]u8 = undefined,
leader_n: u8 = 0,
topbar_col: ?u16 = null,
+ header_column: ?usize = null,
+ header_insert: bool = false,
+ header_anchor: ?u16 = null,
+ header_drag: bool = false,
+ header_scroll: usize = 0,
ov_pinch_scale: f32 = 1.0,
ov_touch_scroll_delta: f32 = 0.0,
/// middle+left chord argument: a kept left selection captured by a left
@@ -5329,11 +5944,57 @@ pub const Pardes = struct {
/// the topbar line: the fixed builtins, plus `Restore <path>` once a dump
/// exists — render and click dispatch must agree on this exact string
fn topbar(p: *Pardes, buf: []u8) []const u8 {
+ if (p.global_tag.custom) return p.global_tag.slice("");
if (p.last_dump) |d|
return std.fmt.bufPrint(buf, config.topbar_str ++ " Restore {s}", .{d}) catch config.topbar_str;
return config.topbar_str;
}
+ pub fn columnBarHeight(p: *const Pardes) u16 {
+ return if (p.settings.column_tags and p.screen_h >= 3) COLBAR_H else 0;
+ }
+
+ pub fn columnTag(p: *const Pardes, c: usize) []const u8 {
+ return p.col_tags[c].slice("New Tty Find Grep Joincol");
+ }
+
+ fn headerText(p: *Pardes) []const u8 {
+ if (p.header_column) |c| return if (c < p.ncol) p.columnTag(c) else "";
+ var buf: [1200]u8 = undefined;
+ return p.scratch.allocator().dupe(u8, p.topbar(&buf)) catch "";
+ }
+
+ fn revealHeader(p: *Pardes) void {
+ const cur = p.topbar_col orelse {
+ p.header_scroll = 0;
+ return;
+ };
+ const text = p.headerText();
+ const width = if (p.header_column) |c| p.col_w[c] else p.screen_w;
+ const col = panes.File.rawDisplayCol(text, @min(cur, text.len));
+ if (col < p.header_scroll) p.header_scroll = col;
+ if (col >= p.header_scroll + width) p.header_scroll = col -| (width -| 1);
+ var raw = panes.File.rawAtDisplay(text, p.header_scroll);
+ p.header_scroll = panes.File.rawDisplayCol(text, raw);
+ if (width > 0 and col >= p.header_scroll + width) {
+ raw = modal.nextGrapheme(text, raw);
+ p.header_scroll = panes.File.rawDisplayCol(text, raw);
+ }
+ }
+
+ fn headerReplace(p: *Pardes, bytes: []const u8) void {
+ const cur = p.topbar_col orelse return;
+ const anchor = p.header_anchor orelse cur;
+ const lo = @min(cur, anchor);
+ const hi = @max(cur, anchor);
+ const fallback = p.headerText();
+ const line = if (p.header_column) |c| &p.col_tags[c] else &p.global_tag;
+ if (line.replace(fallback, lo, hi, bytes)) {
+ p.topbar_col = @intCast(lo + bytes.len);
+ p.header_anchor = null;
+ }
+ }
+
fn detachCwds(p: *Pardes, parents: []const *Pane) !void {
var copies: [MAX_PANES]?[]u8 = @splat(null);
errdefer for (copies) |copy| if (copy) |bytes| p.gpa.free(bytes);
@@ -5673,6 +6334,8 @@ pub const Pardes = struct {
}
pub fn loadThemeFile(p: *Pardes, generation: u32, bytes: []const u8, animate: bool) bool {
+ // ZON's generated field dispatch grows with the complete theme schema.
+ @setEvalBranchQuota(10000);
const request = p.themeFileRequest(generation) orelse return false;
if (bytes.len > 1024 * 1024) {
p.reportError(request.pane, "theme file", error.ThemeFileTooLarge);
@@ -6243,6 +6906,11 @@ pub const Pardes = struct {
}
fn applyPaste(p: *Pardes, bytes: []const u8) void {
+ if (p.topbar_col != null) {
+ p.clip_pending = null;
+ p.headerReplace(bytes);
+ return;
+ }
const req = p.clip_pending;
p.clip_pending = null;
if (bytes.len == 0) return;
@@ -6250,6 +6918,14 @@ pub const Pardes = struct {
const pane = p.panes[id] orelse return;
if (req) |r| if (pane.serial != r.serial) return;
p.active = id;
+ if (pane.tag_edit) {
+ const text = p.tagText(p.scratch.allocator(), pane) catch return;
+ const range: @TypeOf(tagSelBounds(pane)) = if (pane.tag_sel) tagSelBounds(pane) else .{ .lo = pane.tag_col, .hi = pane.tag_col };
+ const hi = if (pane.tag_sel) modal.nextGrapheme(text, range.hi) else range.hi;
+ _ = p.replaceTagText(pane, range.lo, hi, bytes);
+ if (selRegexArmed(pane)) |a| p.applySelRegex(pane, a.pat, a.split);
+ return;
+ }
if (pane.isTerminal() and pane.mode == .tty) return p.typeToTty(id, pane, bytes);
switch (if (req) |r| r.mode else .after) {
.after => p.pasteText(pane, bytes, false, 1),
@@ -6286,14 +6962,15 @@ pub const Pardes = struct {
const arena = p.scratch.allocator();
if (comptime pdf_enabled) if (pane.pdf) |pv| return std.fmt.allocPrint(
arena,
- "pdf {d}/{d} {s} PdfFit {s} PdfTint PdfSections {s}",
- .{ pv.page + 1, pv.page_count, @tagName(pv.fit), @tagName(pv.tint), pv.path },
+ "{s} [{d}/{d}]",
+ .{ pv.path, pv.page + 1, pv.page_count },
);
if (pane.image) |*state| return panes.Image.tagPrefix(arena, state);
if (pane.file) |f| {
+ const name = if (pane.tag_name_len) |len| pane.tag_name[0..len] else f.path;
if (panes.Output.fileTraits(f.output).saves and f.revision != f.saved_revision)
- return std.fmt.allocPrint(arena, "{s}{s}", .{ f.path, dirty_marker });
- return arena.dupe(u8, f.path);
+ return std.fmt.allocPrint(arena, "{s}{s}", .{ name, dirty_marker });
+ return arena.dupe(u8, name);
}
return arena.dupe(u8, pane.cwdSlice());
}
@@ -6305,6 +6982,7 @@ pub const Pardes = struct {
}
fn defaultTail(pane: *const Pane) []const u8 {
+ if (comptime pdf_enabled) if (pane.pdf != null) return pdf_pane_tail;
if (pane.file != null) return file_pane_tail;
if (pane.isTerminal()) return terminal_pane_tail;
return pane_tail;
@@ -6317,45 +6995,21 @@ pub const Pardes = struct {
return null;
}
- fn tagGap(p: *Pardes, pane: *const Pane, used: usize) usize {
- if (pane.tag_init) return 0;
- const id = p.paneIdOf(pane) orelse return 0;
- const r = p.rects[id];
- if (r.w <= config.GUTTER) return 0;
- const tw: usize = r.w - config.GUTTER;
- var end: usize = tw -| config.tag_right_pad;
- for (p.panes, 0..) |slot, qid| if (slot) |q| {
- const qr = p.rects[qid];
- if (qr.h == 0 or qr.x != r.x or qr.w != r.w) continue;
- const words = defaultTail(q);
- const laid = if (q.tag_init) q.tagSlice() else words;
- const lead = laid.len - std.mem.trimStart(u8, laid, " ").len;
- const q_end = panes.File.displayWidth(p.tagPrefix(q) catch continue) + lead + panes.File.displayWidth(std.mem.trimStart(u8, words, " "));
- end = @max(end, @min(q_end, tw));
- };
- return end -| used;
- }
-
pub fn tagText(p: *Pardes, arena: std.mem.Allocator, pane: *Pane) ![]u8 {
const prefix = try p.tagPrefix(pane);
const tail = curTail(pane);
- const gap = p.tagGap(pane, panes.File.displayWidth(prefix) + panes.File.displayWidth(tail));
- const out = try arena.alloc(u8, prefix.len + gap + tail.len);
+ const out = try arena.alloc(u8, prefix.len + tail.len);
@memcpy(out[0..prefix.len], prefix);
- @memset(out[prefix.len..][0..gap], ' ');
- @memcpy(out[prefix.len + gap ..], tail);
+ @memcpy(out[prefix.len..], tail);
return out;
}
- pub fn seedTail(p: *Pardes, pane: *Pane) void {
+ pub fn seedTail(_: *Pardes, pane: *Pane) void {
if (pane.tag_init) return;
const tail = curTail(pane);
- const prefix = (p.tagPrefix(pane) catch return);
- const gap = p.tagGap(pane, panes.File.displayWidth(prefix) + panes.File.displayWidth(tail));
- if (gap + tail.len > pane.tag_tail.len) return;
- @memset(pane.tag_tail[0..gap], ' ');
- @memcpy(pane.tag_tail[gap..][0..tail.len], tail);
- pane.tag_tail_len = gap + tail.len;
+ if (tail.len > pane.tag_tail.len) return;
+ @memcpy(pane.tag_tail[0..tail.len], tail);
+ pane.tag_tail_len = tail.len;
pane.tag_init = true;
}
@@ -6374,9 +7028,16 @@ pub const Pardes = struct {
const lead: i32 = @intCast(tail.len - std.mem.trimStart(u8, tail, " ").len);
if (col < 0) {
pane.tag_col = @intCast(@min(edit0 + lead, end));
+ const text = p.tagText(p.scratch.allocator(), pane) catch return;
+ if (p.paneIdOf(pane)) |id| {
+ const width = @max(1, p.rects[id].w -| config.GUTTER);
+ // Reveal the suffix together with its commands, not merely the
+ // first command letter at the viewport's far right edge.
+ pane.tag_scroll = @intCast(panes.File.displayWidth(text) + 1 -| width);
+ }
} else {
const text = p.tagText(p.scratch.allocator(), pane) catch return;
- pane.tag_col = @intCast(@min(text.len, panes.File.rawAtDisplay(text, @intCast(col))));
+ pane.tag_col = @intCast(@min(text.len, panes.File.rawAtDisplay(text, @as(usize, @intCast(col)) + pane.tag_scroll)));
}
}
@@ -6386,6 +7047,8 @@ pub const Pardes = struct {
} else pane.mode = .normal;
pane.tag_edit = false;
pane.tag_sel = false;
+ pane.tag_name_len = null;
+ pane.tag_scroll = 0;
pane.prompt = .none; // an abandoned prompt stays as tag text
pane.nsel_snap = 0; // ...and its s/S preview keeps whatever it previewed
}
@@ -6407,6 +7070,90 @@ pub const Pardes = struct {
return if (b.hi > b.lo) text[b.lo..b.hi] else null;
}
+ fn tagNameEnd(pane: *const Pane) ?usize {
+ const f = pane.file orelse return null;
+ if (!panes.Output.fileTraits(f.output).saves or f.path.len > pane.tag_name.len) return null;
+ return if (pane.tag_name_len) |len| len else f.path.len;
+ }
+
+ /// Commit a staged buffer name, never a disk rename or write. Keep the
+ /// draft visible on failure so the user can correct it or cancel with Esc.
+ pub fn commitTagName(p: *Pardes, pane: *Pane) bool {
+ const len = pane.tag_name_len orelse return true;
+ const id = p.paneIdOf(pane) orelse return false;
+ const name = pane.tag_name[0..len];
+ if (name.len == 0 or name[name.len - 1] == '/' or !std.unicode.utf8ValidateSlice(name)) {
+ p.reportError(id, "name", error.InvalidName);
+ return false;
+ }
+ for (name) |byte| if (byte < ' ') {
+ p.reportError(id, "name", error.InvalidName);
+ return false;
+ };
+ const old_prefix = (p.tagPrefix(pane) catch return false).len;
+ const tail_col = @as(usize, pane.tag_col) -| old_prefix;
+ const full = std.fs.path.resolvePosix(p.scratch.allocator(), &.{ paneDir(pane), name }) catch |err| {
+ p.reportError(id, "name", err);
+ return false;
+ };
+ filesystem.nameBuffer(p, id, full, true) catch |err| {
+ p.reportError(id, "name", err);
+ return false;
+ };
+ pane.tag_name_len = null;
+ const prefix = (p.tagPrefix(pane) catch return false).len;
+ pane.tag_col = @intCast(prefix + @min(tail_col, pane.tag_tail_len));
+ pane.tag_sel = false;
+ return true;
+ }
+
+ /// Replace one range in the rendered tag. The file name and command tail
+ /// retain separate identities even when a selection crosses their boundary.
+ fn replaceTagText(p: *Pardes, pane: *Pane, start: usize, finish: usize, input: []const u8) bool {
+ const prefix_len = (p.tagPrefix(pane) catch return false).len;
+ const end = prefix_len + pane.tag_tail_len;
+ const lo = @min(start, end);
+ const hi = @max(lo, @min(finish, end));
+ const name_end = tagNameEnd(pane);
+ const editing_name = if (name_end) |n| lo <= n else false;
+ if (!editing_name and lo < prefix_len) return false;
+ var bytes: [limits.max_tag_tail]u8 = undefined;
+ var count: usize = 0;
+ for (input) |byte| {
+ if (byte == '\n' or byte == '\r') continue;
+ if (count == bytes.len) return false;
+ bytes[count] = byte;
+ count += 1;
+ }
+ const tail_lo = lo -| prefix_len;
+ const tail_hi = hi -| prefix_len;
+ const tail_insert = if (editing_name) 0 else count;
+ const tail_len = pane.tag_tail_len - (tail_hi - tail_lo) + tail_insert;
+ if (tail_len > pane.tag_tail.len) return false;
+ if (editing_name) {
+ const n = name_end.?;
+ const name_hi = @min(hi, n);
+ const name_len = n - (name_hi - lo) + count;
+ if (name_len > pane.tag_name.len) return false;
+ if (pane.tag_name_len == null) @memcpy(pane.tag_name[0..n], pane.file.?.path);
+ if (count > name_hi - lo)
+ std.mem.copyBackwards(u8, pane.tag_name[lo + count .. name_len], pane.tag_name[name_hi..n])
+ else
+ std.mem.copyForwards(u8, pane.tag_name[lo + count .. name_len], pane.tag_name[name_hi..n]);
+ @memcpy(pane.tag_name[lo..][0..count], bytes[0..count]);
+ pane.tag_name_len = @intCast(name_len);
+ }
+ if (tail_insert > tail_hi - tail_lo)
+ std.mem.copyBackwards(u8, pane.tag_tail[tail_lo + tail_insert .. tail_len], pane.tag_tail[tail_hi..pane.tag_tail_len])
+ else
+ std.mem.copyForwards(u8, pane.tag_tail[tail_lo + tail_insert .. tail_len], pane.tag_tail[tail_hi..pane.tag_tail_len]);
+ if (!editing_name) @memcpy(pane.tag_tail[tail_lo..][0..count], bytes[0..count]);
+ pane.tag_tail_len = tail_len;
+ pane.tag_col = @intCast(lo + count);
+ pane.tag_sel = false;
+ return true;
+ }
+
fn tagInsertKey(p: *Pardes, pane: *Pane, key: Key) void {
if (hit(key, config.escape)) {
exitTagEdit(pane); // the tag is ALWAYS insert; Esc leaves it
@@ -6414,44 +7161,47 @@ pub const Pardes = struct {
}
// the acme chords on the selection or the word at the cursor
if (hit(key, config.look_key) or hit(key, config.exec_key)) {
+ if (pane.tag_name_len != null) {
+ const in_name = pane.tag_col < (p.tagPrefix(pane) catch return).len;
+ if (!p.commitTagName(pane)) return;
+ if (hit(key, config.look_key) or in_name) {
+ exitTagEdit(pane);
+ return;
+ }
+ }
if (p.tagChordText(pane)) |txt| {
pane.tag_sel = false;
p.runBuiltin(if (hit(key, config.look_key)) config.look_cmd else config.exec_cmd, p.active, "", txt);
}
return;
}
- const edit0: u16 = @intCast((p.tagPrefix(pane) catch return).len);
- const end: u16 = edit0 + @as(u16, @intCast(pane.tag_tail_len));
+ const text = p.tagText(p.scratch.allocator(), pane) catch return;
+ const end = text.len;
if (key.text.len > 0) {
- if (pane.tag_col < edit0) return; // typing inside the path: inert
- var insert_len: usize = 0;
- for (key.text) |ch| insert_len += @intFromBool(ch != '\n' and ch != '\r');
- if (insert_len > pane.tag_tail.len - pane.tag_tail_len) return;
- for (key.text) |ch| {
- if (ch == '\n' or ch == '\r') continue; // one-line tag
- if (!pane.insertTagByte(pane.tag_col - edit0, ch)) return;
- pane.tag_col += 1;
- }
+ const range: @TypeOf(tagSelBounds(pane)) = if (pane.tag_sel) tagSelBounds(pane) else .{ .lo = pane.tag_col, .hi = pane.tag_col };
+ const hi = if (pane.tag_sel) modal.nextGrapheme(text, range.hi) else range.hi;
+ _ = p.replaceTagText(pane, range.lo, hi, key.text);
return;
}
switch (key.cp) {
- Key.backspace => if (pane.tag_col > edit0) {
- const text = p.tagText(p.scratch.allocator(), pane) catch return;
- const prev = @max(@as(usize, edit0), modal.prevGrapheme(text, pane.tag_col));
- const count = @as(usize, pane.tag_col) - prev;
- for (0..count) |_| pane.removeTagByte(prev - edit0);
- pane.tag_col = @intCast(prev);
+ Key.backspace, Key.delete => {
+ if (pane.tag_sel) {
+ const range = tagSelBounds(pane);
+ _ = p.replaceTagText(pane, range.lo, modal.nextGrapheme(text, range.hi), "");
+ } else if (key.cp == Key.backspace and pane.tag_col > 0) {
+ _ = p.replaceTagText(pane, modal.prevGrapheme(text, pane.tag_col), pane.tag_col, "");
+ } else if (key.cp == Key.delete and pane.tag_col < end) {
+ _ = p.replaceTagText(pane, pane.tag_col, modal.nextGrapheme(text, pane.tag_col), "");
+ }
},
Key.left => if (pane.tag_col > 0) {
- const text = p.tagText(p.scratch.allocator(), pane) catch return;
pane.tag_col = @intCast(modal.prevGrapheme(text, pane.tag_col));
},
Key.right => if (pane.tag_col < end) {
- const text = p.tagText(p.scratch.allocator(), pane) catch return;
pane.tag_col = @intCast(modal.nextGrapheme(text, pane.tag_col));
},
Key.home => pane.tag_col = 0,
- Key.end => pane.tag_col = end,
+ Key.end => pane.tag_col = @intCast(end),
else => {},
}
}
@@ -6486,7 +7236,7 @@ pub const Pardes = struct {
if (hit(key, config.insert) or hit(key, config.append) or
hit(key, config.insert_line_start) or hit(key, config.insert_line_end))
{
- const edit0: usize = (p.tagPrefix(pane) catch return).len;
+ const edit0: usize = if (tagNameEnd(pane) != null) 0 else (p.tagPrefix(pane) catch return).len;
pane.tag_col = @intCast(@max(edit0, if (hit(key, config.append))
modal.nextGrapheme(text, cur)
else if (hit(key, config.insert_line_start))
@@ -6509,6 +7259,10 @@ pub const Pardes = struct {
if (d == .Up) {
exitTagEdit(pane);
p.topbar_col = 0;
+ p.header_column = if (p.columnBarHeight() > 0) (layout.findPane(p, from) orelse return).col else null;
+ p.header_insert = false;
+ p.header_anchor = null;
+ p.header_drag = false;
}
return;
}
@@ -6554,25 +7308,83 @@ pub const Pardes = struct {
}
fn topbarKey(p: *Pardes, key: Key) void {
- var tb_buf: [1200]u8 = undefined;
- const bar = p.topbar(&tb_buf);
+ const bar = p.headerText();
// the line GROWS a `Restore <path>` word the moment a dump lands, so
// the column is clamped against the live line on every use
const cur: usize = @min(@as(usize, p.topbar_col orelse return), bar.len);
if (hit(key, config.escape)) {
p.topbar_col = null; // the active pane still has its body focus
+ p.header_column = null;
+ p.header_anchor = null;
+ p.header_drag = false;
+ p.header_scroll = 0;
return;
}
if (hit(key, config.look_key) or hit(key, config.exec_key)) {
- const word = wordAtCol(bar, cur);
+ const a = p.header_anchor orelse @as(u16, @intCast(cur));
+ const word = if (a != cur) bar[@min(a, cur)..@max(a, cur)] else wordAtCol(bar, cur);
p.topbar_col = null;
- if (word.len > 0) _ = p.execute(p.active, word);
+ if (word.len > 0) {
+ if (!p.header_insert) {
+ // Preserve the workspace tag's keyboard command semantics.
+ _ = p.execute(p.active, word);
+ } else p.runBuiltin(if (hit(key, config.look_key)) config.look_cmd else config.exec_cmd, p.active, "", word);
+ }
+ return;
+ }
+ if (p.header_insert) {
+ if (key.ctrl and key.cp == 'v') {
+ p.emit(.read_clipboard);
+ return;
+ }
+ if (key.ctrl and (key.cp == 'c' or key.cp == 'x')) {
+ const anchor = p.header_anchor orelse @as(u16, @intCast(cur));
+ if (anchor != cur) {
+ p.setClipboard(bar[@min(anchor, cur)..@max(anchor, cur)]);
+ if (key.cp == 'x') p.headerReplace("");
+ }
+ return;
+ }
+ if (key.text.len > 0 and !key.ctrl and !key.alt) {
+ p.headerReplace(key.text);
+ return;
+ }
+ if (key.cp == Key.backspace or key.cp == Key.delete) {
+ if (p.header_anchor == null or p.header_anchor.? == cur) p.header_anchor = @intCast(if (key.cp == Key.backspace) modal.prevGrapheme(bar, cur) else modal.nextGrapheme(bar, cur));
+ p.headerReplace("");
+ return;
+ }
+ const next: ?usize = switch (key.cp) {
+ Key.left => modal.prevGrapheme(bar, cur),
+ Key.right => modal.nextGrapheme(bar, cur),
+ Key.home => 0,
+ Key.end => bar.len,
+ else => null,
+ };
+ if (next) |at| {
+ if (key.shift) {
+ if (p.header_anchor == null) p.header_anchor = @intCast(cur);
+ } else p.header_anchor = null;
+ p.topbar_col = @intCast(at);
+ }
+ return;
+ }
+ if (hit(key, config.insert) or hit(key, config.append) or hit(key, config.insert_line_start) or hit(key, config.insert_line_end)) {
+ p.header_insert = true;
+ p.topbar_col = @intCast(if (hit(key, config.insert_line_end)) bar.len else if (hit(key, config.insert_line_start)) 0 else if (hit(key, config.append)) modal.nextGrapheme(bar, cur) else cur);
return;
}
if (hit(key, config.topbar_down)) {
+ if (p.header_column == null and p.columnBarHeight() > 0) {
+ p.header_column = if (layout.findPane(p, p.active)) |f| f.col else 0;
+ p.header_scroll = 0;
+ p.topbar_col = 0;
+ return;
+ }
var dest: ?usize = null;
for (p.panes, 0..) |slot, i| {
- if (slot == null or p.rects[i].y != TOPBAR_H) continue;
+ if (slot == null or p.rects[i].y != TOPBAR_H + p.columnBarHeight()) continue;
+ if (p.header_column) |c| if (p.rects[i].x != p.col_x[c]) continue;
if (i == p.active) {
dest = i;
break;
@@ -6582,11 +7394,18 @@ pub const Pardes = struct {
const d = dest orelse return;
const pane = p.panes[d].?;
p.topbar_col = null;
+ p.header_column = null;
p.active = d;
p.enterTagEdit(pane, -1);
if (pane.tag_edit) pane.mode = .normal;
return;
}
+ if (key.cp == 'k' or key.cp == Key.up) {
+ p.header_column = null;
+ p.header_anchor = null;
+ p.topbar_col = 0;
+ return;
+ }
const col: ?usize = if (hit(key, config.topbar_left))
modal.prevGrapheme(bar, cur)
else if (hit(key, config.topbar_right))
@@ -6861,6 +7680,19 @@ pub const Pardes = struct {
return std.fmt.allocPrint(p.scratch.allocator(), "{s} {s}", .{ t, a }) catch txt;
}
+ /// One mode transition for the terminal tag command and the Ctrl-B chord.
+ pub fn toggleTty(p: *Pardes, id: usize) void {
+ const pane = p.panes[id] orelse return;
+ if (!pane.isTerminal()) return;
+ p.active = id;
+ p.topbar_col = null;
+ if (pane.tag_edit) exitTagEdit(pane);
+ if (pane.mode == .tty) {
+ pane.mode = .normal;
+ pane.normal.clear();
+ } else panes.Terminal.enterTty(p, id);
+ }
+
fn handleKey(p: *Pardes, key: Key) void {
if (p.topbar_col != null) return p.topbarKey(key);
const pane = p.panes[p.active] orelse return;
@@ -6904,12 +7736,8 @@ pub const Pardes = struct {
const tty_alt = hit(key, config.tty_toggle_alt);
const tty_toggle = (key.ctrl and key.cp == p.opts.tty_toggle) or tty_alt;
if (pane.isTerminal() and tty_toggle) {
- if (pane.mode == .tty) {
- if (tty_alt) return p.runBuiltin(.Last, p.active, "", null);
- pane.mode = .normal;
- pane.normal.clear();
- } else panes.Terminal.enterTty(p, p.active);
- return;
+ if (pane.mode == .tty and tty_alt) return p.runBuiltin(.Last, p.active, "", null);
+ return p.toggleTty(p.active);
}
// A shell prompt is a pane you can leave: plain Esc there is Shift-Esc.
if (pane.isTerminal() and pane.mode == .tty and hit(key, config.escape) and p.takesCommandLine(p.active))
@@ -8400,6 +9228,7 @@ pub const Pardes = struct {
if (budget.* == 0) return null;
budget.* -= 1;
const ln = lines[@intCast(r)];
+ if (pane.file) |f| if (!panes.Output.isWalkRow(f.output, ln)) continue;
const on_start = r == start;
switch (grain) {
.word => {
@@ -9640,7 +10469,7 @@ pub const Pardes = struct {
pub const ChromeTarget = struct { col: u16, row: u16 };
pub fn chromeTarget(p: *const Pardes, col: u16, row: u16) ?ChromeTarget {
- if (row < TOPBAR_H) return .{ .col = col, .row = row };
+ if (row < TOPBAR_H + p.columnBarHeight()) return .{ .col = col, .row = row };
for (p.panes, 0..) |slot, id| {
if (slot == null) continue;
const rect = p.rects[id];
@@ -9703,7 +10532,8 @@ pub const Pardes = struct {
const tag_y = if (p.settings.tag_bottom) r.y + r.h -| BOX_H else r.y;
const body_y = if (p.settings.tag_bottom) r.y else r.y + BOX_H;
const on_tag = row >= tag_y and row < tag_y + BOX_H;
- const c: i32 = @as(i32, col) - @as(i32, r.x + config.GUTTER);
+ const c: i32 = @as(i32, col) - @as(i32, r.x + config.GUTTER) +
+ (if (on_tag) @as(i32, p.panes[id].?.tag_scroll) else 0);
const v: i32 = if (on_tag) 0 else @as(i32, row) - @as(i32, body_y) + @as(i32, BOX_H);
return .{
.sel = .{ .state = .dragging, .c0 = c, .c1 = c, .r0 = v, .r1 = v },
@@ -9854,7 +10684,66 @@ pub const Pardes = struct {
p.chord_arg = null;
}
}
- if (m.kind == .press) p.topbar_col = null;
+ if (p.header_drag and m.button == config.select_button and (m.kind == .drag or m.kind == .release)) {
+ const x = if (p.header_column) |c| p.col_x[c] else 0;
+ const bar = p.headerText();
+ p.topbar_col = @intCast(@min(bar.len, panes.File.rawAtDisplay(bar, (mcol -| x) + p.header_scroll)));
+ if (m.kind == .release) p.header_drag = false;
+ return;
+ }
+ if (mrow < TOPBAR_H + p.columnBarHeight() and m.kind == .press and
+ (m.button == config.select_button or m.button == config.exec_button or m.button == config.look_button))
+ {
+ var column: ?usize = null;
+ var x: u16 = 0;
+ if (mrow >= TOPBAR_H) {
+ for (0..p.ncol) |c| if (mcol >= p.col_x[c] and mcol < p.col_x[c] + p.col_w[c]) {
+ column = c;
+ x = p.col_x[c];
+ if (layout.findPane(p, p.active)) |active_col| {
+ if (active_col.col != c and p.col_n[c] > 0) p.active = p.col_panes[c][0];
+ }
+ break;
+ };
+ if (column == null) return;
+ }
+ if (p.header_column != column) {
+ p.topbar_col = null;
+ p.header_anchor = null;
+ p.header_scroll = 0;
+ }
+ p.header_column = column;
+ const bar = p.headerText();
+ const at = @min(bar.len, panes.File.rawAtDisplay(bar, (mcol -| x) + p.header_scroll));
+ if (m.button == config.select_button) {
+ if (p.panes[p.active]) |pane| exitTagEdit(pane);
+ p.topbar_col = @intCast(at);
+ p.header_anchor = @intCast(at);
+ p.header_insert = true;
+ p.header_drag = true;
+ } else {
+ const selected = if (p.topbar_col) |cur| blk: {
+ const a = p.header_anchor orelse cur;
+ break :blk if (at >= @min(a, cur) and at < @max(a, cur)) bar[@min(a, cur)..@max(a, cur)] else wordAtCol(bar, at);
+ } else wordAtCol(bar, at);
+ const word = p.scratch.allocator().dupe(u8, selected) catch return;
+ p.topbar_col = null;
+ if (word.len > 0) {
+ if (m.button == config.exec_button) {
+ const named = std.meta.stringToEnum(Builtin, word);
+ const held = if (named) |b| (if (builtins.registry.takesArg(b)) p.heldSelection(p.active) else null) else p.heldSelection(p.active);
+ _ = p.execute(p.active, p.withArg(word, held));
+ } else p.runBuiltin(config.look_cmd, p.active, "", word);
+ }
+ }
+ return;
+ }
+ if (m.kind == .press) {
+ p.topbar_col = null;
+ p.header_column = null;
+ p.header_anchor = null;
+ p.header_drag = false;
+ }
switch (m.button) {
.none => {}, // hover tracked above; motion has no other meaning
@@ -9910,7 +10799,6 @@ pub const Pardes = struct {
p.drag = .none;
return;
}
- if (mrow < TOPBAR_H) return; // topbar: a select click is deliberately inert
if (hovered) |mid| {
const mr = p.rects[mid];
const mtag = if (p.settings.tag_bottom) mr.y + mr.h -| BOX_H else mr.y;
@@ -9996,22 +10884,6 @@ pub const Pardes = struct {
p.drag = .none;
return;
}
- if (mrow < TOPBAR_H) {
- // global tagbar: EXECUTE runs the command under the
- // click (a stray select click must never Kill)
- if (m.button == config.exec_button) {
- var tb_buf: [1200]u8 = undefined;
- const bar = p.topbar(&tb_buf);
- const word = wordAtCol(bar, panes.File.rawAtDisplay(bar, mcol));
- const named = std.meta.stringToEnum(Builtin, word);
- const held = if (named) |b|
- (if (builtins.registry.takesArg(b)) p.heldSelection(p.active) else null)
- else
- p.heldSelection(p.active); // not a builtin: an ordinary acme 2-1
- if (word.len > 0) _ = p.execute(p.active, p.withArg(word, held));
- }
- return;
- }
const id = hovered orelse return;
const r = p.rects[id];
const pane = p.panes[id] orelse return;
@@ -10100,7 +10972,8 @@ pub const Pardes = struct {
0
else
@as(i32, @min(@max(mrow, r.y), r.y + body_h - 1)) - @as(i32, r.y) + @as(i32, BOX_H);
- } else pane.sel[b].r1 = @as(i32, mrow) - @as(i32, r.y);
+ } else pane.sel[b].r1 = if (pane.sel[b].r0 < BOX_H) 0 else @as(i32, mrow) - @as(i32, r.y);
+ if (pane.sel[b].r1 < BOX_H) pane.sel[b].c1 += pane.tag_scroll;
if (comptime pdf_enabled)
panes.Pdf.pointerUpdate(&s.pdf, p, pane, mcol, mrow);
}
@@ -10109,7 +10982,7 @@ pub const Pardes = struct {
const pane = p.panes[d.id] orelse return;
const c = @as(i32, mcol) - @as(i32, p.rects[d.id].x + config.GUTTER);
const text = p.tagText(p.scratch.allocator(), pane) catch return;
- pane.tag_col = @intCast(@min(text.len, panes.File.rawAtDisplay(text, @intCast(@max(0, c)))));
+ pane.tag_col = @intCast(@min(text.len, panes.File.rawAtDisplay(text, @as(usize, @intCast(@max(0, c))) + pane.tag_scroll)));
pane.tag_sel = pane.tag_col != pane.tag_anchor;
},
.none => {},
@@ -10281,7 +11154,7 @@ pub const Pardes = struct {
}
} else {
const clk = pane.sel[b];
- const operand = p.pointerOperand(pane, clk);
+ var operand = p.pointerOperand(pane, clk);
if (operand.expanded) |expanded|
pane.sel[b] = expanded
else if (operand.text == null)
@@ -10292,6 +11165,26 @@ pub const Pardes = struct {
}
const txt = operand.text;
const cmd = if (s.button == config.look_button) config.look_cmd else config.exec_cmd;
+ if (clk.r0 < BOX_H and s.button == config.exec_button and pane.tag_name_len != null) {
+ const prefix_width = panes.File.displayWidth(p.tagPrefix(pane) catch return);
+ const on_name = @as(usize, @intCast(@max(0, clk.c0))) < prefix_width;
+ if (!p.commitTagName(pane)) return;
+ // Executing a staged filename commits it; executing its
+ // command tail uses the new identity (especially Save).
+ if (on_name) return;
+ const new_width = panes.File.displayWidth(p.tagPrefix(pane) catch return);
+ const shift = @as(i32, @intCast(new_width)) - @as(i32, @intCast(prefix_width));
+ if (operand.expanded) |*sel| {
+ sel.c0 += shift;
+ sel.c1 += shift;
+ }
+ if (operand.preview) |*sel| {
+ sel.c0 += shift;
+ sel.c1 += shift;
+ }
+ pane.sel[b].c0 += shift;
+ pane.sel[b].c1 += shift;
+ }
p.dispatchPointerBuiltin(s.id, cmd, txt, .{
.on_tag = clk.r0 < BOX_H,
.operand = operand,
@@ -10391,7 +11284,7 @@ pub const Pardes = struct {
} else p.pasteText(pane, p.yank orelse return, true, 1);
}
- /// Newtty: a shell in the caller's directory, raw from the first frame,
+ /// Tty: a shell in the caller's directory, raw from the first frame,
/// stacked below the caller like Alt-n's new shell.
pub fn spawnTty(p: *Pardes, from: usize) void {
const src = p.panes[from] orelse return;
@@ -10528,19 +11421,6 @@ pub const Pardes = struct {
}
}
- fn stackDocLeft(p: *Pardes, free: usize, nt: *Pane) void {
- const lc = 0;
- if (p.col_n[lc] > 0) if (p.panes[p.col_panes[lc][0]]) |top| {
- layout.snapColWeights(p, lc);
- const h = p.rects[p.col_panes[lc][0]].h;
- nt.vweight = @floatFromInt(@max(1, h / 2));
- top.vweight = @floatFromInt(@max(1, h -| h / 2));
- };
- layout.insert(p, lc, 0, free);
- p.active = free;
- p.evictLonePristineTty(lc, free);
- }
-
// ---- the ONE dispatcher: look (right/Enter) and execute (middle/Tab) ----
pub fn focusPaneLine(p: *Pardes, id: usize, at: look.Spot, landing: enum { center, keep }) void {
@@ -10766,6 +11646,7 @@ pub const Pardes = struct {
const previous_colors = p.settings.colors;
const previous_transition = p.settings.panel_transition;
const previous_tagline_percent = p.settings.font.tagline_percent;
+ const previous_column_tags = p.settings.column_tags;
switch (setting.action) {
.theme => {
const want = std.mem.trim(u8, arg orelse return, " \t\r\n");
@@ -10776,10 +11657,10 @@ pub const Pardes = struct {
},
.font => {
if (comptime !font_picker) return;
- const want = std.mem.trim(u8, arg orelse return, " \t\r\n");
- const matches = fonts.list(p.scratch.allocator(), want);
+ const spec = config.Runtime.FontSpec.parse(arg orelse return) orelse return;
+ const matches = fonts.list(p.scratch.allocator(), spec.name);
if (matches.len == 0) return;
- if (!p.settings.requestFont(matches[0].path, matches[0].name)) return;
+ if (!p.settings.requestFont(matches[0].path, matches[0].name, spec.size_hundredths)) return;
p.font_request_taken = false;
},
else => _ = p.settings.apply(setting, arg),
@@ -10794,7 +11675,16 @@ pub const Pardes = struct {
p.settings.panel_transition != previous_transition;
const tagline_metrics_changed = setting.action == .tagline_size and
p.settings.font.tagline_percent != previous_tagline_percent;
- if (transition_changed or tagline_metrics_changed) {
+ if (p.settings.column_tags != previous_column_tags) {
+ if (p.header_column != null) {
+ p.topbar_col = null;
+ p.header_column = null;
+ p.header_anchor = null;
+ p.header_drag = false;
+ p.header_scroll = 0;
+ }
+ }
+ if (transition_changed or tagline_metrics_changed or p.settings.column_tags != previous_column_tags) {
p.abandonPanelAnimations();
}
}
@@ -10829,20 +11719,19 @@ pub const Pardes = struct {
p.active = free;
return;
};
- if (src_id) |sid| {
- const src = layout.splitParent(p, sid);
- const sf = layout.findPane(p, src).?;
- layout.insert(p, sf.col, sf.idx + 1, free);
- layout.splitBelow(p, src, nt);
- p.active = free;
- return;
- }
- if (doc and p.ncol < MAX_COLS and layout.columnFitsHalves(p, from_id, 100)) {
- if (!layout.splitColumn(p, from_id, free, true)) return p.stackDocLeft(free, nt);
+ if (src_id == null and doc and p.ncol < MAX_COLS and
+ layout.columnFitsHalves(p, from_id, 100) and layout.splitColumn(p, from_id, free, true))
+ {
p.active = free;
return;
}
- p.stackDocLeft(free, nt);
+ // Without room for a first-document column, split the Look origin
+ // just like Tty. Never displace (or evict) a top-left bystander.
+ const src = layout.splitParent(p, src_id orelse from_id);
+ const sf = layout.findPane(p, src).?;
+ layout.insert(p, sf.col, sf.idx + 1, free);
+ layout.splitBelow(p, src, nt);
+ p.active = free;
}
// ---- dump / load (acme-style: `pardes -l state.zon` restores a session) ----
@@ -10891,6 +11780,7 @@ pub const Pardes = struct {
};
if (ids_len > 0) {
columns[columns_len] = .{
+ .tag = if (p.col_tags[c].custom) p.columnTag(c) else null,
.weight = @as(f32, @floatFromInt(p.col_weight[c])) / @as(f32, @floatFromInt(column_weight_unit)),
.panes = column_ids[c][0..ids_len],
};
@@ -10904,6 +11794,7 @@ pub const Pardes = struct {
.screen = .{ .cols = p.screen_w, .rows = p.screen_h },
.active = slot_to_pane[p.active] orelse 0,
.topbar = config.topbar_str,
+ .topbar_custom = if (p.global_tag.custom) p.global_tag.slice("") else null,
.theme = p.theme().name,
.columns = columns[0..columns_len],
.panes = dump_panes[0..panes_len],
@@ -11033,9 +11924,12 @@ pub const Pardes = struct {
};
p.restoreDumpTail(pane, src);
pane.vweight = src.vweight;
+ pane.collapsed = src.collapsed;
}
p.ncol = @min(st.columns.len, MAX_COLS);
+ if (st.topbar_custom) |bar| _ = p.global_tag.set(bar);
for (st.columns[0..p.ncol], 0..) |col, c| {
+ if (col.tag) |bar| _ = p.col_tags[c].set(bar);
const scaled = @as(f64, @floatCast(col.weight)) * @as(f64, @floatFromInt(column_weight_unit));
const bounded = @min(scaled, @as(f64, @floatFromInt(max_column_weight)));
p.col_weight[c] = @max(1, @as(u64, @intFromFloat(@round(bounded))));
@@ -11059,6 +11953,10 @@ pub const Pardes = struct {
return;
}
const tail_class = tailClass(pane);
+ if (src.kind == .image and panes.Pdf.isPath(src.image.?.path)) {
+ if (panes.Pdf.legacySavedPrefix(src.image.?.path, src.tag)) |prefix|
+ return p.restoreTailAt(pane, src.tag, prefix, .generic);
+ }
if (src.kind == .terminal and std.mem.startsWith(u8, src.tag, "TTY ")) {
const legacy = std.fmt.allocPrint(p.scratch.allocator(), "TTY {s}", .{src.terminal.?.cwd}) catch return;
if (std.mem.startsWith(u8, src.tag, legacy))
@@ -11109,13 +12007,15 @@ pub const Pardes = struct {
const rest = saved_tag[pfx.len..];
const said = std.mem.trimStart(u8, rest, " ");
const defaults: []const []const u8 = switch (class) {
- .generic => &.{ pane_tail, prev_pane_tail, legacy_pane_tail },
- .file => &.{ file_pane_tail, prev_file_pane_tail, legacy_file_pane_tail },
+ .generic => &.{ pdf_pane_tail, pane_tail, pre_collapse_pdf_pane_tail, pre_collapse_pane_tail, pre_column_pdf_pane_tail, pre_column_pane_tail, prev_pane_tail, legacy_pane_tail },
+ .file => &.{ file_pane_tail, pre_collapse_file_pane_tail, pre_column_file_pane_tail, prev_file_pane_tail, legacy_file_pane_tail },
.output => &.{
- file_pane_tail, prev_file_pane_tail, legacy_file_pane_tail,
- pane_tail, prev_pane_tail, legacy_pane_tail,
+ file_pane_tail, prev_file_pane_tail, legacy_file_pane_tail,
+ pane_tail, prev_pane_tail, legacy_pane_tail,
+ pre_column_file_pane_tail, pre_column_pane_tail, pre_collapse_file_pane_tail,
+ pre_collapse_pane_tail,
},
- .terminal => &.{ terminal_pane_tail, prev_terminal_pane_tail, legacy_terminal_pane_tail, pane_tail, prev_pane_tail, legacy_pane_tail },
+ .terminal => &.{ terminal_pane_tail, pre_collapse_terminal_pane_tail, pre_column_terminal_pane_tail, pre_tty_terminal_pane_tail, prev_terminal_pane_tail, legacy_terminal_pane_tail, pane_tail, pre_collapse_pane_tail, pre_column_pane_tail, prev_pane_tail, legacy_pane_tail },
};
for (defaults) |default|
if (std.mem.eql(u8, said, std.mem.trimStart(u8, default, " "))) return;
@@ -11231,12 +12131,21 @@ pub const Pardes = struct {
/// Recompute geometry, push grid-size changes to each emulator + pty, fire
/// deferred greetings. The mirror of the prototype's loop epilogue.
fn sync(p: *Pardes) void {
+ if (p.header_column != null and p.columnBarHeight() == 0) {
+ p.topbar_col = null;
+ p.header_column = null;
+ p.header_anchor = null;
+ p.header_drag = false;
+ p.header_scroll = 0;
+ }
p.reapPanes();
layout.compute(p);
p.presentation.sync(p);
p.trackJump();
for (&p.panes, 0..) |*slot, id| {
const pane = slot.* orelse continue;
+ if (pane.tag_name_len != null and (id != p.active or p.topbar_col != null))
+ exitTagEdit(pane);
if (comptime terminal_panes) if (pane.terminal) |state| {
var off: u16 = 0;
while (off < state.reply_len) {
@@ -11359,8 +12268,8 @@ pub const Pardes = struct {
s.cell_diffs = &.{};
const chrome = p.chromeTheme();
const th = p.theme(); // the message row paints in the editor's colours
- // gaps between panes read as chrome (scrollbar track), not raw default
- s.fill(0, 0, s.cols, s.rows, .{ .bg = .{ .rgb = chrome.scroll_track } });
+ // Separators have their own role; a scrollbar need not frame the page.
+ s.fill(0, 0, s.cols, s.rows, .{ .bg = .{ .rgb = chrome.border } });
for (&p.panes, 0..) |*slot, id| {
const pane = slot.* orelse continue;
@@ -11411,21 +12320,24 @@ pub const Pardes = struct {
}
// global tagbar: full width, top row
+ p.revealHeader();
s.fill(0, 0, s.cols, TOPBAR_H, .{
.bg = .{ .rgb = chrome.tag_bg },
.font_role = .tagline,
});
var tb_buf: [1200]u8 = undefined;
- _ = s.print(0, 0, s.cols, p.topbar(&tb_buf), .{
+ const global_bar = p.topbar(&tb_buf);
+ const global_scroll = if (p.topbar_col != null and p.header_column == null) p.header_scroll else 0;
+ _ = s.print(0, 0, s.cols, global_bar[panes.File.rawAtDisplay(global_bar, global_scroll)..], .{
.fg = .{ .rgb = chrome.tag_fg },
.bg = .{ .rgb = chrome.tag_bg },
.font_role = .tagline,
});
if (p.pointer_inside and p.hover_row < TOPBAR_H) {
const bar = p.topbar(&tb_buf);
- if (wordBoundsAtCol(bar, panes.File.rawAtDisplay(bar, p.hover_col))) |bounds| {
- var col = panes.File.rawDisplayCol(bar, bounds.lo);
- const hi = panes.File.rawDisplayCol(bar, bounds.hi);
+ if (wordBoundsAtCol(bar, panes.File.rawAtDisplay(bar, p.hover_col + global_scroll))) |bounds| {
+ var col = panes.File.rawDisplayCol(bar, bounds.lo) -| global_scroll;
+ const hi = panes.File.rawDisplayCol(bar, bounds.hi) -| global_scroll;
while (col < hi and col < s.cols) : (col += 1) {
const cell = s.at(@intCast(col), 0);
cell.default = false;
@@ -11434,9 +12346,53 @@ pub const Pardes = struct {
}
}
}
- if (p.topbar_col) |c| {
- const col = panes.File.rawDisplayCol(p.topbar(&tb_buf), c);
- if (col < s.cols) s.cursor = .{ .x = @intCast(col), .y = 0, .bar = false };
+ if (p.topbar_col) |c| if (p.header_column == null) {
+ const col = panes.File.rawDisplayCol(p.topbar(&tb_buf), c) -| global_scroll;
+ if (col < s.cols) s.cursor = .{ .x = @intCast(col), .y = 0, .bar = p.header_insert };
+ };
+ if (p.columnBarHeight() > 0) for (0..p.ncol) |c| {
+ const x = p.col_x[c];
+ const w = p.col_w[c];
+ if (w == 0 or x >= s.cols) continue;
+ const active_col = if (layout.findPane(p, p.active)) |f| f.col == c else false;
+ const bg = if (active_col and p.settings.focus_tint) chrome.tag_active_bg else chrome.tag_bg;
+ const fg = if (active_col and p.settings.focus_tint) chrome.tag_active_fg else chrome.tag_fg;
+ s.fill(x, TOPBAR_H, w, 1, .{ .bg = .{ .rgb = bg }, .font_role = .tagline });
+ const bar_scroll = if (p.topbar_col != null and p.header_column == c) p.header_scroll else 0;
+ const tag = p.columnTag(c);
+ _ = s.print(x, TOPBAR_H, w, tag[panes.File.rawAtDisplay(tag, bar_scroll)..], .{
+ .fg = .{ .rgb = fg },
+ .bg = .{ .rgb = bg },
+ .font_role = .tagline,
+ });
+ if (p.pointer_inside and p.hover_row == TOPBAR_H and p.hover_col >= x and p.hover_col < x + w) {
+ const bar = p.columnTag(c);
+ if (wordBoundsAtCol(bar, panes.File.rawAtDisplay(bar, p.hover_col - x + bar_scroll))) |bounds| {
+ var col = panes.File.rawDisplayCol(bar, bounds.lo) -| bar_scroll;
+ const hi = panes.File.rawDisplayCol(bar, bounds.hi) -| bar_scroll;
+ while (col < hi and col < w) : (col += 1) {
+ const cell = s.at(x + @as(u16, @intCast(col)), TOPBAR_H);
+ cell.style.bg = .{ .rgb = th.sel_bg };
+ cell.style.fg = .{ .rgb = th.sel_fg };
+ }
+ }
+ }
+ };
+ if (p.topbar_col) |cur| {
+ const bar = p.headerText();
+ const x = if (p.header_column) |c| p.col_x[c] else 0;
+ const w = if (p.header_column) |c| p.col_w[c] else s.cols;
+ const y: u16 = if (p.header_column != null) TOPBAR_H else 0;
+ const anchor = p.header_anchor orelse cur;
+ var col = panes.File.rawDisplayCol(bar, @min(cur, anchor)) -| p.header_scroll;
+ const hi = panes.File.rawDisplayCol(bar, @max(cur, anchor)) -| p.header_scroll;
+ while (col < hi and col < w) : (col += 1) {
+ const cell = s.at(x + @as(u16, @intCast(col)), y);
+ cell.style.fg = .{ .rgb = th.sel_fg };
+ cell.style.bg = .{ .rgb = th.sel_bg };
+ }
+ const caret = panes.File.rawDisplayCol(bar, @min(cur, bar.len)) -| p.header_scroll;
+ if (caret < w) s.cursor = .{ .x = x + @as(u16, @intCast(caret)), .y = y, .bar = p.header_insert };
}
switch (p.drag) {
@@ -11665,8 +12621,9 @@ pub const Pardes = struct {
const sy = if (row < BOX_H) tag_y else body_y + row - BOX_H;
// File line numbers occupy a gutter only in the body. The tag is
// row zero in Sel space and starts at its real first text cell.
- var col: i32 = if (pane.file != null and row >= BOX_H) @max(c0, @as(i32, panes.File.gutterWidth(pane))) else c0;
- while (col <= c1 and col < tw) : (col += 1) {
+ const scroll: i32 = if (row < BOX_H) pane.tag_scroll else 0;
+ var col: i32 = if (pane.file != null and row >= BOX_H) @max(c0, @as(i32, panes.File.gutterWidth(pane))) else @max(0, c0 - scroll);
+ while (col <= c1 - scroll and col < tw) : (col += 1) {
const cell = s.at(tx + @as(u16, @intCast(col)), sy);
cell.default = false;
cell.style.bg = .{ .rgb = bg };
@@ -11717,21 +12674,37 @@ pub const Pardes = struct {
.tty => config.tag_tty,
}, box_style);
- // tag: live prefix (cwd/path) + editable tail, on a dim bar
- const tag_style: CellStyle = .{ .fg = .{ .rgb = chrome.tag_fg }, .bg = .{ .rgb = chrome.tag_bg }, .font_role = .tagline };
+ // Focus is visible along the tag without changing its live text grid.
+ const tag_bg = if (active and p.settings.focus_tint) chrome.tag_active_bg else chrome.tag_bg;
+ const tag_fg = if (active and p.settings.focus_tint) chrome.tag_active_fg else chrome.tag_fg;
+ const tag_style: CellStyle = .{ .fg = .{ .rgb = tag_fg }, .bg = .{ .rgb = tag_bg }, .font_role = .tagline };
// Padding belongs to the same font row but keeps its default ink: a
// role must not manufacture a foreground color for blank cells.
s.fill(tx, tag_y, tw, BOX_H, .{
- .bg = .{ .rgb = chrome.tag_bg },
+ .bg = .{ .rgb = tag_bg },
.font_role = .tagline,
});
const tag = try p.tagText(arena, pane);
const prompt_at = pane.promptAt();
+ if (active and pane.tag_edit and prompt_at == null) {
+ const caret = panes.File.rawDisplayCol(tag, pane.tag_col);
+ var scroll: usize = pane.tag_scroll;
+ if (caret < scroll) scroll = caret;
+ if (caret >= scroll + tw) scroll = caret - tw + 1;
+ var raw = panes.File.rawAtDisplay(tag, scroll);
+ scroll = panes.File.rawDisplayCol(tag, raw);
+ if (caret >= scroll + tw) {
+ raw = modal.nextGrapheme(tag, raw);
+ scroll = panes.File.rawDisplayCol(tag, raw);
+ }
+ pane.tag_scroll = @intCast(scroll);
+ } else if (!pane.tag_edit or prompt_at != null) pane.tag_scroll = 0;
const tag_cut = if (prompt_at) |at|
@min(tag.len, tag.len - @min(tag.len, pane.tag_tail_len) + at)
else
tag.len;
- _ = s.print(tx, tag_y, tw, tag[0..tag_cut], tag_style);
+ const tag_start = @min(tag_cut, panes.File.rawAtDisplay(tag, pane.tag_scroll));
+ _ = s.print(tx, tag_y, tw, tag[tag_start..tag_cut], tag_style);
if (p.look_hover_preview) |preview| {
if (preview.pane == id and preview.serial == pane.serial) if (preview.sel) |sel| if (@min(sel.r0, sel.r1) < BOX_H) {
const preview_bg = mix(page_rgb, mix(page_rgb, th.sel_bg));
@@ -11740,10 +12713,10 @@ pub const Pardes = struct {
}
if (pane.tag_edit and pane.tag_sel) {
const b = tagSelBounds(pane);
- var col = panes.File.rawDisplayCol(tag, b.lo);
+ var col = panes.File.rawDisplayCol(tag, b.lo) -| pane.tag_scroll;
const hi = modal.nextGrapheme(tag, b.hi);
- const end = panes.File.rawDisplayCol(tag, hi) -| 1;
- while (col <= end and col < tw) : (col += 1) {
+ const end = panes.File.rawDisplayCol(tag, hi);
+ while (col + pane.tag_scroll < end and col < tw) : (col += 1) {
const cell = s.at(tx + @as(u16, @intCast(col)), tag_y);
cell.default = false;
cell.style.bg = .{ .rgb = th.sel_bg };
@@ -11753,10 +12726,14 @@ pub const Pardes = struct {
// cursor while editing the tag: byte offset mapped to its display cell
if (active and pane.tag_edit) {
// bar while typing, block for `:` normal mode (same rule as a body)
- const col = panes.File.rawDisplayCol(tag, pane.tag_col);
+ const col = panes.File.rawDisplayCol(tag, pane.tag_col) -| pane.tag_scroll;
if (col < tw) s.cursor = .{ .x = tx + @as(u16, @intCast(col)), .y = tag_y, .bar = pane.mode == .insert };
}
+ // Folded panes retain their body state, but neither body pixels nor
+ // its cursor belong outside the one-row tag rectangle.
+ if (pane.collapsed) return;
+
if (comptime pdf_enabled)
if (pane.hasPdf() and panes.Pdf.draw(p, pane, r, id, tx, tw)) return;
diff --git a/src/tag_line.zig b/src/tag_line.zig
new file mode 100644
index 00000000..d1a9d166
--- /dev/null
+++ b/src/tag_line.zig
@@ -0,0 +1,41 @@
+//! Bounded, single-line editable chrome. Offsets are UTF-8 byte offsets.
+const std = @import("std");
+const modal = @import("modal.zig");
+pub const Line = struct {
+ text: [@import("memory.zig").limits.max_tag_tail]u8 = undefined,
+ len: usize = 0,
+ custom: bool = false,
+
+ pub fn slice(self: *const Line, fallback: []const u8) []const u8 {
+ return if (self.custom) self.text[0..self.len] else fallback;
+ }
+ pub fn set(self: *Line, bytes: []const u8) bool {
+ if (bytes.len > self.text.len or std.mem.indexOfAny(u8, bytes, "\r\n\x00") != null or !std.unicode.utf8ValidateSlice(bytes)) return false;
+ @memcpy(self.text[0..bytes.len], bytes);
+ self.len = bytes.len;
+ self.custom = true;
+ return true;
+ }
+ pub fn replace(self: *Line, fallback: []const u8, lo: usize, hi: usize, bytes: []const u8) bool {
+ const current = self.slice(fallback);
+ if (lo > hi or hi > current.len) return false;
+ var next: [@import("memory.zig").limits.max_tag_tail]u8 = undefined;
+ const size = lo + bytes.len + current.len - hi;
+ if (size > next.len) return false;
+ @memcpy(next[0..lo], current[0..lo]);
+ @memcpy(next[lo..][0..bytes.len], bytes);
+ @memcpy(next[lo + bytes.len ..][0 .. current.len - hi], current[hi..]);
+ return self.set(next[0..size]);
+ }
+};
+
+test "tag replacement is atomic and keeps UTF-8 intact" {
+ var line: Line = .{};
+ try std.testing.expect(line.replace("New Find", 4, 8, "Grep"));
+ try std.testing.expectEqualStrings("New Grep", line.slice(""));
+ try std.testing.expect(!line.replace("", 0, 0, "bad\nline"));
+ try std.testing.expectEqualStrings("New Grep", line.slice(""));
+ try std.testing.expect(line.set("é界"));
+ try std.testing.expect(line.replace("", 0, modal.nextGrapheme(line.slice(""), 0), ""));
+ try std.testing.expectEqualStrings("界", line.slice(""));
+}
diff --git a/src/themes/atelier.zig b/src/themes/atelier.zig
new file mode 100644
index 00000000..8b45623b
--- /dev/null
+++ b/src/themes/atelier.zig
@@ -0,0 +1,49 @@
+//! Pardes atelier: An Acme homage: butter-yellow paper, blue-green tags and garden ink.
+//! Original palette; editor chrome, search, diagnostics and ANSI output are
+//! designed together. See docs/themes.md for the shared role contract.
+pub const theme = .{
+ .name = "atelier",
+ .bg = .{ 0xff, 0xfd, 0xeb },
+ .fg = .{ 0x29, 0x3f, 0x35 },
+ .tag_bg = .{ 0xe4, 0xf0, 0xed },
+ .tag_fg = .{ 0x3d, 0x60, 0x55 },
+ .tag_active_bg = .{ 0xd3, 0xe7, 0xdf },
+ .tag_active_fg = .{ 0x35, 0x58, 0x4d },
+ .box = .{ 0x3e, 0x7a, 0x68 },
+ .box_dim = .{ 0x99, 0xb6, 0xa3 },
+ .kw = .{ 0x76, 0x4d, 0x80 },
+ .str = .{ 0x3c, 0x6c, 0x43 },
+ .num = .{ 0x88, 0x57, 0x22 },
+ .comment = .{ 0x35, 0x73, 0x3a },
+ .lineno = .{ 0x90, 0x98, 0x80 },
+ .lineno_active = .{ 0x88, 0x90, 0x78 },
+ .scroll_track = .{ 0xee, 0xec, 0xcf },
+ .scroll_thumb = .{ 0x9d, 0xa9, 0x7b },
+ .border = .{ 0xb8, 0xc8, 0xb4 },
+ .sel_bg = .{ 0xe5, 0xe9, 0xae },
+ .sel_fg = .{ 0x35, 0x49, 0x2d },
+ .search_bg = .{ 0xf0, 0xd7, 0x94 },
+ .search_fg = .{ 0x61, 0x47, 0x15 },
+ .diagnostic_error = .{ 0xa3, 0x3d, 0x37 },
+ .diagnostic_warning = .{ 0x81, 0x59, 0x08 },
+ .diagnostic_info = .{ 0x33, 0x65, 0x78 },
+ .diagnostic_hint = .{ 0x52, 0x6e, 0x3d },
+ .palette = .{
+ .{ 0x29, 0x3f, 0x35 },
+ .{ 0xa3, 0x3d, 0x37 },
+ .{ 0x3c, 0x6c, 0x43 },
+ .{ 0x81, 0x59, 0x08 },
+ .{ 0x33, 0x65, 0x78 },
+ .{ 0x76, 0x4d, 0x80 },
+ .{ 0x52, 0x6e, 0x3d },
+ .{ 0x29, 0x3f, 0x35 },
+ .{ 0x68, 0x76, 0x58 },
+ .{ 0xa3, 0x3d, 0x37 },
+ .{ 0x3c, 0x6c, 0x43 },
+ .{ 0x88, 0x57, 0x22 },
+ .{ 0x33, 0x65, 0x78 },
+ .{ 0x76, 0x4d, 0x80 },
+ .{ 0x52, 0x6e, 0x3d },
+ .{ 0x29, 0x3f, 0x35 },
+ },
+};
diff --git a/src/themes/clay.zig b/src/themes/clay.zig
new file mode 100644
index 00000000..bf9e7027
--- /dev/null
+++ b/src/themes/clay.zig
@@ -0,0 +1,50 @@
+//! Pardes clay: Gruvbox warm charcoal and earthy brights; deep olive command rails.
+//! A classic-inspired adaptation, not an exact upstream port.
+//! Reference: vendor/themes/gruvbox.json (Gruvbox Dark).
+//! Pardes-specific tag, search, diagnostic and ANSI roles; see docs/themes.md.
+pub const theme = .{
+ .name = "clay",
+ .bg = .{ 0x10, 0x10, 0x0e },
+ .fg = .{ 0xf3, 0xe5, 0xbc },
+ .tag_bg = .{ 0x34, 0x3f, 0x36 },
+ .tag_fg = .{ 0xd7, 0xd6, 0xb6 },
+ .tag_active_bg = .{ 0x42, 0x4f, 0x40 },
+ .tag_active_fg = .{ 0xe3, 0xe2, 0xc2 },
+ .box = .{ 0x8e, 0xc0, 0x7c },
+ .box_dim = .{ 0x67, 0x77, 0x52 },
+ .kw = .{ 0xfb, 0x8a, 0x69 },
+ .str = .{ 0xb8, 0xbb, 0x26 },
+ .num = .{ 0xd3, 0x86, 0x9b },
+ .comment = .{ 0xe2, 0xb5, 0x6f },
+ .lineno = .{ 0x69, 0x64, 0x55 },
+ .lineno_active = .{ 0x71, 0x6c, 0x5d },
+ .scroll_track = .{ 0x22, 0x21, 0x19 },
+ .scroll_thumb = .{ 0x8a, 0x90, 0x6b },
+ .border = .{ 0x56, 0x64, 0x48 },
+ .sel_bg = .{ 0x4f, 0x58, 0x3c },
+ .sel_fg = .{ 0xfb, 0xf1, 0xc7 },
+ .search_bg = .{ 0x66, 0x51, 0x28 },
+ .search_fg = .{ 0xff, 0xe2, 0xa0 },
+ .diagnostic_error = .{ 0xfb, 0x8a, 0x69 },
+ .diagnostic_warning = .{ 0xfa, 0xbd, 0x2f },
+ .diagnostic_info = .{ 0x83, 0xb5, 0xa8 },
+ .diagnostic_hint = .{ 0x8e, 0xc0, 0x7c },
+ .palette = .{
+ .{ 0x10, 0x10, 0x0e },
+ .{ 0xfb, 0x8a, 0x69 },
+ .{ 0xb8, 0xbb, 0x26 },
+ .{ 0xfa, 0xbd, 0x2f },
+ .{ 0x8c, 0xb0, 0xcb },
+ .{ 0xd3, 0x86, 0x9b },
+ .{ 0x8e, 0xc0, 0xb3 },
+ .{ 0xf3, 0xe5, 0xbc },
+ .{ 0xb1, 0xa1, 0x8b },
+ .{ 0xfb, 0x8a, 0x69 },
+ .{ 0xb8, 0xbb, 0x26 },
+ .{ 0xfa, 0xbd, 0x2f },
+ .{ 0x8c, 0xb0, 0xcb },
+ .{ 0xd3, 0x86, 0x9b },
+ .{ 0x8e, 0xc0, 0xb3 },
+ .{ 0xf3, 0xe5, 0xbc },
+ },
+};
diff --git a/src/themes/daybreak.zig b/src/themes/daybreak.zig
new file mode 100644
index 00000000..28c0ac0a
--- /dev/null
+++ b/src/themes/daybreak.zig
@@ -0,0 +1,49 @@
+//! Pardes daybreak: Crisp white, deep blue ink, and high-contrast navigational cues.
+//! Original palette; editor chrome, search, diagnostics and ANSI output are
+//! designed together. See docs/themes.md for the shared role contract.
+pub const theme = .{
+ .name = "daybreak",
+ .bg = .{ 0xff, 0xff, 0xff },
+ .fg = .{ 0x14, 0x2d, 0x40 },
+ .tag_bg = .{ 0xed, 0xf2, 0xf7 },
+ .tag_fg = .{ 0x29, 0x46, 0x5e },
+ .tag_active_bg = .{ 0xdf, 0xea, 0xf3 },
+ .tag_active_fg = .{ 0x21, 0x3e, 0x56 },
+ .box = .{ 0x07, 0x5f, 0x91 },
+ .box_dim = .{ 0x81, 0x9d, 0xb1 },
+ .kw = .{ 0x62, 0x2a, 0x88 },
+ .str = .{ 0x24, 0x5b, 0x30 },
+ .num = .{ 0x76, 0x42, 0x09 },
+ .comment = .{ 0x14, 0x56, 0x38 },
+ .lineno = .{ 0x88, 0x93, 0x9b },
+ .lineno_active = .{ 0x80, 0x8b, 0x93 },
+ .scroll_track = .{ 0xe6, 0xed, 0xf3 },
+ .scroll_thumb = .{ 0x6b, 0x85, 0x9b },
+ .border = .{ 0x85, 0x9b, 0xac },
+ .sel_bg = .{ 0xc1, 0xde, 0xf3 },
+ .sel_fg = .{ 0x10, 0x36, 0x4f },
+ .search_bg = .{ 0xff, 0xe3, 0x96 },
+ .search_fg = .{ 0x4b, 0x35, 0x00 },
+ .diagnostic_error = .{ 0xa1, 0x1c, 0x30 },
+ .diagnostic_warning = .{ 0x70, 0x49, 0x00 },
+ .diagnostic_info = .{ 0x07, 0x5a, 0x83 },
+ .diagnostic_hint = .{ 0x38, 0x55, 0x2b },
+ .palette = .{
+ .{ 0x14, 0x2d, 0x40 },
+ .{ 0xa1, 0x1c, 0x30 },
+ .{ 0x24, 0x5b, 0x30 },
+ .{ 0x70, 0x49, 0x00 },
+ .{ 0x07, 0x5a, 0x83 },
+ .{ 0x62, 0x2a, 0x88 },
+ .{ 0x38, 0x55, 0x2b },
+ .{ 0x14, 0x2d, 0x40 },
+ .{ 0x45, 0x56, 0x67 },
+ .{ 0xa1, 0x1c, 0x30 },
+ .{ 0x24, 0x5b, 0x30 },
+ .{ 0x76, 0x42, 0x09 },
+ .{ 0x07, 0x5a, 0x83 },
+ .{ 0x62, 0x2a, 0x88 },
+ .{ 0x38, 0x55, 0x2b },
+ .{ 0x14, 0x2d, 0x40 },
+ },
+};
diff --git a/src/themes/dusk.zig b/src/themes/dusk.zig
new file mode 100644
index 00000000..e4ba012b
--- /dev/null
+++ b/src/themes/dusk.zig
@@ -0,0 +1,49 @@
+//! Pardes dusk: Soft plum charcoal, copper comments and deliberately gentle text.
+//! Original palette; editor chrome, search, diagnostics and ANSI output are
+//! designed together. See docs/themes.md for the shared role contract.
+pub const theme = .{
+ .name = "dusk",
+ .bg = .{ 0x39, 0x32, 0x3b },
+ .fg = .{ 0xc3, 0xb6, 0xc1 },
+ .tag_bg = .{ 0x2c, 0x26, 0x30 },
+ .tag_fg = .{ 0xc6, 0xb6, 0xc5 },
+ .tag_active_bg = .{ 0x3b, 0x2f, 0x3b },
+ .tag_active_fg = .{ 0xd2, 0xc2, 0xd1 },
+ .box = .{ 0xe4, 0xb3, 0x9b },
+ .box_dim = .{ 0x71, 0x57, 0x68 },
+ .kw = .{ 0xcf, 0xb1, 0xe8 },
+ .str = .{ 0xba, 0xc8, 0x94 },
+ .num = .{ 0xe8, 0xb5, 0x92 },
+ .comment = .{ 0xf1, 0xb9, 0x89 },
+ .lineno = .{ 0x82, 0x71, 0x7e },
+ .lineno_active = .{ 0x8a, 0x79, 0x86 },
+ .scroll_track = .{ 0x3d, 0x35, 0x40 },
+ .scroll_thumb = .{ 0x8b, 0x69, 0x7c },
+ .border = .{ 0x51, 0x41, 0x4f },
+ .sel_bg = .{ 0x61, 0x44, 0x53 },
+ .sel_fg = .{ 0xff, 0xf0, 0xeb },
+ .search_bg = .{ 0x5e, 0x49, 0x2e },
+ .search_fg = .{ 0xff, 0xe3, 0xa2 },
+ .diagnostic_error = .{ 0xf6, 0xaa, 0xa4 },
+ .diagnostic_warning = .{ 0xed, 0xca, 0x8a },
+ .diagnostic_info = .{ 0xaa, 0xcb, 0xdc },
+ .diagnostic_hint = .{ 0xc2, 0xcd, 0xa1 },
+ .palette = .{
+ .{ 0x39, 0x32, 0x3b },
+ .{ 0xf6, 0xaa, 0xa4 },
+ .{ 0xba, 0xc8, 0x94 },
+ .{ 0xed, 0xca, 0x8a },
+ .{ 0xaa, 0xcb, 0xdc },
+ .{ 0xcf, 0xb1, 0xe8 },
+ .{ 0xc2, 0xcd, 0xa1 },
+ .{ 0xc3, 0xb6, 0xc1 },
+ .{ 0xab, 0x9e, 0xab },
+ .{ 0xf6, 0xaa, 0xa4 },
+ .{ 0xba, 0xc8, 0x94 },
+ .{ 0xe8, 0xb5, 0x92 },
+ .{ 0xaa, 0xcb, 0xdc },
+ .{ 0xcf, 0xb1, 0xe8 },
+ .{ 0xc2, 0xcd, 0xa1 },
+ .{ 0xc3, 0xb6, 0xc1 },
+ },
+};
diff --git a/src/themes/forge.zig b/src/themes/forge.zig
new file mode 100644
index 00000000..ee23640d
--- /dev/null
+++ b/src/themes/forge.zig
@@ -0,0 +1,51 @@
+//! Pardes forge: Dark Plus blue and peach on near-black coal; slate-blue command rails.
+//! A classic-inspired adaptation, not an exact upstream port.
+//! Reference: vendor/themes/dark_plus.toml.
+//! Pardes-specific tag, search, diagnostic and ANSI roles; see docs/themes.md.
+pub const theme = .{
+ .name = "forge",
+ .bg = .{ 0x0c, 0x0c, 0x0e },
+ .fg = .{ 0xe5, 0xe5, 0xe5 },
+ .tag_bg = .{ 0x22, 0x25, 0x2b },
+ .tag_fg = .{ 0xc5, 0xc9, 0xd2 },
+ .tag_active_bg = .{ 0x2d, 0x34, 0x40 },
+ .tag_active_fg = .{ 0xd1, 0xd5, 0xde },
+ .box = .{ 0xa5, 0xc4, 0xee },
+ .box_dim = .{ 0x59, 0x65, 0x77 },
+ .kw = .{ 0x75, 0xb5, 0xe8 },
+ .str = .{ 0xce, 0x91, 0x78 },
+ .num = .{ 0xb5, 0xce, 0xa8 },
+ .comment = .{ 0xb3, 0xca, 0xff },
+ .lineno = .{ 0x62, 0x65, 0x6c },
+ .lineno_active = .{ 0x6a, 0x6d, 0x74 },
+ .scroll_track = .{ 0x1a, 0x1c, 0x21 },
+ .scroll_thumb = .{ 0x73, 0x80, 0x92 },
+ .border = .{ 0x47, 0x52, 0x63 },
+ .sel_bg = .{ 0x26, 0x4f, 0x68 },
+ .sel_fg = .{ 0xe2, 0xee, 0xf4 },
+ .search_bg = .{ 0x59, 0x4a, 0x25 },
+ .search_fg = .{ 0xf5, 0xdf, 0xa1 },
+ .diagnostic_error = .{ 0xf2, 0x8a, 0x81 },
+ .diagnostic_warning = .{ 0xd7, 0xba, 0x7d },
+ .diagnostic_info = .{ 0x75, 0xbe, 0xff },
+ .diagnostic_hint = .{ 0x8b, 0xce, 0xba },
+ // ANSI roles are semantic colors, independent of peach string syntax.
+ .palette = .{
+ .{ 0x0c, 0x0c, 0x0e },
+ .{ 0xf2, 0x8a, 0x81 },
+ .{ 0xb5, 0xce, 0xa8 },
+ .{ 0xd7, 0xba, 0x7d },
+ .{ 0x75, 0xbe, 0xff },
+ .{ 0xc5, 0x86, 0xc0 },
+ .{ 0x8b, 0xce, 0xba },
+ .{ 0xe5, 0xe5, 0xe5 },
+ .{ 0x9c, 0xa0, 0xa9 },
+ .{ 0xf2, 0x8a, 0x81 },
+ .{ 0xb5, 0xce, 0xa8 },
+ .{ 0xd7, 0xba, 0x7d },
+ .{ 0x75, 0xbe, 0xff },
+ .{ 0xc5, 0x86, 0xc0 },
+ .{ 0x8b, 0xce, 0xba },
+ .{ 0xe5, 0xe5, 0xe5 },
+ },
+};
diff --git a/src/themes/forge_black.zig b/src/themes/forge_black.zig
new file mode 100644
index 00000000..d9605e97
--- /dev/null
+++ b/src/themes/forge_black.zig
@@ -0,0 +1,51 @@
+//! Pardes forge_black: Dark Plus blue and peach on pure black, with cool slate tags.
+//! A classic-inspired adaptation, not an exact upstream port.
+//! Reference: vendor/themes/dark_plus.toml.
+//! Pardes-specific tag, search, diagnostic and ANSI roles; see docs/themes.md.
+pub const theme = .{
+ .name = "forge_black",
+ .bg = .{ 0x00, 0x00, 0x00 },
+ .fg = .{ 0xf6, 0xf6, 0xf6 },
+ .tag_bg = .{ 0x22, 0x25, 0x2b },
+ .tag_fg = .{ 0xc5, 0xc9, 0xd2 },
+ .tag_active_bg = .{ 0x2d, 0x34, 0x40 },
+ .tag_active_fg = .{ 0xd1, 0xd5, 0xde },
+ .box = .{ 0xa5, 0xc4, 0xee },
+ .box_dim = .{ 0x59, 0x65, 0x77 },
+ .kw = .{ 0x75, 0xb5, 0xe8 },
+ .str = .{ 0xce, 0x91, 0x78 },
+ .num = .{ 0xb5, 0xce, 0xa8 },
+ .comment = .{ 0xb3, 0xca, 0xff },
+ .lineno = .{ 0x62, 0x65, 0x6c },
+ .lineno_active = .{ 0x6a, 0x6d, 0x74 },
+ .scroll_track = .{ 0x14, 0x16, 0x1a },
+ .scroll_thumb = .{ 0x73, 0x80, 0x92 },
+ .border = .{ 0x47, 0x52, 0x63 },
+ .sel_bg = .{ 0x26, 0x4f, 0x68 },
+ .sel_fg = .{ 0xe2, 0xee, 0xf4 },
+ .search_bg = .{ 0x59, 0x4a, 0x25 },
+ .search_fg = .{ 0xf5, 0xdf, 0xa1 },
+ .diagnostic_error = .{ 0xf2, 0x8a, 0x81 },
+ .diagnostic_warning = .{ 0xd7, 0xba, 0x7d },
+ .diagnostic_info = .{ 0x75, 0xbe, 0xff },
+ .diagnostic_hint = .{ 0x8b, 0xce, 0xba },
+ // ANSI roles are semantic colors, independent of peach string syntax.
+ .palette = .{
+ .{ 0x00, 0x00, 0x00 },
+ .{ 0xf2, 0x8a, 0x81 },
+ .{ 0xb5, 0xce, 0xa8 },
+ .{ 0xd7, 0xba, 0x7d },
+ .{ 0x75, 0xbe, 0xff },
+ .{ 0xc5, 0x86, 0xc0 },
+ .{ 0x8b, 0xce, 0xba },
+ .{ 0xf6, 0xf6, 0xf6 },
+ .{ 0x9c, 0xa0, 0xa9 },
+ .{ 0xf2, 0x8a, 0x81 },
+ .{ 0xb5, 0xce, 0xa8 },
+ .{ 0xd7, 0xba, 0x7d },
+ .{ 0x75, 0xbe, 0xff },
+ .{ 0xc5, 0x86, 0xc0 },
+ .{ 0x8b, 0xce, 0xba },
+ .{ 0xf6, 0xf6, 0xf6 },
+ },
+};
diff --git a/src/themes/forge_soft.zig b/src/themes/forge_soft.zig
new file mode 100644
index 00000000..0d882fbb
--- /dev/null
+++ b/src/themes/forge_soft.zig
@@ -0,0 +1,51 @@
+//! Pardes forge_soft: Dark Plus on neutral slate, with softer text and vivid blue comments.
+//! A classic-inspired adaptation, not an exact upstream port.
+//! Reference: vendor/themes/dark_plus.toml.
+//! Pardes-specific tag, search, diagnostic and ANSI roles; see docs/themes.md.
+pub const theme = .{
+ .name = "forge_soft",
+ .bg = .{ 0x35, 0x38, 0x3e },
+ .fg = .{ 0xbf, 0xc3, 0xcc },
+ .tag_bg = .{ 0x2a, 0x2d, 0x34 },
+ .tag_fg = .{ 0xc5, 0xc9, 0xd2 },
+ .tag_active_bg = .{ 0x37, 0x3e, 0x49 },
+ .tag_active_fg = .{ 0xd1, 0xd5, 0xde },
+ .box = .{ 0xa5, 0xc4, 0xee },
+ .box_dim = .{ 0x59, 0x65, 0x77 },
+ .kw = .{ 0x75, 0xb5, 0xe8 },
+ .str = .{ 0xda, 0xa5, 0x8e },
+ .num = .{ 0xb5, 0xce, 0xa8 },
+ .comment = .{ 0xb3, 0xca, 0xff },
+ .lineno = .{ 0x86, 0x89, 0x91 },
+ .lineno_active = .{ 0x8e, 0x91, 0x99 },
+ .scroll_track = .{ 0x3d, 0x40, 0x47 },
+ .scroll_thumb = .{ 0x73, 0x80, 0x92 },
+ .border = .{ 0x47, 0x52, 0x63 },
+ .sel_bg = .{ 0x26, 0x4f, 0x68 },
+ .sel_fg = .{ 0xe2, 0xee, 0xf4 },
+ .search_bg = .{ 0x59, 0x4a, 0x25 },
+ .search_fg = .{ 0xf5, 0xdf, 0xa1 },
+ .diagnostic_error = .{ 0xf2, 0x8a, 0x81 },
+ .diagnostic_warning = .{ 0xd7, 0xba, 0x7d },
+ .diagnostic_info = .{ 0x75, 0xbe, 0xff },
+ .diagnostic_hint = .{ 0x8b, 0xce, 0xba },
+ // ANSI roles are semantic colors, independent of peach string syntax.
+ .palette = .{
+ .{ 0x35, 0x38, 0x3e },
+ .{ 0xf2, 0x8a, 0x81 },
+ .{ 0xb5, 0xce, 0xa8 },
+ .{ 0xd7, 0xba, 0x7d },
+ .{ 0x75, 0xbe, 0xff },
+ .{ 0xd4, 0x9b, 0xce },
+ .{ 0x8b, 0xce, 0xba },
+ .{ 0xbf, 0xc3, 0xcc },
+ .{ 0xaa, 0xae, 0xb8 },
+ .{ 0xf2, 0x8a, 0x81 },
+ .{ 0xb5, 0xce, 0xa8 },
+ .{ 0xd7, 0xba, 0x7d },
+ .{ 0x75, 0xbe, 0xff },
+ .{ 0xd4, 0x9b, 0xce },
+ .{ 0x8b, 0xce, 0xba },
+ .{ 0xbf, 0xc3, 0xcc },
+ },
+};
diff --git a/src/themes/harvest.zig b/src/themes/harvest.zig
new file mode 100644
index 00000000..0536ffa8
--- /dev/null
+++ b/src/themes/harvest.zig
@@ -0,0 +1,50 @@
+//! Pardes harvest: Autumn ember keywords, leaf greens and cream; deep sage command rails.
+//! A classic-inspired adaptation, not an exact upstream port.
+//! Reference: vendor/themes/autumn.toml.
+//! Pardes-specific tag, search, diagnostic and ANSI roles; see docs/themes.md.
+pub const theme = .{
+ .name = "harvest",
+ .bg = .{ 0x10, 0x0e, 0x0b },
+ .fg = .{ 0xf3, 0xf2, 0xcc },
+ .tag_bg = .{ 0x34, 0x3b, 0x2e },
+ .tag_fg = .{ 0xd5, 0xd8, 0xb8 },
+ .tag_active_bg = .{ 0x42, 0x4d, 0x38 },
+ .tag_active_fg = .{ 0xe1, 0xe4, 0xc4 },
+ .box = .{ 0xcf, 0xba, 0x8b },
+ .box_dim = .{ 0x77, 0x79, 0x53 },
+ .kw = .{ 0xf0, 0x7d, 0x63 },
+ .str = .{ 0x99, 0xbe, 0x70 },
+ .num = .{ 0xfa, 0xd5, 0x66 },
+ .comment = .{ 0xef, 0xc7, 0x8c },
+ .lineno = .{ 0x6a, 0x64, 0x56 },
+ .lineno_active = .{ 0x72, 0x6c, 0x5e },
+ .scroll_track = .{ 0x20, 0x1d, 0x17 },
+ .scroll_thumb = .{ 0x85, 0x8a, 0x62 },
+ .border = .{ 0x59, 0x65, 0x47 },
+ .sel_bg = .{ 0x4d, 0x54, 0x38 },
+ .sel_fg = .{ 0xf3, 0xf2, 0xcc },
+ .search_bg = .{ 0x66, 0x45, 0x2d },
+ .search_fg = .{ 0xff, 0xe2, 0xac },
+ .diagnostic_error = .{ 0xf5, 0x8a, 0x73 },
+ .diagnostic_warning = .{ 0xfa, 0xd5, 0x66 },
+ .diagnostic_info = .{ 0x86, 0xc1, 0xb9 },
+ .diagnostic_hint = .{ 0xb5, 0xc6, 0x8c },
+ .palette = .{
+ .{ 0x10, 0x0e, 0x0b },
+ .{ 0xf5, 0x8a, 0x73 },
+ .{ 0x99, 0xbe, 0x70 },
+ .{ 0xfa, 0xd5, 0x66 },
+ .{ 0x86, 0xa9, 0xce },
+ .{ 0xd0, 0xa5, 0xb5 },
+ .{ 0x86, 0xc1, 0xb9 },
+ .{ 0xf3, 0xf2, 0xcc },
+ .{ 0xa3, 0xac, 0x97 },
+ .{ 0xf5, 0x8a, 0x73 },
+ .{ 0x99, 0xbe, 0x70 },
+ .{ 0xfa, 0xd5, 0x66 },
+ .{ 0x86, 0xa9, 0xce },
+ .{ 0xd0, 0xa5, 0xb5 },
+ .{ 0x86, 0xc1, 0xb9 },
+ .{ 0xf3, 0xf2, 0xcc },
+ },
+};
diff --git a/src/themes/ink.zig b/src/themes/ink.zig
new file mode 100644
index 00000000..d34f8fae
--- /dev/null
+++ b/src/themes/ink.zig
@@ -0,0 +1,49 @@
+//! Pardes ink: Near-black with bright, unambiguous signals for demanding contrast.
+//! Original palette; editor chrome, search, diagnostics and ANSI output are
+//! designed together. See docs/themes.md for the shared role contract.
+pub const theme = .{
+ .name = "ink",
+ .bg = .{ 0x00, 0x00, 0x00 },
+ .fg = .{ 0xf3, 0xf7, 0xfc },
+ .tag_bg = .{ 0x15, 0x21, 0x2c },
+ .tag_fg = .{ 0xd5, 0xe4, 0xf1 },
+ .tag_active_bg = .{ 0x22, 0x33, 0x42 },
+ .tag_active_fg = .{ 0xe1, 0xee, 0xf9 },
+ .box = .{ 0x86, 0xd8, 0xff },
+ .box_dim = .{ 0x64, 0x79, 0x8b },
+ .kw = .{ 0xd5, 0xb8, 0xff },
+ .str = .{ 0xb5, 0xee, 0xae },
+ .num = .{ 0xff, 0xd6, 0x94 },
+ .comment = .{ 0xa8, 0xe7, 0xf4 },
+ .lineno = .{ 0x62, 0x6b, 0x75 },
+ .lineno_active = .{ 0x6a, 0x73, 0x7d },
+ .scroll_track = .{ 0x15, 0x21, 0x2c },
+ .scroll_thumb = .{ 0x8b, 0xa7, 0xbd },
+ .border = .{ 0x59, 0x6f, 0x83 },
+ .sel_bg = .{ 0x26, 0x52, 0x71 },
+ .sel_fg = .{ 0xff, 0xff, 0xff },
+ .search_bg = .{ 0x75, 0x50, 0x1b },
+ .search_fg = .{ 0xff, 0xff, 0xff },
+ .diagnostic_error = .{ 0xff, 0xb1, 0xb1 },
+ .diagnostic_warning = .{ 0xff, 0xe2, 0x9c },
+ .diagnostic_info = .{ 0x9b, 0xde, 0xff },
+ .diagnostic_hint = .{ 0xc6, 0xe4, 0xb5 },
+ .palette = .{
+ .{ 0x00, 0x00, 0x00 },
+ .{ 0xff, 0xb1, 0xb1 },
+ .{ 0xb5, 0xee, 0xae },
+ .{ 0xff, 0xe2, 0x9c },
+ .{ 0x9b, 0xde, 0xff },
+ .{ 0xd5, 0xb8, 0xff },
+ .{ 0xc6, 0xe4, 0xb5 },
+ .{ 0xf3, 0xf7, 0xfc },
+ .{ 0xb9, 0xc6, 0xd2 },
+ .{ 0xff, 0xb1, 0xb1 },
+ .{ 0xb5, 0xee, 0xae },
+ .{ 0xff, 0xd6, 0x94 },
+ .{ 0x9b, 0xde, 0xff },
+ .{ 0xd5, 0xb8, 0xff },
+ .{ 0xc6, 0xe4, 0xb5 },
+ .{ 0xf3, 0xf7, 0xfc },
+ },
+};
diff --git a/src/themes/lagoon.zig b/src/themes/lagoon.zig
new file mode 100644
index 00000000..cc444ff1
--- /dev/null
+++ b/src/themes/lagoon.zig
@@ -0,0 +1,50 @@
+//! Pardes lagoon: Material Oceanic slate and pastel syntax; deep sea-glass command rails.
+//! A classic-inspired adaptation, not an exact upstream port.
+//! Reference: vendor/themes/material_oceanic.toml (inherits material_deep_ocean.toml).
+//! Pardes-specific tag, search, diagnostic and ANSI roles; see docs/themes.md.
+pub const theme = .{
+ .name = "lagoon",
+ .bg = .{ 0x34, 0x46, 0x4c },
+ .fg = .{ 0xba, 0xc9, 0xce },
+ .tag_bg = .{ 0x29, 0x44, 0x3f },
+ .tag_fg = .{ 0xbb, 0xd7, 0xcb },
+ .tag_active_bg = .{ 0x34, 0x57, 0x4d },
+ .tag_active_fg = .{ 0xc7, 0xe3, 0xd7 },
+ .box = .{ 0x89, 0xc7, 0xb4 },
+ .box_dim = .{ 0x59, 0x7e, 0x71 },
+ .kw = .{ 0xd5, 0xa8, 0xed },
+ .str = .{ 0xc3, 0xe8, 0x8d },
+ .num = .{ 0xff, 0xad, 0x91 },
+ .comment = .{ 0x92, 0xe1, 0xd1 },
+ .lineno = .{ 0x7b, 0x91, 0x94 },
+ .lineno_active = .{ 0x83, 0x99, 0x9c },
+ .scroll_track = .{ 0x3a, 0x4c, 0x50 },
+ .scroll_thumb = .{ 0x72, 0x97, 0x8a },
+ .border = .{ 0x50, 0x74, 0x68 },
+ .sel_bg = .{ 0x39, 0x5b, 0x65 },
+ .sel_fg = .{ 0xe6, 0xf2, 0xf3 },
+ .search_bg = .{ 0x60, 0x53, 0x27 },
+ .search_fg = .{ 0xff, 0xf0, 0xb9 },
+ .diagnostic_error = .{ 0xff, 0x9d, 0xa1 },
+ .diagnostic_warning = .{ 0xff, 0xcb, 0x6b },
+ .diagnostic_info = .{ 0x82, 0xc9, 0xfa },
+ .diagnostic_hint = .{ 0x89, 0xdd, 0xcc },
+ .palette = .{
+ .{ 0x34, 0x46, 0x4c },
+ .{ 0xff, 0x9d, 0xa1 },
+ .{ 0xc3, 0xe8, 0x8d },
+ .{ 0xff, 0xcb, 0x6b },
+ .{ 0x82, 0xc9, 0xfa },
+ .{ 0xd5, 0xa8, 0xed },
+ .{ 0x89, 0xdd, 0xcc },
+ .{ 0xba, 0xc9, 0xce },
+ .{ 0xad, 0xba, 0xbc },
+ .{ 0xff, 0x9d, 0xa1 },
+ .{ 0xc3, 0xe8, 0x8d },
+ .{ 0xff, 0xcb, 0x6b },
+ .{ 0x82, 0xc9, 0xfa },
+ .{ 0xd5, 0xa8, 0xed },
+ .{ 0x89, 0xdd, 0xcc },
+ .{ 0xba, 0xc9, 0xce },
+ },
+};
diff --git a/src/themes/orchard.zig b/src/themes/orchard.zig
new file mode 100644
index 00000000..17ac801a
--- /dev/null
+++ b/src/themes/orchard.zig
@@ -0,0 +1,49 @@
+//! Pardes orchard: Near-black evergreen, with lively leaf comments and plum syntax.
+//! Original palette; editor chrome, search, diagnostics and ANSI output are
+//! designed together. See docs/themes.md for the shared role contract.
+pub const theme = .{
+ .name = "orchard",
+ .bg = .{ 0x0d, 0x14, 0x10 },
+ .fg = .{ 0xe5, 0xee, 0xe5 },
+ .tag_bg = .{ 0x1d, 0x28, 0x24 },
+ .tag_fg = .{ 0xb2, 0xc3, 0xb8 },
+ .tag_active_bg = .{ 0x26, 0x36, 0x2d },
+ .tag_active_fg = .{ 0xbe, 0xcf, 0xc4 },
+ .box = .{ 0xad, 0xcc, 0x91 },
+ .box_dim = .{ 0x4c, 0x63, 0x56 },
+ .kw = .{ 0xc9, 0xb0, 0xe4 },
+ .str = .{ 0xb6, 0xce, 0x94 },
+ .num = .{ 0xe9, 0xbf, 0x91 },
+ .comment = .{ 0xb9, 0xe5, 0x8f },
+ .lineno = .{ 0x59, 0x67, 0x5c },
+ .lineno_active = .{ 0x61, 0x6f, 0x64 },
+ .scroll_track = .{ 0x15, 0x20, 0x19 },
+ .scroll_thumb = .{ 0x63, 0x7f, 0x6a },
+ .border = .{ 0x35, 0x48, 0x3d },
+ .sel_bg = .{ 0x40, 0x5d, 0x4b },
+ .sel_fg = .{ 0xf5, 0xf7, 0xee },
+ .search_bg = .{ 0x57, 0x47, 0x2a },
+ .search_fg = .{ 0xf7, 0xe4, 0xa5 },
+ .diagnostic_error = .{ 0xf1, 0xa3, 0x9b },
+ .diagnostic_warning = .{ 0xe9, 0xc6, 0x80 },
+ .diagnostic_info = .{ 0x9b, 0xcb, 0xd5 },
+ .diagnostic_hint = .{ 0xb6, 0xc5, 0x9e },
+ .palette = .{
+ .{ 0x0d, 0x14, 0x10 },
+ .{ 0xf1, 0xa3, 0x9b },
+ .{ 0xb6, 0xce, 0x94 },
+ .{ 0xe9, 0xc6, 0x80 },
+ .{ 0x9b, 0xcb, 0xd5 },
+ .{ 0xc9, 0xb0, 0xe4 },
+ .{ 0xb6, 0xc5, 0x9e },
+ .{ 0xe5, 0xee, 0xe5 },
+ .{ 0x96, 0xa6, 0x9b },
+ .{ 0xf1, 0xa3, 0x9b },
+ .{ 0xb6, 0xce, 0x94 },
+ .{ 0xe9, 0xbf, 0x91 },
+ .{ 0x9b, 0xcb, 0xd5 },
+ .{ 0xc9, 0xb0, 0xe4 },
+ .{ 0xb6, 0xc5, 0x9e },
+ .{ 0xe5, 0xee, 0xe5 },
+ },
+};
diff --git a/src/themes/orchard_black.zig b/src/themes/orchard_black.zig
new file mode 100644
index 00000000..bf53c66a
--- /dev/null
+++ b/src/themes/orchard_black.zig
@@ -0,0 +1,49 @@
+//! Pardes orchard_black: Pure-black evergreen with bright leaf comments and luminous garden ink.
+//! Original palette; editor chrome, search, diagnostics and ANSI output are
+//! designed together. See docs/themes.md for the shared role contract.
+pub const theme = .{
+ .name = "orchard_black",
+ .bg = .{ 0x00, 0x00, 0x00 },
+ .fg = .{ 0xf2, 0xf8, 0xef },
+ .tag_bg = .{ 0x1d, 0x28, 0x24 },
+ .tag_fg = .{ 0xb2, 0xc3, 0xb8 },
+ .tag_active_bg = .{ 0x26, 0x36, 0x2d },
+ .tag_active_fg = .{ 0xbe, 0xcf, 0xc4 },
+ .box = .{ 0xad, 0xcc, 0x91 },
+ .box_dim = .{ 0x4c, 0x63, 0x56 },
+ .kw = .{ 0xc9, 0xb0, 0xe4 },
+ .str = .{ 0xb6, 0xce, 0x94 },
+ .num = .{ 0xe9, 0xbf, 0x91 },
+ .comment = .{ 0xb9, 0xe5, 0x8f },
+ .lineno = .{ 0x59, 0x67, 0x5c },
+ .lineno_active = .{ 0x61, 0x6f, 0x64 },
+ .scroll_track = .{ 0x11, 0x18, 0x13 },
+ .scroll_thumb = .{ 0x63, 0x7f, 0x6a },
+ .border = .{ 0x35, 0x48, 0x3d },
+ .sel_bg = .{ 0x40, 0x5d, 0x4b },
+ .sel_fg = .{ 0xf5, 0xf7, 0xee },
+ .search_bg = .{ 0x57, 0x47, 0x2a },
+ .search_fg = .{ 0xf7, 0xe4, 0xa5 },
+ .diagnostic_error = .{ 0xf1, 0xa3, 0x9b },
+ .diagnostic_warning = .{ 0xe9, 0xc6, 0x80 },
+ .diagnostic_info = .{ 0x9b, 0xcb, 0xd5 },
+ .diagnostic_hint = .{ 0xb6, 0xc5, 0x9e },
+ .palette = .{
+ .{ 0x00, 0x00, 0x00 },
+ .{ 0xf1, 0xa3, 0x9b },
+ .{ 0xb6, 0xce, 0x94 },
+ .{ 0xe9, 0xc6, 0x80 },
+ .{ 0x9b, 0xcb, 0xd5 },
+ .{ 0xc9, 0xb0, 0xe4 },
+ .{ 0xb6, 0xc5, 0x9e },
+ .{ 0xf2, 0xf8, 0xef },
+ .{ 0x96, 0xa6, 0x9b },
+ .{ 0xf1, 0xa3, 0x9b },
+ .{ 0xb6, 0xce, 0x94 },
+ .{ 0xe9, 0xbf, 0x91 },
+ .{ 0x9b, 0xcb, 0xd5 },
+ .{ 0xc9, 0xb0, 0xe4 },
+ .{ 0xb6, 0xc5, 0x9e },
+ .{ 0xf2, 0xf8, 0xef },
+ },
+};
diff --git a/src/themes/paper.zig b/src/themes/paper.zig
new file mode 100644
index 00000000..7bfb891d
--- /dev/null
+++ b/src/themes/paper.zig
@@ -0,0 +1,49 @@
+//! Pardes paper: Uncoated paper with graphite text and restrained teal accents.
+//! Original palette; editor chrome, search, diagnostics and ANSI output are
+//! designed together. See docs/themes.md for the shared role contract.
+pub const theme = .{
+ .name = "paper",
+ .bg = .{ 0xf5, 0xf3, 0xed },
+ .fg = .{ 0x30, 0x3b, 0x3b },
+ .tag_bg = .{ 0xe8, 0xea, 0xe3 },
+ .tag_fg = .{ 0x52, 0x62, 0x5a },
+ .tag_active_bg = .{ 0xdc, 0xe5, 0xdc },
+ .tag_active_fg = .{ 0x4a, 0x5a, 0x52 },
+ .box = .{ 0x3c, 0x6b, 0x56 },
+ .box_dim = .{ 0x91, 0xa3, 0x95 },
+ .kw = .{ 0x73, 0x51, 0x90 },
+ .str = .{ 0x41, 0x68, 0x48 },
+ .num = .{ 0x87, 0x58, 0x26 },
+ .comment = .{ 0x2e, 0x71, 0x59 },
+ .lineno = .{ 0x8b, 0x91, 0x85 },
+ .lineno_active = .{ 0x83, 0x89, 0x7d },
+ .scroll_track = .{ 0xe5, 0xe8, 0xdf },
+ .scroll_thumb = .{ 0x88, 0x9b, 0x8b },
+ .border = .{ 0xb5, 0xc1, 0xb3 },
+ .sel_bg = .{ 0xc8, 0xdf, 0xd1 },
+ .sel_fg = .{ 0x20, 0x3e, 0x31 },
+ .search_bg = .{ 0xf0, 0xdd, 0xa8 },
+ .search_fg = .{ 0x61, 0x46, 0x1c },
+ .diagnostic_error = .{ 0xa3, 0x39, 0x38 },
+ .diagnostic_warning = .{ 0x80, 0x57, 0x0c },
+ .diagnostic_info = .{ 0x30, 0x65, 0x75 },
+ .diagnostic_hint = .{ 0x52, 0x6d, 0x3e },
+ .palette = .{
+ .{ 0x30, 0x3b, 0x3b },
+ .{ 0xa3, 0x39, 0x38 },
+ .{ 0x41, 0x68, 0x48 },
+ .{ 0x80, 0x57, 0x0c },
+ .{ 0x30, 0x65, 0x75 },
+ .{ 0x73, 0x51, 0x90 },
+ .{ 0x52, 0x6d, 0x3e },
+ .{ 0x30, 0x3b, 0x3b },
+ .{ 0x64, 0x6e, 0x65 },
+ .{ 0xa3, 0x39, 0x38 },
+ .{ 0x41, 0x68, 0x48 },
+ .{ 0x87, 0x58, 0x26 },
+ .{ 0x30, 0x65, 0x75 },
+ .{ 0x73, 0x51, 0x90 },
+ .{ 0x52, 0x6d, 0x3e },
+ .{ 0x30, 0x3b, 0x3b },
+ },
+};
diff --git a/src/themes/solarium.zig b/src/themes/solarium.zig
new file mode 100644
index 00000000..84866830
--- /dev/null
+++ b/src/themes/solarium.zig
@@ -0,0 +1,50 @@
+//! Pardes solarium: Solarized deep blue-green and warm ink; teal command rails.
+//! A classic-inspired adaptation, not an exact upstream port.
+//! Reference: vendor/themes/solarized_dark.toml.
+//! Pardes-specific tag, search, diagnostic and ANSI roles; see docs/themes.md.
+pub const theme = .{
+ .name = "solarium",
+ .bg = .{ 0x17, 0x3e, 0x45 },
+ .fg = .{ 0xa7, 0xb7, 0xae },
+ .tag_bg = .{ 0x12, 0x3f, 0x43 },
+ .tag_fg = .{ 0xc7, 0xd4, 0xbd },
+ .tag_active_bg = .{ 0x21, 0x4e, 0x50 },
+ .tag_active_fg = .{ 0xd3, 0xe0, 0xc9 },
+ .box = .{ 0xd5, 0xbc, 0x72 },
+ .box_dim = .{ 0x4c, 0x79, 0x72 },
+ .kw = .{ 0x6a, 0xae, 0xdd },
+ .str = .{ 0xaf, 0xbd, 0x52 },
+ .num = .{ 0xd9, 0x9a, 0x5e },
+ .comment = .{ 0xe2, 0xc4, 0x6e },
+ .lineno = .{ 0x64, 0x7e, 0x7c },
+ .lineno_active = .{ 0x6c, 0x86, 0x84 },
+ .scroll_track = .{ 0x1c, 0x45, 0x4c },
+ .scroll_thumb = .{ 0x69, 0x93, 0x8a },
+ .border = .{ 0x38, 0x65, 0x5f },
+ .sel_bg = .{ 0x27, 0x56, 0x5c },
+ .sel_fg = .{ 0xee, 0xe8, 0xd5 },
+ .search_bg = .{ 0x64, 0x53, 0x26 },
+ .search_fg = .{ 0xff, 0xf0, 0xb9 },
+ .diagnostic_error = .{ 0xed, 0x84, 0x77 },
+ .diagnostic_warning = .{ 0xdf, 0xb6, 0x5b },
+ .diagnostic_info = .{ 0x6a, 0xae, 0xdd },
+ .diagnostic_hint = .{ 0x69, 0xbd, 0xb0 },
+ .palette = .{
+ .{ 0x17, 0x3e, 0x45 },
+ .{ 0xed, 0x84, 0x77 },
+ .{ 0xaf, 0xbd, 0x52 },
+ .{ 0xdf, 0xb6, 0x5b },
+ .{ 0x6a, 0xae, 0xdd },
+ .{ 0xb3, 0x9d, 0xdc },
+ .{ 0x69, 0xbd, 0xb0 },
+ .{ 0xa7, 0xb7, 0xae },
+ .{ 0x91, 0xa8, 0xa8 },
+ .{ 0xed, 0x84, 0x77 },
+ .{ 0xaf, 0xbd, 0x52 },
+ .{ 0xdf, 0xb6, 0x5b },
+ .{ 0x6a, 0xae, 0xdd },
+ .{ 0xb3, 0x9d, 0xdc },
+ .{ 0x69, 0xbd, 0xb0 },
+ .{ 0xa7, 0xb7, 0xae },
+ },
+};
diff --git a/src/themes/spectrum.zig b/src/themes/spectrum.zig
new file mode 100644
index 00000000..8c43fada
--- /dev/null
+++ b/src/themes/spectrum.zig
@@ -0,0 +1,50 @@
+//! Pardes spectrum: Monokai Pro charcoal and candy syntax; warm umber command rails.
+//! A classic-inspired adaptation, not an exact upstream port.
+//! Reference: vendor/themes/monokai_pro.toml.
+//! Pardes-specific tag, search, diagnostic and ANSI roles; see docs/themes.md.
+pub const theme = .{
+ .name = "spectrum",
+ .bg = .{ 0x10, 0x0e, 0x11 },
+ .fg = .{ 0xfc, 0xfc, 0xfa },
+ .tag_bg = .{ 0x3b, 0x38, 0x30 },
+ .tag_fg = .{ 0xdd, 0xd8, 0xbb },
+ .tag_active_bg = .{ 0x4d, 0x47, 0x36 },
+ .tag_active_fg = .{ 0xe9, 0xe4, 0xc7 },
+ .box = .{ 0xff, 0xd8, 0x66 },
+ .box_dim = .{ 0x8b, 0x80, 0x56 },
+ .kw = .{ 0xff, 0x61, 0x88 },
+ .str = .{ 0xa9, 0xdc, 0x76 },
+ .num = .{ 0xab, 0x9d, 0xf2 },
+ .comment = .{ 0xff, 0xe0, 0x9b },
+ .lineno = .{ 0x68, 0x61, 0x6b },
+ .lineno_active = .{ 0x70, 0x69, 0x73 },
+ .scroll_track = .{ 0x21, 0x1d, 0x23 },
+ .scroll_thumb = .{ 0x91, 0x8b, 0x72 },
+ .border = .{ 0x6a, 0x64, 0x50 },
+ .sel_bg = .{ 0x51, 0x43, 0x5c },
+ .sel_fg = .{ 0xfc, 0xfc, 0xfa },
+ .search_bg = .{ 0x66, 0x56, 0x27 },
+ .search_fg = .{ 0xff, 0xf0, 0xb0 },
+ .diagnostic_error = .{ 0xff, 0x79, 0x9b },
+ .diagnostic_warning = .{ 0xff, 0xd8, 0x66 },
+ .diagnostic_info = .{ 0x78, 0xdc, 0xe8 },
+ .diagnostic_hint = .{ 0xa9, 0xdc, 0x76 },
+ .palette = .{
+ .{ 0x10, 0x0e, 0x11 },
+ .{ 0xff, 0x79, 0x9b },
+ .{ 0xa9, 0xdc, 0x76 },
+ .{ 0xff, 0xd8, 0x66 },
+ .{ 0x8f, 0xb5, 0xf5 },
+ .{ 0xab, 0x9d, 0xf2 },
+ .{ 0x78, 0xdc, 0xe8 },
+ .{ 0xfc, 0xfc, 0xfa },
+ .{ 0xad, 0xa5, 0xae },
+ .{ 0xff, 0x79, 0x9b },
+ .{ 0xa9, 0xdc, 0x76 },
+ .{ 0xff, 0xd8, 0x66 },
+ .{ 0x8f, 0xb5, 0xf5 },
+ .{ 0xab, 0x9d, 0xf2 },
+ .{ 0x78, 0xdc, 0xe8 },
+ .{ 0xfc, 0xfc, 0xfa },
+ },
+};
diff --git a/src/tutor.txt b/src/tutor.txt
index b2110dd8..7ee56add 100644
--- a/src/tutor.txt
+++ b/src/tutor.txt
@@ -59,10 +59,13 @@
2-1 (hold middle, click left) execute the middle word WITH the
left selection as its argument
- Every tag with text leads with Save; a terminal also has Filter.
- Images and PDFs show "New Del". The top bar is:
+ Every tag with text leads with Save; a terminal also has Togglettymode
+ and Filter. Tty opens a terminal; New belongs to each column tag.
+ Images show "Tty Del Collapse"; PDFs also have PdfSections and PdfTint.
+ Every pane has Collapse: hide its body, then execute again to expand it.
+ The top bar is:
- New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor
+ Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor
Debug Kill
Reach it from the keyboard with `k` off the topmost tagline; `j` comes
@@ -119,7 +122,10 @@
Alt-c move the active pane into a fresh column — any pane, not
just a terminal. A no-op if it is alone in its column,
or if the sixth column already exists.
- New Newcol in the top bar: a pane, or a pane in a new column
+ New in a column tag: a new scratch pane
+ Newcol in the top bar: a pane in a new column
+ Tty new terminal in the calling pane's directory
+ Togglettymode in a terminal tag: switch editor/raw mode (Ctrl-B)
Joincol delete this column, move its panes to the one right
Del in a pane's own tag: close it
diff --git a/test/appearance_gallery.py b/test/appearance_gallery.py
new file mode 100644
index 00000000..c80d1a33
--- /dev/null
+++ b/test/appearance_gallery.py
@@ -0,0 +1,213 @@
+#!/usr/bin/env python3
+"""Review native palettes, compact tags, sized fonts and pets in an owned SDL session."""
+import argparse
+import hashlib
+import json
+import os
+from pathlib import Path
+import subprocess
+import time
+
+from fs import session
+from ui_review import capture, command, panes, require, wait_for
+
+
+THEMES = ('forge', 'lagoon', 'solarium', 'spectrum', 'harvest', 'clay')
+NOTES = b'''Pardes / workspace review
+
+New belongs to the column.
+Tty opens a terminal.
+Togglettymode switches its input mode.
+
+Font MartianMono-NrRg:18
+TaglineSize 80
+
+Native palettes
+ forge familiar charcoal
+ lagoon oceanic blue
+ solarium quiet solar tones
+ spectrum vivid syntax
+ harvest warm earth
+ clay soft rose and pine
+
+Pet cat / Pet frog / Pet off
+Companions stay in unused workspace-tag space.
+'''
+PREFERENCE_NOTES = b'''Pardes / contrast studies
+
+Comments carry their weight.
+Line numbers stay in the background.
+Current line: bold quiet ink, no bright block.
+
+Forge: neutral, near-black charcoal
+ Theme forge
+ Theme forge_black
+ Theme forge_soft
+
+Orchard: crisp woodland color
+ Theme orchard
+ Theme orchard_black
+
+Dusk: intentionally soft and warm
+ Theme dusk
+
+ThemeSel: Pardes themes come first.
+'''
+
+
+def run(args):
+ root = args.output.resolve()
+ root.mkdir(parents=True, mode=0o700, exist_ok=True)
+ root.chmod(0o700)
+ config = root / 'config/pardes'
+ config.mkdir(parents=True, exist_ok=True)
+ (config / 'init').write_text('Shell /bin/sh\nTheme forge\nFont MartianMono-NrRg:18\nTaglineSize 80\n')
+ source_path = args.project.resolve() / 'gossip/src/crds_value.rs'
+ original = source_path.read_bytes()
+ name = 'appearance-gallery-' + str(os.getpid())
+ launch = ['-c', 'stty cols 150 rows 48; exec "$@"', name,
+ str(args.binary.resolve()), '--9p=' + name, str(source_path)]
+ inherited = {'PARDES_TEST': '1', 'PARDES_TEST_CAPTURE_DIR': str(root),
+ 'PARDES_TEST_COLS': '150', 'PARDES_TEST_ROWS': '48',
+ 'SDL_VIDEODRIVER': 'x11'}
+ if args.live_window:
+ inherited = {'SDL_VIDEODRIVER': 'x11'}
+ handles = {}
+ report = {'themes': [], 'pets': [], 'os_windows': []}
+ with session('/bin/sh', root, name, socket_name=name, tty=True,
+ launch=launch, inherited=inherited, terminal=handles) as (client, _):
+ source = next(serial for serial, tag in panes(client).items() if str(source_path) in tag)
+ before = set(panes(client))
+ command(client, source, 'Newcol')
+ right = require(wait_for(lambda: next((s for s in panes(client) if s not in before), None)), 'right column missing')
+ client.write(f'/self/pane/{right}/ctl', f'name {root / "Review"}\n'.encode())
+ client.write(f'/self/pane/{right}/body', PREFERENCE_NOTES if args.theme_selector else NOTES, truncate=True)
+ client.write(f'/self/pane/{right}/ctl', b'clean\n')
+ before = set(panes(client))
+ command(client, right, 'Tty')
+ terminal = require(wait_for(lambda: next((s for s in panes(client) if s not in before), None)), 'terminal missing')
+ client.write(f'/self/pane/{terminal}/pty/data', b"PS1='$ '; printf '\\033[2J\\033[H\\033[1;36mPardes workspace\\033[0m\\n\\n'; printf 'Agave source: read-only\\nTerminal: ready\\n\\n'; printf '\\033[32mSmall touches. Same workflow.\\033[0m\\n'\r")
+ require(wait_for(lambda: b'Small touches. Same workflow.' in client.read(f'/self/pane/{terminal}/body')), 'terminal output missing')
+
+ def config_report():
+ before = set(panes(client))
+ command(client, right, 'Config')
+ pane = require(wait_for(lambda: next((s for s in panes(client) if s not in before), None)), 'Config output missing')
+ text = client.read(f'/self/pane/{pane}/body').decode()
+ client.write(f'/self/pane/{pane}/ctl', b'del\n')
+ return text
+
+ settings = config_report()
+ require('Font effective size: 18.00 pixels' in settings, 'configured font size not applied: ' + settings)
+ require('TaglineSize: 80' in settings, 'configured tag size missing')
+ (root / 'effective-config.txt').write_text(settings)
+ report['font_effective_pixels'] = 18
+ report['tagline_percent'] = 80
+ for serial, tag in panes(client).items():
+ require(' New ' not in tag, 'pane still contains New')
+ require('Newtty' not in tag, 'old terminal name remains')
+ require('Togglettymode' in panes(client)[terminal], 'terminal mode action missing')
+
+ def owned_window():
+ result = subprocess.run(['xdotool', 'search', '--onlyvisible', '--pid', str(handles['pid'])],
+ text=True, capture_output=True)
+ ids = result.stdout.split()
+ if not ids:
+ return None
+ window = ids[0]
+ actual_pid = subprocess.check_output(['xdotool', 'getwindowpid', window], text=True).strip()
+ require(actual_pid == str(handles['pid']), 'OS capture window is not owned')
+ return window
+
+ window = require(wait_for(owned_window), 'owned SDL window missing')
+ subprocess.run(['xdotool', 'windowsize', window, '1440', '960'], check=True)
+
+ def take_frame(label):
+ capture(client, root, label, not args.live_window)
+ if not args.live_window:
+ return
+ window = require(owned_window(), 'owned SDL window disappeared')
+ subprocess.run(['magick', 'import', '-window', window, str(root / (label + '.png'))], check=True)
+ if window not in report['os_windows']:
+ report['os_windows'].append(window)
+
+ for theme in args.themes:
+ command(client, right, 'Theme ' + theme)
+ if args.theme_selector:
+ # Keep both quiet active gutter ink and vivid comments in view.
+ client.write(f'/self/pane/{source}/ctl', f'look {source_path}:117\n'.encode())
+ take_frame('classic-' + theme)
+ if args.theme_selector:
+ frame = client.screen()
+ row = frame['cursor']['y'] * frame['cols']
+ gutter = frame['styles'][frame['cells'][row + 2][1]]
+ margin = frame['styles'][frame['cells'][row + 1][1]]
+ require(gutter['bg'] == margin['bg'], 'active line number has a background block in ' + theme)
+ require(gutter['bold'], 'active line number is not bold in ' + theme)
+ previous = frame['styles'][frame['cells'][row - frame['cols'] + 2][1]]
+ require(not previous['bold'], 'inactive line number is bold in ' + theme)
+ active_tag = frame['styles'][frame['cells'][2 * frame['cols'] + 2][1]]
+ inactive_tag = frame['styles'][frame['cells'][2 * frame['cols'] + frame['cols'] // 2 + 2][1]]
+ def ink_polarity(style):
+ return sum(style['fg']['rgb']) - sum(style['bg']['rgb'])
+ require(ink_polarity(active_tag) * ink_polarity(inactive_tag) > 0,
+ 'focused tag inverts the inactive tag in ' + theme)
+ report['active_gutter_bold_without_block'] = True
+ report['focus_tags_without_inversion'] = True
+ report['themes'].append(theme)
+ command(client, right, 'Theme forge')
+ if args.theme_selector:
+ command(client, terminal, 'Collapse')
+ before = set(panes(client))
+ command(client, right, 'ThemeSel')
+ selector = require(wait_for(lambda: next((s for s in panes(client) if s not in before), None)),
+ 'ThemeSel missing')
+ body = client.read(f'/self/pane/{selector}/body').decode()
+ native, legacy = body.split('# Legacy and imported themes', 1)
+ for theme in ('forge_black', 'forge_soft', 'orchard_black'):
+ require('Theme ' + theme + '\n' in native, 'native contrast variant below legacy heading')
+ require('Theme helix\n' in legacy, 'legacy theme section missing')
+ require('Theme orchard' in ''.join(c[0] for c in client.screen()['cells']),
+ 'ThemeSel did not open at native first entry')
+ take_frame('theme-selector')
+ report['native_themes_first'] = True
+ client.write(f'/self/pane/{selector}/ctl', b'del\n')
+ command(client, terminal, 'Collapse')
+ for pet in (() if args.skip_pets else ('cat', 'frog', 'off')):
+ command(client, right, 'Pet ' + pet)
+ settings = config_report()
+ require('Pet: ' + pet + '\n' in settings, 'pet setting not applied')
+ # Returning focus to the source closes all transient report state.
+ client.write(f'/self/pane/{source}/ctl', f'look {source_path}:1\n'.encode())
+ take_frame('pet-' + pet)
+ if pet != 'off':
+ frame = client.screen()
+ original_tag = frame['cells'][:frame['cols']]
+ time.sleep(1)
+ take_frame('pet-' + pet + '-later')
+ frame = client.screen()
+ require(original_tag == frame['cells'][:frame['cols']], 'pet animation changed tag text or styles')
+ def band_digest(label):
+ pixels = subprocess.check_output(['magick', str(root / (label + '.png')),
+ '-crop', '1500x20+0+0', '-depth', '8', 'RGB:-'])
+ return hashlib.sha256(pixels).hexdigest()
+ require(band_digest('pet-' + pet) != band_digest('pet-' + pet + '-later'),
+ 'pet did not animate in workspace tag')
+ report['pets'].append(pet)
+ require(client.read(f'/self/pane/{source}/body') == original == source_path.read_bytes(), 'Agave source changed')
+ report['source_unchanged'] = True
+ client.write(f'/self/pane/{terminal}/pty/data', b'exit\r')
+ (root / 'report.json').write_text(json.dumps(report, indent=2))
+ print(json.dumps(report, indent=2))
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('binary', type=Path)
+ parser.add_argument('output', type=Path)
+ parser.add_argument('--project', required=True, type=Path)
+ parser.add_argument('--live-window', action='store_true', help='capture the owned OS window without offscreen test mode')
+ parser.add_argument('--themes', nargs='+', default=THEMES, help='themes to compare in order')
+ parser.add_argument('--skip-pets', action='store_true', help='review palettes without repeating pet animation tests')
+ parser.add_argument('--theme-selector', action='store_true', help='capture native-first picker and focused source gutter')
+ run(parser.parse_args())
diff --git a/test/collapse_layout.py b/test/collapse_layout.py
new file mode 100644
index 00000000..e549bd37
--- /dev/null
+++ b/test/collapse_layout.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python3
+"""Check local Collapse height transfers through an owned SDL or TTY 9P session.
+
+python3 -B test/collapse_layout.py zig-out/column-review/bin/pardes-gui
+python3 -B test/collapse_layout.py zig-out/column-review/bin/pardes --tty
+
+Measures tagline boundaries in the rendered core grid, not host pixel geometry.
+No user session is contacted, and all fixture files live in a temporary directory.
+"""
+import argparse
+from pathlib import Path
+import tempfile
+
+from fs import new_pane, session
+from ui_review import panes, require, wait_for
+
+
+def geometry(client, names):
+ frame = client.screen()
+ rows = [''.join(cell[0] for cell in frame['cells'][row * frame['cols']:(row + 1) * frame['cols']])
+ for row in range(frame['rows'])]
+ starts = [next((row for row, text in enumerate(rows) if '/' + name + ' ' in text), None)
+ for name in names]
+ if any(row is None for row in starts) or starts != sorted(set(starts)):
+ return None
+ ends = starts[1:] + [frame['rows']]
+ return tuple((start, end - start) for start, end in zip(starts, ends))
+
+
+def toggle(client, serial):
+ """Execute the default tag's Collapse word without changing any body or tag."""
+ pane = f'/self/pane/{serial}'
+ tag = client.read(pane + '/tag')
+ at = tag.rfind(b' Collapse')
+ require(at >= 0, 'default pane tag lacks Collapse')
+ at += 1
+ client.write(pane + '/event', f'Mx{at} {at + len("Collapse")}\n'.encode())
+
+
+def run(args):
+ binary = str(args.binary.resolve())
+ with tempfile.TemporaryDirectory(prefix='pardes-collapse-') as directory:
+ root = Path(directory)
+ name = 'collapse-layout'
+ inherited = {} if args.tty else {
+ 'PARDES_TEST': '1', 'PARDES_TEST_COLS': '120', 'PARDES_TEST_ROWS': '48',
+ 'PARDES_TEST_CAPTURE_DIR': str(root),
+ 'SDL_VIDEODRIVER': 'x11',
+ }
+ launch = ['-c', 'stty cols 120 rows 48; exec "$@"', name, binary,
+ '--9p=' + name, str(root / (name + '.txt'))]
+ with session('/bin/sh', root, name, socket_name=name, tty=True,
+ launch=launch, inherited=inherited) as (client, _):
+ serials = [next(iter(panes(client)))]
+ names = [f'collapse-{letter}' for letter in 'ABCD']
+ contents = b'owned collapse fixture\n' * 60
+ for index, label in enumerate(names):
+ if index:
+ serials.append(new_pane(client, b''))
+ pane = f'/self/pane/{serials[index]}'
+ client.write(pane + '/ctl', ('name ' + label + '\n').encode())
+ client.write(pane + '/body', contents, truncate=True)
+ original = require(wait_for(lambda: geometry(client, names)), 'four pane tags not visible')
+ require(all(height > 1 for _, height in original), f'fixture has no body room: {original}')
+ for target in [1, 3, 0, 2, 1, 3, 0]:
+ recipient = target - 1 if target else 1
+ heights = [height for _, height in original]
+ heights[recipient] += heights[target] - 1
+ heights[target] = 1
+ expected = []
+ row = original[0][0]
+ for height in heights:
+ expected.append((row, height))
+ row += height
+ toggle(client, serials[target])
+ require(wait_for(lambda: geometry(client, names) == tuple(expected)),
+ f'Collapse {names[target]} changed unrelated geometry: {geometry(client, names)} != {expected}')
+ for index in range(4):
+ if index not in [target, recipient]:
+ require(expected[index] == original[index], 'unrelated pane moved')
+ toggle(client, serials[target])
+ require(wait_for(lambda: geometry(client, names) == original),
+ f'expansion did not restore original geometry: {geometry(client, names)}')
+ for serial in serials:
+ require(client.read(f'/self/pane/{serial}/body') == contents, 'Collapse changed pane contents')
+ require((root / (name + '.txt')).read_bytes() == b'initial\n', 'fixture source file changed')
+ print(f'{"TTY" if args.tty else "SDL"}: 7 local collapse/expand pairs, exact unrelated pane geometry, and content preservation passed')
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('binary', type=Path)
+ parser.add_argument('--tty', action='store_true')
+ run(parser.parse_args())
diff --git a/test/column_tags.py b/test/column_tags.py
new file mode 100644
index 00000000..6173d38a
--- /dev/null
+++ b/test/column_tags.py
@@ -0,0 +1,306 @@
+#!/usr/bin/env python3
+"""Exercise editable global, column and pane tags through real host input.
+
+python3 -B test/column_tags.py zig-out/column-review/bin/pardes-gui \\
+ /tmp/pardes-column-tags --project /path/to/agave
+
+9P observes state and prepares owned scratch panes. SGR mouse events and
+keyboard bytes enter through the session's real PTY input parser. SDL mode
+captures GPU PNGs; --tty records the core grid and styles. This is not an
+independent terminal-emulator screenshot or an SDL pixel-coordinate test.
+"""
+import argparse
+import codecs
+import contextlib
+import json
+import os
+from pathlib import Path
+import re
+
+from fs import session
+from ninep import Client
+from ui_review import capture, command, panes, require, wait_for
+
+
+class Input:
+ def __init__(self, fd):
+ self.fd = fd
+
+ def send(self, data):
+ os.write(self.fd, data.encode() if isinstance(data, str) else data)
+
+ def mouse(self, button, col, row, release=False, drag=False):
+ code = button + (32 if drag else 0)
+ self.send(f'\x1b[<{code};{col + 1};{row + 1}{"m" if release else "M"}')
+
+ def click(self, col, row, button=0):
+ self.mouse(button, col, row)
+ self.mouse(button, col, row, release=True)
+
+ def drag(self, first, last, row):
+ self.mouse(0, first, row)
+ self.mouse(0, last, row, drag=True)
+ self.mouse(0, last, row, release=True)
+
+ def escape(self):
+ # SDL's test feed reserves a partial ESC]777;finger prefix. CSI-u
+ # identifies Escape unambiguously without waiting for another byte.
+ self.send(b'\x1b[27u')
+
+
+def row_text(client, row):
+ frame = client.screen()
+ return ''.join(cell[0] for cell in frame['cells'][row * frame['cols']:(row + 1) * frame['cols']]).rstrip()
+
+
+def locate(client, word, row=None, minimum_col=0):
+ """Find an ASCII needle using cell positions, even after wide glyphs."""
+ frame = client.screen()
+ rows = range(frame['rows']) if row is None else [row]
+ for y in rows:
+ cells = frame['cells'][y * frame['cols']:(y + 1) * frame['cols']]
+ for x in range(minimum_col, frame['cols']):
+ if ''.join(cell[0] for cell in cells[x:x + len(word)]) == word:
+ return x, y
+ return None
+
+
+def await_text(client, row, text):
+ require(wait_for(lambda: text in row_text(client, row)), f'row {row} never showed {text!r}')
+
+
+def tag(client, serial):
+ return client.read(f'/self/pane/{serial}/tag').decode().rstrip('\n')
+
+
+def new_serial(client, previous):
+ return next((serial for serial in panes(client) if serial not in previous), None)
+
+
+def exec_tag_without_cleanup(client, serial, text):
+ """Restore can replace the whole core, so never touch the old pane after it."""
+ client.write(f'/self/pane/{serial}/tag', (' ' + text).encode())
+ whole = client.read(f'/self/pane/{serial}/tag')
+ start = whole.rfind(text.encode())
+ client.write(f'/self/pane/{serial}/event', f'Mx{start} {start + len(text.encode())}\n'.encode())
+
+
+def reconnect(address):
+ try:
+ return Client(address)
+ except (OSError, EOFError):
+ return None
+
+
+def run(args):
+ root = args.output.resolve()
+ root.mkdir(parents=True, mode=0o700, exist_ok=True)
+ root.chmod(0o700)
+ config = root / 'config/pardes'
+ config.mkdir(parents=True, exist_ok=True)
+ (config / 'init').write_text('Shell /bin/sh\nTheme orchard\n')
+ source = args.project.resolve() / 'gossip/src/crds_value.rs'
+ original = source.read_bytes()
+ name = 'column-tags-' + str(os.getpid())
+ launch = ['-c', 'stty cols 150 rows 48; exec "$@"', 'column-tags',
+ str(args.binary.resolve()), '--9p=' + name, str(source)]
+ env = {} if args.tty else {
+ 'PARDES_TEST': '1', 'PARDES_TEST_CAPTURE_DIR': str(root),
+ 'PARDES_TEST_COLS': '150', 'PARDES_TEST_ROWS': '48', 'SDL_VIDEODRIVER': 'x11',
+ }
+ handles = {}
+ checks = []
+ with session('/bin/sh', root, name, socket_name=name, tty=True,
+ launch=launch, inherited=env, terminal=handles) as (client, address), contextlib.ExitStack() as connections:
+ print('socket', address, flush=True)
+ keys = Input(handles['input_fd'])
+ await_text(client, 1, 'New Tty Find Grep Joincol')
+ require(locate(client, 'New Tty', row=1) == (0, 1), 'left column tag does not start flush-left')
+ require(tag(client, 1).startswith(str(source) + ' Save Tty Del'),
+ 'generated gap still separates the filename from pane commands')
+ checks.append('pane commands follow the filename with one space')
+
+ # Global header: actual left drag replaces Joincol, End appends Unicode,
+ # and backspace removes a wide character as one grapheme.
+ keys.drag(7, 14, 0)
+ keys.send('Help')
+ require(wait_for(lambda: row_text(client, 0).startswith('Newcol Help ')), 'global drag replacement failed')
+ keys.send(b'\x1b[F')
+ keys.send(' Ω界')
+ await_text(client, 0, ' Ω界')
+ keys.send(b'\x7f')
+ require(wait_for(lambda: row_text(client, 0).endswith(' Ω')), 'wide-character backspace split a grapheme')
+ keys.send('界')
+ await_text(client, 0, ' Ω界')
+ global_text = row_text(client, 0)
+ keys.escape()
+ checks.append('global drag replacement, typing, Unicode and grapheme backspace')
+
+ before = panes(client)
+ keys.click(*require(locate(client, 'Newcol', row=0), 'Newcol missing'), button=1)
+ right = require(wait_for(lambda: new_serial(client, before)), 'Newcol did not create its pane')
+ right_name = root / 'right.rs'
+ client.write(f'/self/pane/{right}/ctl', f'name {right_name}\n'.encode())
+ right_body = b'// Column-local scratch\nfn main() {\n let ready = true;\n}\n'
+ client.write(f'/self/pane/{right}/body', right_body)
+ client.write(f'/self/pane/{right}/ctl', b'clean\n')
+ require(wait_for(lambda: locate(client, 'New Tty', row=1, minimum_col=75)), 'right column tag missing')
+ require(locate(client, 'New Tty', row=1, minimum_col=75) == (75, 1),
+ 'right column tag retains an inset')
+ checks.append('column tags start at the first cell of each column')
+
+ # Column header uses half-open drag ranges; replacement must not leak
+ # into its neighbour, the global header, or the active pane's body.
+ col_start, _ = locate(client, 'New Tty', row=1, minimum_col=75)
+ keys.click(col_start, 1)
+ keys.send(b'\x1b[F')
+ keys.send(' Scope λ界')
+ await_text(client, 1, 'Scope λ界')
+ scope_x, _ = require(locate(client, 'Scope', row=1, minimum_col=75), 'column suffix missing')
+ keys.drag(scope_x, scope_x + len('Scope'), 1)
+ keys.send('Work')
+ await_text(client, 1, 'Work λ界')
+ require('Scope' not in row_text(client, 1), 'column replacement appended to selection')
+ keys.escape()
+ require(row_text(client, 0) == global_text, 'column edit changed global tag')
+ checks.append('column drag replacement and Unicode are scoped to that column')
+
+ # Click the left source body, then execute New on the inactive RIGHT
+ # column. A distinct marker must render on the right half afterwards.
+ keys.click(12, 4)
+ before = panes(client)
+ keys.click(col_start, 1, button=1)
+ extra = require(wait_for(lambda: new_serial(client, before)), 'right-column New did not create a pane')
+ client.write(f'/self/pane/{extra}/body', b'RIGHT-COLUMN-NEW\n')
+ require(wait_for(lambda: locate(client, 'RIGHT-COLUMN-NEW', minimum_col=75)), 'right-column command targeted another column')
+ client.write(f'/self/pane/{extra}/ctl', b'delete\n')
+ checks.append('middle-click New targets the inactive right column')
+
+ # An owned short-path file makes its complete tag visible. Pane-tag
+ # selections retain the existing inclusive endpoint convention.
+ save_x, pane_y = require(wait_for(lambda: locate(client, 'Save Tty', minimum_col=75)), 'right pane actions missing')
+ keys.click(save_x, pane_y)
+ keys.send(b'\x1b[F')
+ keys.send(' TailMark')
+ require(wait_for(lambda: tag(client, right).endswith(' TailMark')), 'pane tail typing failed')
+ mark_x, mark_y = require(locate(client, 'TailMark', minimum_col=75), 'pane tail marker not visible')
+ keys.drag(mark_x, mark_x + len('TailMark') - 1, mark_y)
+ keys.send('Local')
+ require(wait_for(lambda: tag(client, right).endswith(' Local')), 'pane selection replacement failed')
+ keys.escape()
+ checks.append('pane command tail supports typing and selection replacement')
+
+ filename_x, filename_y = require(locate(client, 'right.rs', minimum_col=75), 'short filename not visible')
+ keys.click(filename_x, filename_y)
+ keys.send('X')
+ require(wait_for(lambda: 'Xright.rs' in tag(client, right)), 'filename draft did not become editable')
+ keys.escape()
+ require(wait_for(lambda: tag(client, right).startswith(str(right_name) + ' ')), 'Escape did not cancel filename draft')
+ require(not (root / 'Xright.rs').exists(), 'editing a filename wrote a file')
+ require(client.read(f'/self/pane/{right}/body') == right_body, 'tag editing changed file body')
+ checks.append('filename draft cancels without disk writes or body changes')
+
+ # Keep a real embedded shell in the right column for useful captures.
+ keys.click(12, 4)
+ before = panes(client)
+ keys.click(*require(locate(client, 'Tty', row=1, minimum_col=75), 'Tty missing'), button=1)
+ terminal = require(wait_for(lambda: new_serial(client, before)), 'column Tty did not create a pane')
+ require('pty' in client.list(f'/self/pane/{terminal}'), 'Tty created a non-terminal pane')
+ client.write(f'/self/pane/{terminal}/pty/data', b"printf 'Column-local terminal ready\\n'; pwd\r")
+ require(wait_for(lambda: b'\nColumn-local terminal ready\n' in client.read(f'/self/pane/{terminal}/body').replace(b'\r', b'')), 'terminal command output missing')
+ checks.append('right-column embedded terminal executes harmless commands')
+
+ # Persistence is checked through real Dump/Restore dispatch and the
+ # resulting live header rows, not just serializer string matching.
+ command(client, right, 'Dump')
+ dump_path = root / (name + '.dump.zon')
+ require(wait_for(dump_path.exists), 'Dump did not create an isolated session file')
+ dumped = dump_path.read_bytes()
+ saved_global = re.search(rb'\.topbar_custom\s*=\s*"((?:[^"\\]|\\.)*)"', dumped)
+ require(saved_global and codecs.escape_decode(saved_global[1])[0].decode() == global_text,
+ 'global custom tag absent from dump')
+ require(b'New Tty Find Grep Joincol Work' in dumped, 'column custom tag absent from dump')
+ keys.click(1, 0)
+ keys.send(b'\x1b[F')
+ keys.send(' TEMP')
+ await_text(client, 0, ' TEMP')
+ keys.escape()
+ try:
+ exec_tag_without_cleanup(client, right, 'Restore ' + str(dump_path))
+ except (ConnectionResetError, BrokenPipeError, EOFError):
+ # Restore replaces the core and listener; even the write's final
+ # clunk may lose its connection after successful dispatch.
+ pass
+ client.socket.close()
+ client = connections.enter_context(require(wait_for(lambda: reconnect(address)), '9P did not return after Restore'))
+ require(wait_for(lambda: row_text(client, 0) == global_text), 'Restore lost the custom global tag')
+ await_text(client, 1, 'Work λ界')
+ checks.append('Dump/Restore preserves custom global and column text')
+
+ source_serial = require(next((serial for serial, text in panes(client).items() if str(source) in text), None), 'source pane lost after restore')
+ right = require(next((serial for serial, text in panes(client).items() if str(right_name) in text), None), 'scratch pane lost after restore')
+ (root / 'verified-headers.json').write_text(json.dumps({
+ 'global': global_text, 'columns_row': row_text(client, 1),
+ 'pane_tag': tag(client, right), 'dump': str(dump_path),
+ }, indent=2, ensure_ascii=False))
+
+ # Keep the tested Unicode and persistence evidence above. The published
+ # workspace uses useful command text, edited through the same real input
+ # route rather than modifying screenshots or injecting rendered cells.
+ clean_global = 'Newcol Help Changelog Tutor Dump NextColor Debug Kill'
+ keys.click(1, 0)
+ keys.send(b'\x1b[H\x1b[1;2F')
+ keys.send(clean_global)
+ require(wait_for(lambda: row_text(client, 0) == clean_global), 'clean global tag replacement failed')
+ keys.escape()
+ col_start, _ = require(locate(client, 'New Tty', row=1, minimum_col=75), 'right column tag missing after restore')
+ keys.click(col_start, 1)
+ keys.send(b'\x1b[H\x1b[1;2F')
+ keys.send('New Tty Find Grep Joincol Work')
+ require(wait_for(lambda: row_text(client, 1).endswith('New Tty Find Grep Joincol Work')),
+ 'clean column tag replacement failed')
+ keys.escape()
+ clean_pane = str(right_name) + ' Save Tty Del Collapse'
+ current_pane = tag(client, right)
+ require(current_pane.startswith(clean_pane), 'unexpected scratch tag before presentation cleanup')
+ suffix = current_pane[len(clean_pane):]
+ require(suffix.isascii(), 'presentation cleanup expects its own ASCII test suffix')
+ keys.click(*require(locate(client, 'Save Tty', minimum_col=75), 'scratch pane commands missing'))
+ keys.send(b'\x1b[F')
+ keys.send(b'\x7f' * len(suffix))
+ require(wait_for(lambda: tag(client, right) == clean_pane), 'clean pane command tail replacement failed')
+ keys.escape()
+ checks.append('presentation tags cleaned through actual input after preserving Unicode evidence')
+ for theme in ['orchard', 'atelier']:
+ command(client, source_serial, 'Theme ' + theme)
+ capture(client, root, 'columns-' + theme, not args.tty)
+ # The source path exceeds the left column's width. Moving its tag
+ # caret to End must reveal the actions without changing the filename.
+ source_tag = tag(client, source_serial)
+ keys.click(12, 2)
+ keys.send(b'\x1b[F')
+ require(wait_for(lambda: (point := locate(client, 'Save Tty Del', row=2))
+ and point[0] < 75), 'long-path tag did not reveal its command tail at End')
+ require(tag(client, source_serial) == source_tag, 'caret movement changed the source tag')
+ capture(client, root, 'columns-tag-reveal', not args.tty)
+ keys.escape()
+ checks.append('long-path pane tag reveals its command tail when the caret moves to End')
+ require(client.read(f'/self/pane/{source_serial}/body') == original == source.read_bytes(), 'Agave source changed')
+ checks.append('Agave source bytes unchanged')
+ for serial in panes(client):
+ if 'pty' in client.list(f'/self/pane/{serial}'):
+ client.write(f'/self/pane/{serial}/pty/data', b'exit\r')
+ report = {'checks': checks, 'cols': 150, 'rows': 48, 'host': 'tty' if args.tty else 'sdl',
+ 'input': 'keyboard and SGR mouse through the host PTY parser',
+ 'source': str(source), 'artifacts': str(root)}
+ (root / 'report.json').write_text(json.dumps(report, indent=2))
+ print(json.dumps(report, indent=2))
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('binary', type=Path)
+ parser.add_argument('output', type=Path)
+ parser.add_argument('--project', required=True, type=Path)
+ parser.add_argument('--tty', action='store_true')
+ run(parser.parse_args())
diff --git a/test/font_size.py b/test/font_size.py
new file mode 100644
index 00000000..e40b7b3a
--- /dev/null
+++ b/test/font_size.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+"""Check startup/runtime SDL Font name:size requests through an isolated 9P session."""
+import argparse
+from pathlib import Path
+
+from fs import execute, new_pane, session
+from ui_review import capture, panes, require, wait_for
+
+
+def run(args):
+ root = args.output.resolve()
+ root.mkdir(parents=True, mode=0o700, exist_ok=True)
+ root.chmod(0o700)
+ config = root / 'config/pardes'
+ config.mkdir(parents=True, exist_ok=True)
+ (config / 'init').write_text(f'Shell /bin/sh\nTheme orchard\nFont {args.font}:18\nTaglineSize 80\n')
+ name = 'font-size'
+ launch = ['-c', 'stty cols 150 rows 48; exec "$@"', name,
+ str(args.binary.resolve()), '--9p=' + name]
+ inherited = {'PARDES_TEST': '1', 'PARDES_TEST_CAPTURE_DIR': str(root),
+ 'PARDES_TEST_COLS': '150', 'PARDES_TEST_ROWS': '48',
+ 'SDL_VIDEODRIVER': 'x11'}
+ with session('/bin/sh', root, name, socket_name=name, tty=True,
+ launch=launch, inherited=inherited) as (client, _):
+ control = new_pane(client, b'')
+
+ def report(size):
+ execute(client, control, 'Config')
+ def ready():
+ for serial, tag in panes(client).items():
+ if '/+Config ' in tag:
+ body = client.read(f'/self/pane/{serial}/body').decode()
+ if f'Font effective size: {size:.2f} pixels' in body:
+ return body
+ return None
+ return require(wait_for(ready), f'Font did not become {size} pixels')
+
+ initial = report(18)
+ require('Font requested size: 18.00' in initial, 'startup size suffix ignored')
+ require(args.font in initial, 'requested font missing')
+ execute(client, control, f'Font {args.font}:20.5')
+ require('Font requested size: 20.50' in report(20.5), 'fractional size ignored')
+ execute(client, control, f'Font {args.font}')
+ report(20.5) # no suffix preserves current size
+ execute(client, control, f'Font {args.font}:900')
+ report(20.5) # invalid request cannot partially change the font
+ execute(client, control, 'Font DefinitelyMissingPardesFont:12')
+ report(20.5)
+ execute(client, control, f'Font {args.font}:18')
+ final = report(18)
+ (root / 'font-report.txt').write_text(final)
+ capture(client, root, 'font-size-18', True)
+ print('Font startup, fractional size, omitted size and invalid requests passed')
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('binary', type=Path)
+ parser.add_argument('output', type=Path)
+ parser.add_argument('--font', default='MartianMono-NrRg')
+ run(parser.parse_args())
diff --git a/test/fs.py b/test/fs.py
index 9fc5bcc6..85cf6855 100644
--- a/test/fs.py
+++ b/test/fs.py
@@ -17,7 +17,7 @@ from ninep import Client
@contextlib.contextmanager
def session(binary, root, name, *options, socket_name=None, file=None, tty=False, network=None,
- launch=None, inherited=None):
+ launch=None, inherited=None, terminal=None):
env = {key: value for key, value in os.environ.items()
if not key.startswith('PARDES_')}
env.update(HOME=str(root), XDG_RUNTIME_DIR=str(root),
@@ -47,6 +47,9 @@ def session(binary, root, name, *options, socket_name=None, file=None, tty=False
stdout=slave if tty else subprocess.DEVNULL,
stderr=subprocess.PIPE, start_new_session=True,
preexec_fn=preexec)
+ if terminal is not None:
+ # Borrowed handles for input-driving probes, valid inside this context.
+ terminal.update(pid=child.pid, input_fd=master)
if launch is not None and socket_name is None:
address = root / f'pardes-9p-{child.pid}.sock'
if slave is not None:
@@ -77,6 +80,8 @@ def session(binary, root, name, *options, socket_name=None, file=None, tty=False
assert set(network) == {'TCP', 'QUIC'}, network
yield client, address
finally:
+ if terminal is not None:
+ terminal.clear()
if child is not None:
if child.poll() is None:
child.terminate()
diff --git a/test/image_harness.zig b/test/image_harness.zig
index 1141d81f..474ec48b 100644
--- a/test/image_harness.zig
+++ b/test/image_harness.zig
@@ -22,7 +22,7 @@ extern "c" fn unsetenv(name: [*:0]const u8) c_int;
const gpa = std.heap.page_allocator;
const fixture_rgb = [3]u8{ 13, 77, 231 };
-// The harness isolates configuration, so fresh PDFs use the boot `helix`
+// The harness pins configuration, so fresh PDFs use the legacy `helix`
// theme (#080808 paper, #bdbdbd ink). These are the exact fixed-point
// filtered-tint results for the fixture's saturated red and green pages.
const pdf_filtered_red = [3]u8{ 255, 77, 77 };
@@ -50,6 +50,10 @@ pub fn main(init: std.process.Init) !void {
// native process under test; this nonexistent directory is test-owned.
const config_home = try std.fmt.allocPrintSentinel(arena, "{s}/.config", .{base}, 0);
_ = setenv("XDG_CONFIG_HOME", config_home, 1);
+ if (libc.mkdir(config_home, 0o755) != 0) return error.MkdirFailed;
+ const config_dir = try std.fmt.allocPrintSentinel(arena, "{s}/pardes", .{config_home}, 0);
+ if (libc.mkdir(config_dir, 0o755) != 0) return error.MkdirFailed;
+ try eh.writeFile(try std.fmt.allocPrintSentinel(arena, "{s}/init", .{config_dir}, 0), "Theme helix\n");
_ = setenv("HISTFILE", "/dev/null", 1);
_ = setenv("TERM", "xterm-256color", 1);
_ = setenv("LC_ALL", "C", 1);
@@ -68,6 +72,12 @@ pub fn main(init: std.process.Init) !void {
}
fn cleanupBase(arena: std.mem.Allocator, base: [:0]const u8) void {
+ const init_path = std.fmt.allocPrintSentinel(arena, "{s}/.config/pardes/init", .{base}, 0) catch return;
+ _ = libc.unlink(init_path);
+ const config_dir = std.fmt.allocPrintSentinel(arena, "{s}/.config/pardes", .{base}, 0) catch return;
+ _ = libc.rmdir(config_dir);
+ const config_home = std.fmt.allocPrintSentinel(arena, "{s}/.config", .{base}, 0) catch return;
+ _ = libc.rmdir(config_home);
const names = [_][]const u8{ "native.ppm", "pages.pdf", "latest.ppm", "latest.ppm.tmp", ".bash_history" };
for (names) |name| {
const path = std.fmt.allocPrintSentinel(arena, "{s}/{s}", .{ base, name }, 0) catch continue;
@@ -279,7 +289,8 @@ fn runKittyPdf(arena: std.mem.Allocator, exe: [:0]const u8, base: [:0]const u8)
try writePdf(arena, pdf_path, .red);
defer _ = libc.unlink(pdf_path);
- var h = try eh.Harness.initArgs(gpa, exe, 16, 40, pdf_path);
+ // Preserve fourteen document rows below workspace, column and pane tags.
+ var h = try eh.Harness.initArgs(gpa, exe, 17, 40, pdf_path);
defer h.deinit();
try h.expectRawWaitFor(
"\x1b_Gi=1,a=q\x1b\\",
@@ -292,15 +303,15 @@ fn runKittyPdf(arena: std.mem.Allocator, exe: [:0]const u8, base: [:0]const u8)
const first_deadline = eh.nowMs() + 5000;
while (eh.nowMs() < first_deadline) {
_ = try h.pumpOnce(50);
- const sent = std.mem.indexOf(u8, h.raw.items, transmit) != null;
+ const sent = std.mem.count(u8, h.raw.items, transmit) >= 2;
const placed = std.mem.indexOf(u8, h.raw.items, "\x1b_Ga=p,i=") != null;
- if (sent and placed and h.contains("pdf 1/4 width PdfFit filtered PdfTint")) break;
+ if (sent and placed and h.contains("[1/4]")) break;
}
try h.expectRawContains(transmit, "first PDF page was not transmitted as the 96x64 Kitty raster");
try h.expectRawContains("\x1b_Ga=p,i=", "first PDF page was not placed in the pane body");
try h.expectContains(
- "pdf 1/4 width PdfFit filtered PdfTint",
- "fresh PDF pane did not expose filtered tint as its default",
+ "[1/4]",
+ "fresh PDF pane did not show its compact page indicator",
);
// Fit-width is the initial PDF policy. The short fixture pages make the
@@ -334,7 +345,7 @@ fn runKittyPdf(arena: std.mem.Allocator, exe: [:0]const u8, base: [:0]const u8)
_ = try h.pumpOnce(50);
if (std.mem.count(u8, h.raw.items, transmit) != initial_transmits)
return error.KittyPdfPlacementScrollRetransmitted;
- try h.expectContains("pdf 1/4 width PdfFit", "one-row scroll snapped to another PDF page");
+ try h.expectContains("[1/4]", "one-row scroll snapped to another PDF page");
// The newly exposed page-two head is 29px tall and begins three pixels
// into a cell. Kitty infers an integer row count when only c is supplied;
@@ -364,7 +375,7 @@ fn runKittyPdf(arena: std.mem.Allocator, exe: [:0]const u8, base: [:0]const u8)
const transmits_before_step = std.mem.count(u8, h.raw.items, all_transmits);
const page_three_transmit = "\x1b_Gf=32,s=96,v=64,i=";
try h.send("\x06");
- try h.expectWaitFor("pdf 2/4 width PdfFit", 5000, "continuous page-down did not enter PDF page two");
+ try h.expectWaitFor("[2/4]", 5000, "continuous page-down did not enter PDF page two");
const page_step_deadline = eh.nowMs() + 5000;
while (eh.nowMs() < page_step_deadline and
std.mem.indexOf(u8, h.raw.items[page_step_start..], page_three_transmit) == null)
@@ -380,7 +391,7 @@ fn runKittyPdf(arena: std.mem.Allocator, exe: [:0]const u8, base: [:0]const u8)
// viewport, then submitting the bare search selects and Looks its first
// hit through the shared walk, creating a decorated page-two revision.
try h.send("\x02");
- try h.expectWaitFor("pdf 1/4 width PdfFit", 5000, "continuous page-up did not return to PDF page one");
+ try h.expectWaitFor("[1/4]", 5000, "continuous page-up did not return to PDF page one");
const transmits_before_search = std.mem.count(u8, h.raw.items, all_transmits);
try h.send("/SECOND\r");
const search_row = try std.fmt.allocPrint(arena, "{s}:2:1 SECOND", .{std.fs.path.basename(pdf_path)});
@@ -389,9 +400,9 @@ fn runKittyPdf(arena: std.mem.Allocator, exe: [:0]const u8, base: [:0]const u8)
while (eh.nowMs() < look_deadline) {
_ = try h.pumpOnce(50);
if (std.mem.count(u8, h.raw.items, all_transmits) > transmits_before_search and
- h.contains("pdf 2/4 width PdfFit")) break;
+ h.contains("[2/4]")) break;
}
- try h.expectContains("pdf 2/4 width PdfFit", "bare search did not reveal its first PDF hit at page two");
+ try h.expectContains("[2/4]", "bare search did not reveal its first PDF hit at page two");
if (std.mem.count(u8, h.raw.items, all_transmits) <= transmits_before_search)
return error.KittyPdfLookRetransmitMissing;
@@ -400,7 +411,7 @@ fn runKittyPdf(arena: std.mem.Allocator, exe: [:0]const u8, base: [:0]const u8)
const before_fit = std.mem.count(u8, h.raw.items, all_transmits);
const fit_raw_start = h.raw.items.len;
try h.send(" tz");
- try h.expectWaitFor("pdf 2/4 height PdfFit", 5000, "PdfFit did not expose height fit");
+ try h.expectWaitFor("[2/4]", 5000, "PdfFit did not expose height fit");
const fit_deadline = eh.nowMs() + 3000;
while (eh.nowMs() < fit_deadline and
kittyPlacementApcWithParam(h.raw.items, fit_raw_start, 'r') == null)
@@ -425,7 +436,7 @@ fn runKittyPdf(arena: std.mem.Allocator, exe: [:0]const u8, base: [:0]const u8)
const upper_start = h.raw.items.len;
try h.send("n\r");
- try h.expectWaitFor("pdf 1/4 height PdfFit", 5000, "first PdfSections n+Look did not reveal page one");
+ try h.expectWaitFor("[1/4]", 5000, "first PdfSections n+Look did not reveal page one");
const upper_deadline = eh.nowMs() + 3000;
while (eh.nowMs() < upper_deadline and kittyPlacementApc(h.raw.items, upper_start) == null)
_ = try h.pumpOnce(50);
@@ -437,7 +448,7 @@ fn runKittyPdf(arena: std.mem.Allocator, exe: [:0]const u8, base: [:0]const u8)
const lower_start = h.raw.items.len;
try h.send("n\r");
- try h.expectWaitFor("pdf 1/4 height PdfFit", 5000, "nested PdfSections n+Look left page one");
+ try h.expectWaitFor("[1/4]", 5000, "nested PdfSections n+Look left page one");
const lower_deadline = eh.nowMs() + 3000;
while (eh.nowMs() < lower_deadline and kittyPlacementApc(h.raw.items, lower_start) == null)
_ = try h.pumpOnce(50);
@@ -449,9 +460,9 @@ fn runKittyPdf(arena: std.mem.Allocator, exe: [:0]const u8, base: [:0]const u8)
return error.KittyPdfSectionsSamePageRetransmitted;
try h.send("n\r");
- try h.expectWaitFor("pdf 2/4 height PdfFit", 5000, "third PdfSections n+Look did not reveal page two");
+ try h.expectWaitFor("[2/4]", 5000, "third PdfSections n+Look did not reveal page two");
try h.send("N\r");
- try h.expectWaitFor("pdf 1/4 height PdfFit", 5000, "PdfSections N+Look did not return to the nested page-one row");
+ try h.expectWaitFor("[1/4]", 5000, "PdfSections N+Look did not return to the nested page-one row");
// Editor-style save: build a same-sized blue first page on another inode,
// atomically rename it over the live pathname, and send NO input. The
@@ -548,9 +559,11 @@ fn runGuiPdf(arena: std.mem.Allocator, exe: [:0]const u8, base: [:0]const u8) !v
_ = setenv("PARDES_TEST", "1", 1);
_ = setenv("PARDES_TEST_CAPTURE_DIR", base, 1);
_ = setenv("PARDES_TEST_COLS", "20", 1);
- _ = setenv("PARDES_TEST_ROWS", "10", 1);
+ // Keep eight document rows beneath the workspace, column and pane tags;
+ // the fit-height assertions below compare this viewport with width-fit.
+ _ = setenv("PARDES_TEST_ROWS", "11", 1);
- var h = try eh.Harness.initArgs(gpa, exe, 10, 20, pdf_path);
+ var h = try eh.Harness.initArgs(gpa, exe, 11, 20, pdf_path);
defer h.deinit();
const fit_width = try waitForCaptureBounds(&h, capture_path, pdf_filtered_red, 500, 5000);
const initial_green = try waitForCaptureBounds(&h, capture_path, pdf_filtered_green, 500, 5000);
diff --git a/test/look_placement.py b/test/look_placement.py
new file mode 100644
index 00000000..e9918c5d
--- /dev/null
+++ b/test/look_placement.py
@@ -0,0 +1,143 @@
+#!/usr/bin/env python3
+"""Check narrow-window first-document Look placement in owned SDL/TTY sessions.
+
+python3 -B test/look_placement.py zig-out/column-review/bin/pardes-gui
+python3 -B test/look_placement.py zig-out/column-review/bin/pardes --tty
+
+Starts the classic three-terminal layout, then opens the first document from
+the lower-left or right terminal. Screen-grid geometry must split only that
+terminal, immediately below it, and a repeated Look must reuse the file pane.
+Use --output DIR to retain grid observations and SDL GPU screenshots.
+"""
+import argparse
+from contextlib import nullcontext
+from pathlib import Path
+import tempfile
+
+from fs import session
+from ui_review import capture, panes, require, wait_for
+
+
+def geometry(client, markers):
+ frame = client.screen()
+ width = frame['cols']
+ lines = [''.join(cell[0] for cell in frame['cells'][row * width:(row + 1) * width])
+ for row in range(frame['rows'])]
+ positions = {}
+ for serial, marker in markers.items():
+ hits = [(row, line.index(marker)) for row, line in enumerate(lines) if marker in line]
+ if len(hits) != 1:
+ return None
+ row, offset = hits[0]
+ column_x = 0 if offset < width // 2 else width // 2
+ positions[serial] = (column_x, row)
+ rectangles = {}
+ for serial, (column_x, row) in positions.items():
+ following = [other_y for other_x, other_y in positions.values()
+ if other_x == column_x and other_y > row]
+ end = min(following, default=frame['rows'])
+ rectangles[serial] = (column_x, row, width // 2, end - row)
+ return frame, rectangles
+
+
+def rectangle_text(frame, rect):
+ x, y, width, height = rect
+ return tuple(tuple(cell[0] for cell in frame['cells'][row * frame['cols'] + x:
+ row * frame['cols'] + x + width])
+ for row in range(y, y + height))
+
+
+def run_case(args, root, source_index):
+ root.mkdir(parents=True, exist_ok=True, mode=0o700)
+ root.chmod(0o700)
+ config = root / 'config/pardes'
+ config.mkdir(parents=True)
+ (config / 'init').write_text('Shell /bin/sh\nTheme forge\n')
+ target = root / 'opened.txt'
+ contents = b'First document opened from this terminal.\n' * 40
+ target.write_bytes(contents)
+ name = 'look-placement'
+ inherited = {} if args.tty else {
+ 'PARDES_TEST': '1', 'PARDES_TEST_COLS': '150', 'PARDES_TEST_ROWS': '48',
+ 'PARDES_TEST_CAPTURE_DIR': str(root), 'SDL_VIDEODRIVER': 'x11',
+ }
+ # No document argument: the regression concerns the very first document.
+ launch = ['-c', 'stty cols 150 rows 48; exec "$@"', name,
+ str(args.binary.resolve()), '--9p=' + name, '-n', '3']
+ with session('/bin/sh', root, name, socket_name=name, tty=True,
+ launch=launch, inherited=inherited) as (client, _):
+ serials = list(panes(client))
+ require(len(serials) == 3, 'classic fixture did not boot three terminals')
+ markers = {}
+ for index, serial in enumerate(serials):
+ pane = f'/self/pane/{serial}'
+ require('pty' in client.list(pane), 'fixture contains an existing document')
+ marker = f'LP_{index}'
+ markers[serial] = marker
+ client.write(pane + '/ctl', b'cleartag\n')
+ client.write(pane + '/tag', f' {marker} Tty Del Collapse'.encode())
+ # Establish non-pristine shells and a stable prompt before measuring.
+ client.write(pane + '/pty/data', f"printf 'ready-{index}\\n'\r".encode())
+ require(wait_for(lambda: f'\nready-{index}\n'.encode() in
+ client.read(pane + '/body').replace(b'\r', b'')),
+ 'terminal did not execute readiness command')
+ before_frame, before = require(wait_for(lambda: geometry(client, markers)),
+ 'terminal tags not visible in fixture')
+ source = serials[source_index]
+ source_rect = before[source]
+ require(source_rect[3] >= 8, 'source terminal too short for a local split')
+ require(before[serials[0]][:2] == (0, 2) and before[serials[1]][0] == 0 and
+ before[serials[1]][1] > 2 and before[serials[2]][:2] == (75, 2),
+ f'unexpected initial classic layout: {before}')
+ client.write(f'/self/pane/{source}/ctl', f'look {target}\n'.encode())
+ opened = require(wait_for(lambda: next((serial for serial in panes(client)
+ if serial not in serials), None)),
+ 'Look did not open the first document')
+ markers[opened] = 'opened.txt'
+ after_frame, after = require(wait_for(lambda: geometry(client, markers)),
+ 'Look pane tags not visible')
+ require(len(panes(client)) == 4, 'Look removed a terminal or added extra panes')
+ x, y, width, height = source_rect
+ require(after[source][:3] == (x, y, width),
+ f'Look moved its originating terminal: {source_rect} -> {after[source]}')
+ require(after[opened][:3] == (x, y + after[source][3], width) and
+ after[source][3] + after[opened][3] == height,
+ f'Look did not split directly below its caller: {after}')
+ for serial in serials:
+ if serial == source:
+ continue
+ require(after[serial] == before[serial],
+ f'Look resized or moved unrelated terminal {serial}: {before} -> {after}')
+ require(rectangle_text(before_frame, before[serial]) ==
+ rectangle_text(after_frame, after[serial]),
+ f'Look changed unrelated terminal {serial} rendered text')
+ require(client.read(f'/self/pane/{opened}/body') == contents,
+ 'opened document contents differ')
+ client.write(f'/self/pane/{source}/ctl', f'look {target}:2\n'.encode())
+ require(list(panes(client)) == serials + [opened], 'repeated Look created a duplicate pane')
+ require(wait_for(lambda: geometry(client, markers)[1] == after),
+ 'repeated Look changed layout')
+ require(target.read_bytes() == contents, 'Look modified the fixture on disk')
+ if args.output:
+ capture(client, root, 'look-below-caller', not args.tty)
+ print(f'{"TTY" if args.tty else "SDL"} source {"lower-left" if source_index == 1 else "right"}: '
+ 'local split, unchanged other terminals, first-file contents and re-Look reuse passed', flush=True)
+
+
+def run(args):
+ # Cache-rooted fixtures avoid relying on /tmp quota in developer sessions.
+ cache = Path.home() / '.cache'
+ cache.mkdir(exist_ok=True)
+ context = nullcontext(str(args.output.resolve())) if args.output else tempfile.TemporaryDirectory(
+ prefix='lp-', dir=cache)
+ with context as directory:
+ for source_index, label in [(1, 'left'), (2, 'right')]:
+ run_case(args, Path(directory) / label, source_index)
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('binary', type=Path)
+ parser.add_argument('--tty', action='store_true')
+ parser.add_argument('--output', type=Path)
+ run(parser.parse_args())
diff --git a/test/macos-snapshots/boot.snap b/test/macos-snapshots/boot.snap
index 9adcf95c..c62fa2bd 100644
--- a/test/macos-snapshots/boot.snap
+++ b/test/macos-snapshots/boot.snap
@@ -9,7 +9,7 @@
# prompt visible. `$ ` is the prompt the hermetic .bashrc pins, and no chrome
# row carries a `$`, so waiting on one is waiting on the shell.
start 24 80
-wait 8000 New Newcol
+wait 8000 Newcol Joincol
wait 8000 $
stable 700 20000
snap boot
diff --git a/test/macos-snapshots/keys.snap b/test/macos-snapshots/keys.snap
index b81b88b7..d4c6e0fb 100644
--- a/test/macos-snapshots/keys.snap
+++ b/test/macos-snapshots/keys.snap
@@ -3,7 +3,7 @@
# are split with '' so the echoed command line can never be the thing a `wait`
# matched — the output has to be what arrived.
start 24 80
-wait 8000 New Newcol
+wait 8000 Newcol Joincol
wait 8000 $
stable 700 20000
# raw tty mode: characters and Enter travel to the shell through the pty
diff --git a/test/macos-snapshots/rotate.snap b/test/macos-snapshots/rotate.snap
index 1f2e4667..8ade842b 100644
--- a/test/macos-snapshots/rotate.snap
+++ b/test/macos-snapshots/rotate.snap
@@ -9,7 +9,7 @@
# remainder is banked, which makes the pairs below exact rather than
# approximate: -12 spends one notch and banks -2.
start 30 100
-wait 8000 New Newcol
+wait 8000 Newcol Joincol
wait 8000 $
stable 700 20000
# Twenty-four hits, not three. A coast is worth asserting only on a list long
diff --git a/test/macos-snapshots/trackpad.snap b/test/macos-snapshots/trackpad.snap
index df843e5d..474dcda0 100644
--- a/test/macos-snapshots/trackpad.snap
+++ b/test/macos-snapshots/trackpad.snap
@@ -11,7 +11,7 @@
# Coordinates are 0-based cells, which is what pardes_mouse takes. The tty
# suite's press/release are 1-based SGR and so read one higher.
start 30 100
-wait 8000 New Newcol
+wait 8000 Newcol Joincol
wait 8000 $
stable 700 20000
# something to look at; split so the echoed command line is not the match
@@ -70,9 +70,9 @@ snap scrolled
wheel wheeldown 4 5
stable 700 10000
snap notched
-# TWO FINGERS = button 2 = Exec. `New` in the top tag is a builtin, so this
+# TWO FINGERS = button 2 = Exec. `New` in the column tag is a builtin, so this
# spawns a pane rather than running something the machine would have to own.
-fingers 2 1 0
+fingers 2 3 1
stable 700 20000
haptic exec
snap exec
@@ -80,7 +80,7 @@ snap exec
# exists for: macOS delivers them on the right stream exactly like two, so a
# view that trusted the stream would Look here. `Newcol` proves this one went
# somewhere different from the click above.
-fingers 3 5 0
+fingers 3 1 0
stable 700 20000
haptic exec
snap exec3
diff --git a/test/output.zig b/test/output.zig
index 577b8e73..fd4252e1 100644
--- a/test/output.zig
+++ b/test/output.zig
@@ -11,6 +11,49 @@ const platform = pardes.platform;
const font_picker = pardes.font_picker;
const fonts = if (font_picker) pardes.fonts else struct {};
+test "search tint survives wrapping and theme changes while selections remain authoritative" {
+ const text = "nested/path/a.txt:1:5-7 let abc = 1;\n";
+ for ([_]u16{ 30, 80 }) |width| {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = width, .rows = 12 });
+ defer p.deinit();
+ const pane = try p.setTestFile(text);
+ pane.file.?.output = .{ .from = .search };
+ var frame = std.heap.ArenaAllocator.init(std.testing.allocator);
+ defer frame.deinit();
+ for ([_]bool{ false, true }) |bottom| {
+ p.settings.tag_bottom = bottom;
+ for ([_]bool{ true, false, true }) |colors| {
+ p.settings.colors = colors;
+ const surface = try p.render(frame.allocator());
+ var marked: usize = 0;
+ for (surface.cells) |cell| {
+ if (std.meta.eql(cell.style.bg, pardes.Color{ .rgb = p.theme().search_bg.? })) marked += 1;
+ }
+ try std.testing.expectEqual(@as(usize, if (colors) 3 else 0), marked);
+ _ = frame.reset(.retain_capacity);
+ }
+ }
+ // The body changes immediately even when dark chrome is still fading.
+ try std.testing.expect(p.executeBuiltinLine(0, "Theme daybreak"));
+ const light = try p.render(frame.allocator());
+ var light_matches: usize = 0;
+ for (light.cells) |cell| {
+ if (!std.meta.eql(cell.style.bg, pardes.Color{ .rgb = p.theme().search_bg.? })) continue;
+ try std.testing.expectEqualDeep(pardes.Color{ .rgb = p.theme().search_fg.? }, cell.style.fg);
+ light_matches += 1;
+ }
+ try std.testing.expectEqual(@as(usize, 3), light_matches);
+ pane.mode = .normal;
+ pane.cur_row = 0;
+ pane.cur_col = @intCast(std.mem.indexOf(u8, text, "abc").? + 2);
+ pane.vsel = .{ .active = true, .row = 0, .col = pane.cur_col - 2, .explicit = true };
+ const selected = try p.render(frame.allocator());
+ for (selected.cells) |cell|
+ try std.testing.expect(!std.meta.eql(cell.style.bg, pardes.Color{ .rgb = p.theme().search_bg.? }));
+ try std.testing.expectEqualStrings(text, pane.file.?.content);
+ }
+}
+
test "location results sort filenames and numeric positions while remapping their anchor" {
const before = "z.zig:1:1 z\nb.zig:10:2-3 ten\nb.zig:2:10-12 two-b\nb.zig:2:2-3 two-a\na.zig:99:1 a\nb.zig:2:2-3 duplicate\n";
const after = "a.zig:99:1 a\nb.zig:2:2-3 two-a\nb.zig:2:2-3 duplicate\nb.zig:2:10-12 two-b\nb.zig:10:2-3 ten\nz.zig:1:1 z\n";
@@ -326,6 +369,8 @@ test "Mini syntax colors survive toggles themes and rendering without source acc
const id = p.active;
const mini = p.panes[id].?;
const keyword = std.mem.indexOfScalar(u8, mini.file.?.mini.?.colors, @intFromEnum(pardes.syntax.Syn.keyword)) orelse return error.MissingKeywordColor;
+ // Direct pane construction bypasses the host update's layout sync.
+ p.update(.{ .resize = .{ .cols = 80, .rows = 24 } });
const position = modal.positionAt(mini.file.?.content, keyword);
const column = panes.File.displayWidth(modal.lineSlice(mini.file.?.content, position.row)[0..position.col]);
try tmp.dir.deleteFile(std.testing.io, "demo.zig");
@@ -391,7 +436,7 @@ test "Config prints the startup path and refreshes its one output" {
const out = p.panes[opened].?.file.?;
for ([_][]const u8{
"Startup config: " ++ path ++ "\n",
- "Theme: helix\n",
+ "Theme: orchard\n",
"Shell requested (new panes): " ++ config.default_shell ++ " (default)\n",
"Shell effective (last spawn): (none)\n",
"Shell pending: on\n",
@@ -691,6 +736,44 @@ test "N exactly reverses n across output panes and the ring seam" {
try std.testing.expect(saw_first and saw_second);
}
+test "ThemeSel groups native themes first and skips headings in both directions" {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 100, .rows = 40 });
+ defer p.deinit();
+ const source = try p.setTestFile("notes\n");
+ p.setThemeIndex(pardes.themes.len - 1);
+ const original_theme = p.settings.theme;
+ try std.testing.expect(p.executeBuiltinLine(0, "ThemeSel"));
+ const tid = source.search_pane orelse return error.MissingThemeList;
+ const list = p.panes[tid].?;
+ const content = list.file.?.content;
+ try std.testing.expectEqual(@as(usize, 0), p.active);
+ try std.testing.expectEqual(@as(i32, 0), list.cur_row);
+ try std.testing.expectEqual(@as(usize, 0), list.file.?.scroll);
+ try std.testing.expectEqualStrings("# Pardes themes", modal.lineSlice(content, 0));
+ try std.testing.expectEqualStrings("# Legacy and imported themes", modal.lineSlice(content, pardes.native_theme_count + 2));
+ try std.testing.expectEqual(@as(usize, pardes.themes.len + 3), std.mem.count(u8, content, "\n"));
+ for (pardes.themes, 0..) |theme, i| {
+ const row = i + 1 + @as(usize, if (i >= pardes.native_theme_count) 2 else 0);
+ const line = modal.lineSlice(content, row);
+ try std.testing.expect(std.mem.startsWith(u8, line, "Theme "));
+ try std.testing.expectEqualStrings(theme.name, line["Theme ".len..]);
+ }
+ // Opening an imported theme's selector must still begin with the natives.
+ // Walk across the section break without selecting or executing a heading.
+ for (pardes.themes[0 .. pardes.native_theme_count + 1]) |theme| {
+ p.update(.{ .key = .{ .cp = 'n' } });
+ try std.testing.expectEqual(tid, p.active);
+ const selected = selectedOutputText(list) orelse return error.MissingThemeSelection;
+ try std.testing.expectEqualStrings(theme.name, selected["Theme ".len..]);
+ try std.testing.expectEqual(original_theme, p.settings.theme);
+ }
+ p.update(.{ .key = .{ .cp = 'N' } });
+ const previous = selectedOutputText(list) orelse return error.MissingThemeSelection;
+ try std.testing.expectEqualStrings(pardes.themes[pardes.native_theme_count - 1].name, previous["Theme ".len..]);
+ p.update(.{ .key = .{ .cp = Key.tab } });
+ try std.testing.expectEqual(pardes.native_theme_count - 1, p.settings.theme);
+}
+
test "n/N selects command outputs by whole row" {
if (platform == .web) return;
var cwd_buf: [4096]u8 = undefined;
@@ -705,7 +788,7 @@ test "n/N selects command outputs by whole row" {
const themes = p.panes[tid].?;
try std.testing.expect(panes.Output.fileTraits(themes.file.?.output).commands);
p.update(.{ .key = .{ .cp = 'n' } });
- const row0 = std.mem.trimEnd(u8, modal.lineSlice(themes.file.?.content, 0), " \t\r");
+ const row0 = std.mem.trimEnd(u8, modal.lineSlice(themes.file.?.content, 1), " \t\r");
try std.testing.expectEqualStrings(row0, selectedOutputText(themes) orelse "");
const theme_before = p.settings.theme;
p.update(.{ .key = .{ .cp = 'n' } });
diff --git a/test/panes.zig b/test/panes.zig
index 7d7a9ab7..2d57ecd8 100644
--- a/test/panes.zig
+++ b/test/panes.zig
@@ -12,6 +12,185 @@ const image = pardes.image;
const syntax = pardes.syntax;
const filesystem = pardes.filesystem;
+test "pane filename edits stage commit and cancel without changing body or command tail" {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 70, .rows = 12 });
+ defer p.deinit();
+ const pane = try p.setTestFile("original body\n");
+ const original = try p.gpa.dupe(u8, pane.file.?.path);
+ defer p.gpa.free(original);
+ p.seedTail(pane);
+ try std.testing.expect(pane.appendTag(" SyntaxBold"));
+ const tail = try p.gpa.dupe(u8, pane.tagSlice());
+ defer p.gpa.free(tail);
+ for ([_]bool{ false, true }) |commit| {
+ p.update(.{ .key = .{ .cp = ':' } });
+ p.update(.{ .key = .{ .cp = 'i' } });
+ pane.tag_anchor = 0;
+ pane.tag_col = @intCast(original.len - 1);
+ pane.tag_sel = true;
+ p.update(.{ .paste = "/new name.zig" });
+ try std.testing.expectEqualStrings(original, pane.file.?.path);
+ try std.testing.expectEqualStrings("/new name.zig", pane.tag_name[0..pane.tag_name_len.?]);
+ try std.testing.expectEqualStrings(tail, pane.tagSlice());
+ try std.testing.expectEqualStrings("original body\n", pane.file.?.content);
+ p.update(.{ .key = .{ .cp = if (commit) Key.enter else Key.escape } });
+ try std.testing.expect(!pane.tag_edit);
+ try std.testing.expect(pane.tag_name_len == null);
+ try std.testing.expectEqualStrings(if (commit) "/new name.zig" else original, pane.file.?.path);
+ try std.testing.expectEqualStrings(tail, pane.tagSlice());
+ while (p.nextEffect()) |effect| try std.testing.expect(std.meta.activeTag(effect) != .save_file);
+ }
+ try std.testing.expect(pane.file.?.revision != pane.file.?.saved_revision);
+}
+
+test "pane filename grapheme edits and invalid empty commits preserve the buffer" {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true });
+ defer p.deinit();
+ const pane = try p.setTestFile("untouched\n");
+ p.update(.{ .key = .{ .cp = ':' } });
+ p.update(.{ .key = .{ .cp = 'i' } });
+ pane.tag_anchor = 0;
+ pane.tag_col = @intCast(pane.file.?.path.len - 1);
+ pane.tag_sel = true;
+ p.update(.{ .paste = "/café界" });
+ p.update(.{ .key = .{ .cp = Key.backspace } });
+ try std.testing.expectEqualStrings("/café", pane.tag_name[0..pane.tag_name_len.?]);
+ p.update(.{ .key = .{ .cp = Key.backspace } });
+ try std.testing.expectEqualStrings("/caf", pane.tag_name[0..pane.tag_name_len.?]);
+ pane.tag_anchor = 0;
+ pane.tag_col = 3;
+ pane.tag_sel = true;
+ p.update(.{ .key = .{ .cp = Key.delete } });
+ try std.testing.expectEqual(@as(u16, 0), pane.tag_name_len.?);
+ p.update(.{ .key = .{ .cp = Key.enter } });
+ try std.testing.expect(pane.tag_edit);
+ try std.testing.expectEqualStrings("/test.txt", pane.file.?.path);
+ try std.testing.expectEqualStrings("untouched\n", pane.file.?.content);
+ p.update(.{ .key = .{ .cp = Key.escape } });
+ try std.testing.expect(pane.tag_name_len == null);
+}
+
+test "leaving a pane or entering a header cancels an uncommitted filename" {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true });
+ defer p.deinit();
+ const pane = try p.setTestFile("untouched\n");
+ for ([_]bool{ false, true }) |header| {
+ p.active = 0;
+ p.topbar_col = null;
+ p.update(.{ .key = .{ .cp = ':' } });
+ p.update(.{ .key = .{ .cp = 'i' } });
+ p.update(.{ .key = .{ .cp = Key.home } });
+ p.update(.{ .paste = "/draft" });
+ try std.testing.expect(pane.tag_name_len != null);
+ if (header) {
+ p.topbar_col = 0;
+ p.update(.tick);
+ } else {
+ try std.testing.expect(p.executeBuiltinLine(0, "New"));
+ p.update(.tick);
+ }
+ try std.testing.expect(pane.tag_name_len == null);
+ try std.testing.expect(!pane.tag_edit);
+ try std.testing.expectEqualStrings("/test.txt", pane.file.?.path);
+ }
+}
+
+test "middle clicking Save commits the staged filename before issuing a save" {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 70, .rows = 12 });
+ defer p.deinit();
+ const pane = try p.setTestFile("untouched\n");
+ p.update(.{ .key = .{ .cp = ':' } });
+ p.update(.{ .key = .{ .cp = 'i' } });
+ pane.tag_anchor = 0;
+ pane.tag_col = @intCast(pane.file.?.path.len - 1);
+ pane.tag_sel = true;
+ p.update(.{ .paste = "/renamed.txt" });
+ var arena = std.heap.ArenaAllocator.init(p.gpa);
+ defer arena.deinit();
+ _ = try p.render(arena.allocator());
+ const text = try p.tagText(arena.allocator(), pane);
+ const save_at = std.mem.indexOf(u8, text, "Save").?;
+ const x: u16 = @intCast(p.rects[0].x + config.GUTTER + save_at - pane.tag_scroll);
+ const y = p.rects[0].y;
+ while (p.nextEffect()) |_| {}
+ p.update(.{ .mouse = .{ .col = x, .row = y, .button = config.exec_button, .kind = .press } });
+ p.update(.{ .mouse = .{ .col = x, .row = y, .button = config.exec_button, .kind = .release } });
+ try std.testing.expectEqualStrings("/renamed.txt", pane.file.?.path);
+ try std.testing.expect(pane.tag_name_len == null);
+ try std.testing.expectEqualStrings("untouched\n", pane.file.?.content);
+ var saves: usize = 0;
+ while (p.nextEffect()) |effect| if (effect == .save_file) {
+ try std.testing.expectEqual(@as(u8, 0), effect.save_file.pane);
+ saves += 1;
+ };
+ try std.testing.expectEqual(@as(usize, 1), saves);
+}
+
+test "oversized filename paste refuses atomically across a selected tag boundary" {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true });
+ defer p.deinit();
+ const pane = try p.setTestFile("untouched\n");
+ p.update(.{ .key = .{ .cp = ':' } });
+ p.update(.{ .key = .{ .cp = 'i' } });
+ const before = try p.tagText(p.gpa, pane);
+ defer p.gpa.free(before);
+ pane.tag_anchor = 0;
+ pane.tag_col = @intCast(before.len - 1);
+ pane.tag_sel = true;
+ const excess = try p.gpa.alloc(u8, pane.tag_name.len + 1);
+ defer p.gpa.free(excess);
+ @memset(excess, 'x');
+ p.update(.{ .paste = excess });
+ try std.testing.expect(pane.tag_name_len == null);
+ try std.testing.expect(pane.tag_sel);
+ try std.testing.expectEqualStrings(before, try p.tagText(p.scratch.allocator(), pane));
+ try std.testing.expectEqualStrings("untouched\n", pane.file.?.content);
+}
+
+test "paste into pane commands and prompts never inserts into the body" {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true });
+ defer p.deinit();
+ const pane = try p.setTestFile("one two one\n");
+ p.update(.{ .key = .{ .cp = ':' } });
+ p.update(.{ .key = .{ .cp = 'A' } });
+ p.update(.{ .paste = " Custom\r\nCommand" });
+ try std.testing.expect(std.mem.endsWith(u8, pane.tagSlice(), " CustomCommand"));
+ p.update(.{ .key = .{ .cp = Key.escape } });
+ p.startPrompt(pane, .{ .search = config.search_marker });
+ p.update(.{ .paste = "two" });
+ try std.testing.expect(std.mem.endsWith(u8, pane.tagSlice(), "two"));
+ try std.testing.expectEqualStrings("one two one\n", pane.file.?.content);
+ p.update(.{ .key = .{ .cp = Key.escape } });
+ try std.testing.expect(std.mem.endsWith(u8, pane.tagSlice(), " CustomCommand"));
+}
+
+test "long pane tags reveal commands and map visible clicks to whole tag addresses" {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 50, .rows = 12 });
+ defer p.deinit();
+ const pane = try p.setTestFile("body\n");
+ p.gpa.free(pane.file.?.path);
+ pane.file.?.path = try p.gpa.dupe(u8, "/an/especially/deep/project/path/with/a/long/component/filename.zig");
+ p.seedTail(pane);
+ try std.testing.expect(pane.appendTag(" SyntaxBold"));
+ p.update(.{ .key = .{ .cp = ':' } });
+ p.update(.{ .key = .{ .cp = 'A' } });
+ var arena = std.heap.ArenaAllocator.init(p.gpa);
+ defer arena.deinit();
+ const surface = try p.render(arena.allocator());
+ try std.testing.expect(pane.tag_scroll > 0);
+ try std.testing.expect(surface.cursor.?.x < p.rects[0].x + p.rects[0].w);
+ const text = try p.tagText(p.gpa, pane);
+ defer p.gpa.free(text);
+ const offset = std.mem.indexOf(u8, text, "SyntaxBold").?;
+ const x: u16 = @intCast(p.rects[0].x + config.GUTTER + panes.File.rawDisplayCol(text, offset) - pane.tag_scroll);
+ const y = p.rects[0].y;
+ const before = p.settings.syntax_bold;
+ p.update(.{ .mouse = .{ .col = x, .row = y, .button = config.exec_button, .kind = .press } });
+ p.update(.{ .mouse = .{ .col = x, .row = y, .button = config.exec_button, .kind = .release } });
+ try std.testing.expectEqual(!before, p.settings.syntax_bold);
+ try std.testing.expectEqualStrings(text, try p.tagText(p.scratch.allocator(), pane));
+}
+
test "terminal overlay recoloring never materializes unrelated history" {
const testing = std.testing;
const p = try Pardes.init(testing.allocator, .{ .tty_only = true, .cols = 32, .rows = 8 });
@@ -37,7 +216,7 @@ test "terminal overlay recoloring never materializes unrelated history" {
const body_y = if (p.settings.tag_bottom) rect.y else rect.y + pardes.BOX_H;
const cell = surface.at(rect.x + config.GUTTER, body_y);
try testing.expectEqualStrings("c", cell.grapheme());
- try testing.expectEqual(pardes.Color{ .index = 2 }, cell.style.fg);
+ try testing.expectEqual(pardes.Color{ .rgb = p.theme().palette.?[2] }, cell.style.fg);
}
test "terminal output keeps following new rows after scrollback eviction" {
@@ -86,7 +265,7 @@ test "terminal output keeps following new rows after scrollback eviction" {
for (last, 0..) |byte, col| {
const cell = surface.at(x + @as(u16, @intCast(col)), y);
try std.testing.expectEqualStrings(&.{byte}, cell.grapheme());
- try std.testing.expectEqual(pardes.Color{ .index = 2 }, cell.style.fg);
+ try std.testing.expectEqual(pardes.Color{ .rgb = p.theme().palette.?[2] }, cell.style.fg);
}
while (p.nextEffect()) |_| {}
p.update(.{ .key = .{ .cp = 'f', .text = "f" } });
@@ -1163,6 +1342,13 @@ const PdfTests = struct {
if (!enabled) try std.testing.expectEqual(@as(usize, 0), @sizeOf(State));
}
+ test "compact PDF saved prefix separates page status from editable commands" {
+ const path = "/tmp/a document.pdf";
+ try std.testing.expectEqualStrings(path ++ " [2/9]", legacySavedPrefix(path, path ++ " [2/9] Keep Del").?);
+ try std.testing.expect(legacySavedPrefix(path, path ++ " [oops] Keep Del") == null);
+ try std.testing.expect(legacySavedPrefix(path, path ++ " [2/9/4] Keep Del") == null);
+ }
+
test "PDF section rows preserve DFS ordinals and sanitise hierarchy" {
if (!enabled) return;
const entries = [_]pdf.OutlineEntry{
@@ -1296,6 +1482,9 @@ const PdfTests = struct {
};
const TerminalTests = struct {
+ // Tests asserting raw ANSI indices explicitly select helix, whose palette
+ // is inherited. Native-palette coverage lives in the overlay/eviction and
+ // trailing-blank tests and checks their concrete RGB values instead.
const gridOffset = panes.Terminal.gridOffset;
const scrollGrid = panes.Terminal.scrollGrid;
const promptInputReady = panes.Terminal.promptInputReady;
@@ -1536,7 +1725,7 @@ const TerminalTests = struct {
test "an edit buffer slides shell rows and their colors together" {
const testing = std.testing;
- const p = try Pardes.init(testing.allocator, .{ .tty_only = true, .cols = 18, .rows = 12 });
+ const p = try Pardes.init(testing.allocator, .{ .startup_config = "Theme helix\n", .tty_only = true, .cols = 18, .rows = 12 });
defer p.deinit();
while (p.nextEffect()) |_| {}
const pane = p.panes[0].?;
@@ -1586,7 +1775,7 @@ const TerminalTests = struct {
test "a combining mark in the prompt keeps the command and its colors aligned" {
const testing = std.testing;
- const p = try Pardes.init(testing.allocator, .{ .tty_only = true, .cols = 18, .rows = 6 });
+ const p = try Pardes.init(testing.allocator, .{ .startup_config = "Theme helix\n", .tty_only = true, .cols = 18, .rows = 6 });
defer p.deinit();
while (p.nextEffect()) |_| {}
const pane = p.panes[0].?;
@@ -1620,7 +1809,7 @@ const TerminalTests = struct {
test "colors are never taken from shell rows below the viewport" {
const testing = std.testing;
- const p = try Pardes.init(testing.allocator, .{ .tty_only = true, .cols = 18, .rows = 14 });
+ const p = try Pardes.init(testing.allocator, .{ .startup_config = "Theme helix\n", .tty_only = true, .cols = 18, .rows = 14 });
defer p.deinit();
while (p.nextEffect()) |_| {}
const pane = p.panes[0].?;
@@ -1678,7 +1867,7 @@ const TerminalTests = struct {
test "a row the edit buffer only swallowed keeps its color" {
const testing = std.testing;
- const p = try Pardes.init(testing.allocator, .{ .tty_only = true, .cols = 18, .rows = 12 });
+ const p = try Pardes.init(testing.allocator, .{ .startup_config = "Theme helix\n", .tty_only = true, .cols = 18, .rows = 12 });
defer p.deinit();
while (p.nextEffect()) |_| {}
const pane = p.panes[0].?;
@@ -1715,7 +1904,7 @@ const TerminalTests = struct {
test "an edit buffer reaching past the dumped rows colors nothing from row zero" {
const testing = std.testing;
- const p = try Pardes.init(testing.allocator, .{ .tty_only = true, .cols = 18, .rows = 12 });
+ const p = try Pardes.init(testing.allocator, .{ .startup_config = "Theme helix\n", .tty_only = true, .cols = 18, .rows = 12 });
defer p.deinit();
while (p.nextEffect()) |_| {}
const pane = p.panes[0].?;
@@ -1791,7 +1980,7 @@ const TerminalTests = struct {
};
for (prompts) |prompt| {
for ([_]bool{ false, true }) |filter| {
- const p = try Pardes.init(testing.allocator, .{ .tty_only = true, .cols = 24, .rows = 6 });
+ const p = try Pardes.init(testing.allocator, .{ .startup_config = "Theme helix\n", .tty_only = true, .cols = 24, .rows = 6 });
defer p.deinit();
while (p.nextEffect()) |_| {}
const pane = p.panes[0].?;
@@ -1972,7 +2161,7 @@ const TerminalTests = struct {
// background, and wraps the glyph to the next row. A head OWNS its column,
// so skipping it the way a tail is skipped left the row's final column bare.
for ([_]pardes.Pane.Mode{ .tty, .normal }) |mode| {
- const p = try Pardes.init(testing.allocator, .{ .tty_only = true, .cols = 16, .rows = 8 });
+ const p = try Pardes.init(testing.allocator, .{ .startup_config = "Theme helix\n", .tty_only = true, .cols = 16, .rows = 8 });
defer p.deinit();
while (p.nextEffect()) |_| {}
const pane = p.panes[0].?;
@@ -2123,7 +2312,7 @@ const TerminalTests = struct {
test "an emptied edit buffer does not shift the colors below it" {
const testing = std.testing;
- const p = try Pardes.init(testing.allocator, .{ .tty_only = true, .cols = 18, .rows = 12 });
+ const p = try Pardes.init(testing.allocator, .{ .startup_config = "Theme helix\n", .tty_only = true, .cols = 18, .rows = 12 });
defer p.deinit();
while (p.nextEffect()) |_| {}
const pane = p.panes[0].?;
@@ -2157,7 +2346,7 @@ const TerminalTests = struct {
test "an edit overlay never changes tty-mode ansi colors" {
const testing = std.testing;
- const p = try Pardes.init(testing.allocator, .{ .tty_only = true, .cols = 18, .rows = 6 });
+ const p = try Pardes.init(testing.allocator, .{ .startup_config = "Theme helix\n", .tty_only = true, .cols = 18, .rows = 6 });
defer p.deinit();
while (p.nextEffect()) |_| {}
const pane = p.panes[0].?;
@@ -2583,7 +2772,7 @@ test "Colors restores syntax after rendering disabled files and disabled edits"
seen += 1;
for ([_]*pardes.Cell{ first, second }) |cell| {
try std.testing.expectEqual(pardes.Color{ .rgb = p.theme().kw }, cell.style.fg);
- try std.testing.expect(cell.style.bold);
+ try std.testing.expect(!cell.style.bold);
}
}
try std.testing.expectEqual(@as(usize, 2), seen);
@@ -2599,6 +2788,8 @@ test "growing a file pane colors every newly visible Zig keyword" {
const file = &pane.file.?;
gpa.free(file.path);
file.path = try gpa.dupe(u8, "/resize.zig");
+ p.update(.{ .command = "SyntaxBold" });
+ try std.testing.expect(p.settings.syntax_bold);
p.settings.colors = true;
p.presentation.enabled = false;
var frame = std.heap.ArenaAllocator.init(gpa);
@@ -2689,7 +2880,7 @@ test "Zig keywords keep every rendered byte colored across line-number widths" {
.{ line, view.wrap, view.horizontal, sample, cell.grapheme() },
);
try std.testing.expectEqual(expected, cell.style.fg);
- try std.testing.expect(cell.style.bold);
+ try std.testing.expect(!cell.style.bold);
}
}
}
@@ -2720,7 +2911,8 @@ test "terminal overlays preserve trailing blank styles without coloring inserted
const rect = p.rects[0];
const x = rect.x + config.GUTTER;
const y = if (p.settings.tag_bottom) rect.y else rect.y + pardes.BOX_H;
- const colors = [_]pardes.Color{ .{ .index = 1 }, .{ .index = 2 }, .{ .index = 4 } };
+ const palette = p.theme().palette.?;
+ const colors = [_]pardes.Color{ .{ .rgb = palette[1] }, .{ .rgb = palette[2] }, .{ .rgb = palette[4] } };
const original = try p.render(frame.allocator());
for (colors, 0..) |color, row| {
const cell = original.at(x, y + 1 + @as(u16, @intCast(row)));
diff --git a/test/pdf.zig b/test/pdf.zig
index b2d03bb8..a5720f3f 100644
--- a/test/pdf.zig
+++ b/test/pdf.zig
@@ -25,7 +25,7 @@ const pdf_raster_policy = pardes.pdf_raster_policy;
const PDF_PAGE_GAP_PX = pardes.PDF_PAGE_GAP_PX;
const BOX_H = pardes.BOX_H;
const sel_slot = @intFromEnum(config.select_button);
-const pane_tail = " " ++ config.pane_builtins_str;
+const pane_tail = " " ++ config.pdf_pane_builtins_str;
fn hasPdf(pane: *const pardes.Pane) bool {
return if (comptime pdf_enabled) pane.pdf != null else false;
@@ -445,10 +445,8 @@ test "MuPDF pane renders, navigates, searches, and round-trips its page" {
try std.testing.expectEqual(@as(u16, 8), p.cell_pixels.w);
try std.testing.expectEqual(@as(u16, 16), p.cell_pixels.h);
const initial_tag = try pardes.test_api.tagText(p, p.scratch.allocator(), pane);
- try std.testing.expect(std.mem.indexOf(u8, initial_tag, "pdf 1/") != null);
- try std.testing.expect(std.mem.indexOf(u8, initial_tag, " width ") != null);
- try std.testing.expect(std.mem.indexOf(u8, initial_tag, " height ") == null);
- try std.testing.expect(std.mem.indexOf(u8, initial_tag, "PdfFit") != null);
+ const expected_tag = try std.fmt.allocPrint(p.scratch.allocator(), "{s} [1/{d}]{s}", .{ pane.pdf.?.path, pane.pdf.?.page_count, pane_tail });
+ try std.testing.expectEqualStrings(expected_tag, initial_tag);
try std.testing.expect(std.mem.endsWith(u8, initial_tag, pane_tail));
p.native_images = true;
@@ -668,10 +666,8 @@ test "MuPDF pane renders, navigates, searches, and round-trips its page" {
panes.Pdf.rasterForPage(&pane.pdf.?, pane.pdf.?.page).?.revision,
);
const height_tag = try pardes.test_api.tagText(p, p.scratch.allocator(), pane);
- try std.testing.expect(std.mem.indexOf(u8, height_tag, "pdf 1/") != null);
- try std.testing.expect(std.mem.indexOf(u8, height_tag, " width ") == null);
- try std.testing.expect(std.mem.indexOf(u8, height_tag, " height ") != null);
- try std.testing.expect(std.mem.indexOf(u8, height_tag, "PdfFit") != null);
+ const expected_height_tag = try std.fmt.allocPrint(p.scratch.allocator(), "{s} [{d}/{d}]{s}", .{ pane.pdf.?.path, pane.pdf.?.page + 1, pane.pdf.?.page_count, pane_tail });
+ try std.testing.expectEqualStrings(expected_height_tag, height_tag);
for (p.panes) |slot| {
const other = slot orelse continue;
if (hasPdf(other)) continue;
@@ -1072,7 +1068,7 @@ test "PDF continuous strip renders every intersecting short page" {
}
}
-test "PdfTint cycles pane-local state and exposes it in the live PDF tag" {
+test "PdfTint cycles pane-local state without adding tag clutter" {
if (!pdf_enabled or platform == .web) return;
const p = try Pardes.init(std.testing.allocator, .{
@@ -1088,11 +1084,9 @@ test "PdfTint cycles pane-local state and exposes it in the live PDF tag" {
try std.testing.expectEqual(PdfTintMode.filtered, pv.tint);
const initial_tag = try pardes.test_api.tagText(p, p.scratch.allocator(), pane);
- try std.testing.expect(std.mem.indexOf(
- u8,
- initial_tag,
- "width PdfFit filtered PdfTint",
- ) != null);
+ try std.testing.expect(std.mem.startsWith(u8, initial_tag, pv.path));
+ try std.testing.expect(std.mem.endsWith(u8, initial_tag, " PdfSections PdfTint Collapse"));
+ try std.testing.expect(std.mem.indexOf(u8, initial_tag, "filtered") == null);
try std.testing.expect(pardes.test_api.runBuiltin(
p,
@@ -1103,7 +1097,8 @@ test "PdfTint cycles pane-local state and exposes it in the live PDF tag" {
));
try std.testing.expectEqual(PdfTintMode.full, pv.tint);
const full_tag = try pardes.test_api.tagText(p, p.scratch.allocator(), pane);
- try std.testing.expect(std.mem.indexOf(u8, full_tag, "full PdfTint") != null);
+ try std.testing.expectEqualStrings(initial_tag, full_tag);
+ try std.testing.expect(std.mem.indexOf(u8, full_tag, "full") == null);
// Running the same pane-scoped word in a terminal cannot mutate the PDF
// next to it. A FILE boot is one pane now, so that terminal is asked for
@@ -1130,7 +1125,8 @@ test "PdfTint cycles pane-local state and exposes it in the live PDF tag" {
));
try std.testing.expectEqual(PdfTintMode.disabled, pv.tint);
const disabled_tag = try pardes.test_api.tagText(p, p.scratch.allocator(), pane);
- try std.testing.expect(std.mem.indexOf(u8, disabled_tag, "disabled PdfTint") != null);
+ try std.testing.expectEqualStrings(initial_tag, disabled_tag);
+ try std.testing.expect(std.mem.indexOf(u8, disabled_tag, "disabled") == null);
try std.testing.expect(pardes.test_api.runBuiltin(
p,
@tagName(tint_builtin),
diff --git a/test/snapshots/argv.golden b/test/snapshots/argv.golden
index fba7ae43..4da2a12d 100644
--- a/test/snapshots/argv.golden
+++ b/test/snapshots/argv.golden
@@ -1,12 +1,14 @@
-== snap noargs grid=100x30 cursor=4,4
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|$ /tmp/pardes-snap/argv/cwd Save New Newtty Del Filter
+== snap noargs grid=100x31 cursor=4,5
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+|$ /tmp/pardes-snap/argv/cwd Save Tty Del Togglettymode Filter Collapse
| $ echo ARGV''TTY
| ARGVTTY
| $
-== snap filearg grid=100x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/argv/cwd/notes.txt Save New Newtty Del
+== snap filearg grid=100x31 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/argv/cwd/notes.txt Save Tty Del Collapse
| 3 line 3
| 4 line 4
| 5 line 5
@@ -14,9 +16,10 @@
| 7 line 7
| 8 line 8
| 9
-== snap filearg-n3 grid=100x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/argv/cwd/notes.txt Save New Newtty Del
+== snap filearg-n3 grid=100x31 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/argv/cwd/notes.txt Save Tty Del Collapse
| 1 line 1
| 2 line 2
| 3 line 3
@@ -26,8 +29,9 @@
| 7 line 7
| 8 line 8
| 9
-== snap dirarg grid=100x30 cursor=4,4
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/argv/cwd/sub Save New Newtty Del Filter
+== snap dirarg grid=100x31 cursor=4,5
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/argv/cwd/sub Save Tty Del Togglettymode Filter Collapse
| ls
| inside.txt
diff --git a/test/snapshots/argv.snap b/test/snapshots/argv.snap
index b2ebff2d..892f6b24 100644
--- a/test/snapshots/argv.snap
+++ b/test/snapshots/argv.snap
@@ -4,7 +4,7 @@
# argument becomes the cwd the shell spawns in
lines notes.txt 8
file zmarker.txt x
-start 30 100
+start 31 100
wait 8000 $
stable 700 20000
text echo ARGV''TTY
@@ -12,23 +12,23 @@ key enter
wait 8000 ARGVTTY
stable 700 10000
snap noargs
-start 30 100 notes.txt:3
-wait 8000 New Newcol
+start 31 100 notes.txt:3
+wait 8000 Newcol Joincol
wait 8000 line 3
stable 700 20000
snap filearg
# -n and a FILE are not a combination: the file names the whole boot layout, so
# `-n 3` boots the very same single pane (it always did — the file arm never
# looked at the count; before this it merely also stapled a shell to the right)
-start 30 100 -n 3 notes.txt
-wait 8000 New Newcol
+start 31 100 -n 3 notes.txt
+wait 8000 Newcol Joincol
wait 8000 line 1
stable 700 20000
snap filearg-n3
dirmk sub
file sub/inside.txt marker
-start 30 100 sub
-wait 8000 New Newcol
+start 31 100 sub
+wait 8000 Newcol Joincol
wait 8000 inside.txt
stable 700 20000
snap dirarg
diff --git a/test/snapshots/badutf.golden b/test/snapshots/badutf.golden
index 49395e38..270b3fe6 100644
--- a/test/snapshots/badutf.golden
+++ b/test/snapshots/badutf.golden
@@ -1,14 +1,16 @@
-== snap badbytes grid=100x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/badutf/cwd/bad.txt Save New Newtty Del
+== snap badbytes grid=100x31 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/badutf/cwd/bad.txt Save Tty Del Collapse
| 1 hello �� world
| 2 latin-1 caf� tail
| 3 truncated �� here
| 4 end
| 5
-== snap hscroll-midglyph grid=50x30 cursor=46,2
-|New Newcol Joincol Find Grep Help Changelog Tutor
-| /tmp/pardes-snap/badutf/cwd/wide.txt Save New Ne
+== snap hscroll-midglyph grid=50x31 cursor=46,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/badutf/cwd/wide.txt Save Tty De
| 1 日本語 日本語 日本語 日本語 日本語 tail
| 2
| 3
diff --git a/test/snapshots/badutf.snap b/test/snapshots/badutf.snap
index 46592178..ddd1588b 100644
--- a/test/snapshots/badutf.snap
+++ b/test/snapshots/badutf.snap
@@ -4,15 +4,15 @@
# horizontal scrolling must start at a complete grapheme boundary.
file bad.txt hello \xff\xfe world\nlatin-1 caf\xe9 tail\ntruncated \xe6\x97 here\nend\n
file wide.txt \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e tail\nsecond line\n
-start 30 100 bad.txt
-wait 8000 New Newcol
+start 31 100 bad.txt
+wait 8000 Newcol Joincol
stable 700 20000
snap badbytes
# 50 columns, not 100: a FILE boots alone and fills the window, and at 100 the
# whole line fits, so `$` scrolls nowhere. This is
# the width the left column used to be, i.e. the pane this case was written for
-start 30 50 wide.txt
-wait 8000 New Newcol
+start 31 50 wide.txt
+wait 8000 Newcol Joincol
stable 700 20000
# SPC t w turns soft wrap OFF: hscroll is the other half of this case and a
# wrapped body has nothing to scroll sideways. The unwrapped view must keep the
diff --git a/test/snapshots/boot.golden b/test/snapshots/boot.golden
index 12f20b9e..f1e159d1 100644
--- a/test/snapshots/boot.golden
+++ b/test/snapshots/boot.golden
@@ -1,36 +1,38 @@
-== snap boot grid=100x30 cursor=4,4
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/boot/cwd Save New Newtty Del Filter
+== snap boot grid=100x31 cursor=4,5
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/boot/cwd Save Tty Del Togglettymode Filter Collapse
| ls
| hello.txt
-== style boot grid=100x30
-|0: 0-74 #949494,#121212, 75-99 d,#121212,
-|1: 0-1 #ffffff,#626262, 2-79 #949494,#121212, 80-99 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|4: 0-0 d,#444444, 1-99 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|8: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|11: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|16: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|19: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|29: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
+== style boot grid=100x31
+|0: 0-70 #b2c3b8,#1d2824, 71-99 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-99 d,#26362d,
+|2: 0-1 #000000,#adcc91, 2-69 #becfc4,#26362d, 70-99 d,#26362d,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|5: 0-0 d,#637f6a, 1-99 d,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|17: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|20: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
diff --git a/test/snapshots/boot.snap b/test/snapshots/boot.snap
index cf2ae3fd..60baf7de 100644
--- a/test/snapshots/boot.snap
+++ b/test/snapshots/boot.snap
@@ -1,7 +1,7 @@
# -n 1: one shell pane in normal mode, greets with ls; prompts hidden
file hello.txt marker-content
-start 30 100 -n 1
-wait 8000 New Newcol
+start 31 100 -n 1
+wait 8000 Newcol Joincol
wait 8000 hello.txt
stable 700 20000
snap boot
diff --git a/test/snapshots/builtins.golden b/test/snapshots/builtins.golden
index 5c9ab060..17b4db5e 100644
--- a/test/snapshots/builtins.golden
+++ b/test/snapshots/builtins.golden
@@ -1,6 +1,7 @@
-== snap boot grid=120x66 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/builtins/cwd/notes.txt Save New Newtty Del
+== snap boot grid=120x67 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/builtins/cwd/notes.txt Save Tty Del Collapse
| 1 line 1
| 2 line 2
| 3 line 3
@@ -8,36 +9,36 @@
| 5 line 5
| 6 line 6
| 7
-== snap window-group grid=120x66 cursor=7,35
-|34: /tmp/pardes-snap/builtins/cwd/+Help Save New Newtty Del
-|35: 1 pardes builtins under SPC w
-|36: 2
-|37: 3 SPC w h Left C-w h, C-w left
-|38: 4 SPC w j Down C-w j, C-w down
-|39: 5 SPC w k Up C-w k, C-w up
-|40: 6 SPC w l Right C-w l, C-w right
-|41: 7
-== snap docs-group grid=120x66 cursor=7,35
-|35: 1 pardes builtins under SPC h
-|37: 3 SPC h c Changelog topbar
-|38: 4 SPC h m Messages
-|39: 5 SPC h t Tutor topbar
-|40: 6
-|41:
-== snap tutor-from-index grid=120x66 cursor=7,19
-|18: /Tutor Save New Newtty Del
-|19: 1
-|20: 2 PARDES TUTOR
-|21: 3 tmux + vi + acme, from scratch.
-|22: 4
-|23: 5 The model is acme's: EVERYTHING is text, editable and executable
-|24: 6 the same way. Modal editing (helix-style) lives on top of that.
-|25: 7 Press j until you reach the introduction.
-|26: 8
-|27: 9
-|28: 10 =================================================================
-|29: 11 = INTRODUCTION =
-|30: 12 =================================================================
-|31: 13
-|32: 14 A pane is just text on screen. There is no separate "buffer" type —
-|33: 15 what you see is what you edit. Some panes happen to be live terminals;
+== snap window-group grid=120x67 cursor=7,36
+|35: /tmp/pardes-snap/builtins/cwd/+Help Save Tty Del Collapse
+|36: 1 pardes builtins under SPC w
+|37: 2
+|38: 3 SPC w h Left C-w h, C-w left
+|39: 4 SPC w j Down C-w j, C-w down
+|40: 5 SPC w k Up C-w k, C-w up
+|41: 6 SPC w l Right C-w l, C-w right
+|42: 7
+== snap docs-group grid=120x67 cursor=7,36
+|36: 1 pardes builtins under SPC h
+|38: 3 SPC h c Changelog topbar
+|39: 4 SPC h m Messages
+|40: 5 SPC h t Tutor topbar
+|41: 6
+|42:
+== snap tutor-from-index grid=120x67 cursor=7,20
+|19: /Tutor Save Tty Del Collapse
+|20: 1
+|21: 2 PARDES TUTOR
+|22: 3 tmux + vi + acme, from scratch.
+|23: 4
+|24: 5 The model is acme's: EVERYTHING is text, editable and executable
+|25: 6 the same way. Modal editing (helix-style) lives on top of that.
+|26: 7 Press j until you reach the introduction.
+|27: 8
+|28: 9
+|29: 10 =================================================================
+|30: 11 = INTRODUCTION =
+|31: 12 =================================================================
+|32: 13
+|33: 14 A pane is just text on screen. There is no separate "buffer" type —
+|34: 15 what you see is what you edit. Some panes happen to be live terminals;
diff --git a/test/snapshots/builtins.snap b/test/snapshots/builtins.snap
index aebb2a18..06298d77 100644
--- a/test/snapshots/builtins.snap
+++ b/test/snapshots/builtins.snap
@@ -1,5 +1,5 @@
lines notes.txt 6
-start 66 120 notes.txt
+start 67 120 notes.txt
wait 8000 notes.txt
stable 700 20000
snap boot
@@ -9,6 +9,9 @@ key space ?
wait 10000 pardes builtins, and how to run each:
wait 10000 ClipPasteBefore
key g e
+# The new Collapse entry adds one index line: expose Look above the bottom
+# viewport while keeping the same pane geometry for the later group clicks.
+wheel up 110 50
wait 10000 Look enter, right-click
wait 10000 Exec tab, middle-click
wait 10000 Filter
@@ -28,8 +31,8 @@ key space h ?
wait 10000 Tutor
stable 700 15000
snap docs-group
-press middle @Tutor 40
-release middle @Tutor 40
+press middle @Tutor 41
+release middle @Tutor 41
wait 10000 PARDES TUTOR
stable 700 15000
snap tutor-from-index
diff --git a/test/snapshots/chordcut.golden b/test/snapshots/chordcut.golden
index 07628820..33bc8356 100644
--- a/test/snapshots/chordcut.golden
+++ b/test/snapshots/chordcut.golden
@@ -1,98 +1,85 @@
-== snap opened grid=120x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/chordcut/cwd/f.txt Save New Newtty Del /tmp/pardes-snap/chordcut/cwd Save New Newtty Del Filter
-| 1 line 1 ls
-| 2 line 2 f.txt g.txt
+== snap opened grid=120x31 cursor=7,7
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/chordcut/cwd Save Tty Del Togglettymode F /tmp/pardes-snap/chordcut/cwd Save Tty Del Togglettymode F
+| ls ls
+| f.txt g.txt f.txt g.txt
+|
+| /tmp/pardes-snap/chordcut/cwd/f.txt Save Tty Del Collapse
+| 1 line 1
+| 2 line 2
| 3 line 3
| 4 line 4
| 5 line 5
-|╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
-| /tmp/pardes-snap/chordcut/cwd Save New Newtty Del Filter
-| ls
-| f.txt g.txt
+| 6
|
|
|
-| f.txt
|
-| /tmp/pardes-snap/chordcut/cwd Save New Newtty Del Filter
+| /tmp/pardes-snap/chordcut/cwd Save Tty Del Togglettymode F
| ls
| f.txt g.txt
-== snap cut grid=120x30 cursor=7,3
-|1: /tmp/pardes-snap/chordcut/cwd/f.txt * Save New Newtty Del /tmp/pardes-snap/chordcut/cwd Save New Newtty Del Filter
-|3: 2 2 f.txt g.txt
-|7: 6
-|8: /tmp/pardes-snap/chordcut/cwd Save New Newtty Del Filter
-|16: /tmp/pardes-snap/chordcut/cwd Save New Newtty Del Filter
-== snap copied grid=120x30 cursor=10,4
-== snap pointpaste grid=120x30 cursor=16,5
-|5: 4 line 4line
-== snap replaced grid=120x30 cursor=11,6
-|6: 5 lline 5
-== snap cancelexec grid=120x30 cursor=25,3
-|3: 2 2echo B''OO g.txt f.txt g.txt
-== snap execafter grid=120x30 cursor=25,3
-|9: f.txt g.txt
-|10:
-|13: f.txt
-|14: BOO
-== snap cancellook grid=120x30 cursor=25,3
-== snap lookafter grid=120x30 cursor=7,5
-|3: ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ f.txt g.txt
-|4: /tmp/pardes-snap/chordcut/cwd/g.txt Save New Newtty Del
-|5: 1 line 1
-|6: 2 line 2
-|7: 3
-== style chordsel grid=120x30
-|0: 0-74 #949494,#121212, 75-119 d,#121212,
-|1: 0-1 #ffffff,#262626, 2-58 #949494,#121212, 59-59 d,#121212, 60-61 #ffffff,#262626, 62-117 #949494,#121212, 118-119 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-59 d,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|3: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-24 #bdbdbd,#080808, 25-59 d,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|4: 0-1 #ffffff,#626262, 2-58 #949494,#121212, 59-59 d,#121212, 60-60 d,#444444, 61-119 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-10 #080808,#80a0ff, 11-12 #bdbdbd,#080808, 13-59 d,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-59 d,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-59 d,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|8: 0-1 #ffffff,#262626, 2-58 #949494,#121212, 59-59 d,#121212, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|10: 0-0 d,#444444, 1-59 d,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|11: 0-0 d,#444444, 1-59 d,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|12: 0-0 d,#444444, 1-59 d,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-8 #bdbdbd,#080808, 9-59 d,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|15: 0-0 d,#121212, 1-59 d,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|16: 0-1 #ffffff,#262626, 2-58 #949494,#121212, 59-59 d,#121212, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|19: 0-0 d,#444444, 1-59 d,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|29: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-== style clickdismiss grid=120x30
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-59 d,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-12 #bdbdbd,#080808, 13-59 d,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-== snap ttyprobe grid=120x30 cursor=42,15
-|3: 2 2echo B''OO g.txt f.txt g.txt
-|4: /tmp/pardes-snap/chordcut/cwd/g.txt * Save New Newtty Del
-|8: $ /tmp/pardes-snap/chordcut/cwd Save New Newtty Del Filter
-|9: $
-|10: $
-|11: $ echo B''OO
-|12: BOO
-|13: $ stty -icanon -echo; printf '\x1b[?2004h\x1b[?1000h\x1b[?
-|14: 1006h'; cat -v
-|15: ^[[<0;38;3M^[[<0;38;3m^[[200~line^[[201~
-== snap ttyprompt grid=120x30 cursor=8,15
-|9: $ echo B''OO
-|10: BOO
-|11: $ stty -icanon -echo; printf '\x1b[?2004h\x1b[?1000h\x1b[?
-|12: 1006h'; cat -v
-|13: ^[[<0;38;3M^[[<0;38;3m^[[200~line^[[201~
-|14: $
-|15: $ line
+== snap cut grid=120x31 cursor=7,8
+|6: /tmp/pardes-snap/chordcut/cwd/f.txt * Save Tty Del Collaps
+|8: 2 2
+== snap copied grid=120x31 cursor=10,9
+== snap pointpaste grid=120x31 cursor=16,10
+|10: 4 line 4line
+== snap replaced grid=120x31 cursor=11,11
+|11: 5 lline 5
+== snap cancelexec grid=120x31 cursor=25,8
+|8: 2 2echo B''OO g.txt
+== snap execafter grid=120x31 cursor=25,8
+|3: f.txt ls
+|4: BOO f.txt g.txt
+== snap cancellook grid=120x31 cursor=25,8
+== snap lookafter grid=120x31 cursor=7,13
+|12: /tmp/pardes-snap/chordcut/cwd/g.txt Save Tty Del Collapse
+|13: 1 line 1
+|14: 2 line 2
+|15: 3
+== style chordsel grid=120x31
+|0: 0-70 #b2c3b8,#1d2824, 71-119 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-59 d,#26362d, 60-84 #b2c3b8,#1d2824, 85-119 d,#1d2824,
+|2: 0-1 #ffffff,#4c6356, 2-59 #b2c3b8,#1d2824, 60-61 #ffffff,#4c6356, 62-119 #b2c3b8,#1d2824,
+|3: 0-0 d,#152019, 1-1 d,#0d1410, 2-8 #e5eee5,#0d1410, 9-59 d,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|5: 0-0 d,#152019, 1-59 d,#0d1410, 60-60 d,#637f6a, 61-119 d,#0d1410,
+|6: 0-1 #ffffff,#4c6356, 2-59 #b2c3b8,#1d2824, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-59 d,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-24 #e5eee5,#0d1410, 25-59 d,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-59 d,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-16 #e5eee5,#0d1410, 17-59 d,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|11: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-59 d,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|12: 0-1 #000000,#adcc91, 2-59 #becfc4,#26362d, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-10 #f5f7ee,#405d4b, 11-12 #e5eee5,#0d1410, 13-59 d,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-59 d,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-59 d,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-59 d,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|17: 0-1 #ffffff,#4c6356, 2-59 #b2c3b8,#1d2824, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|20: 0-0 d,#637f6a, 1-59 d,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+== style clickdismiss grid=120x31
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-59 d,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-12 #e5eee5,#0d1410, 13-59 d,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+== snap ttyprobe grid=120x31 cursor=42,22
+|12: /tmp/pardes-snap/chordcut/cwd/g.txt * Save Tty Del Collaps
+|17: $ /tmp/pardes-snap/chordcut/cwd Save Tty Del Togglettymode F
+|18: $ ls
+|20: $ stty -icanon -echo; printf '\x1b[?2004h\x1b[?1000h\x1b[?
+|21: 1006h'; cat -v
+|22: ^[[<0;38;6M^[[<0;38;6m^[[200~line^[[201~
+== snap ttyprompt grid=120x31 cursor=8,24
+|23: $
+|24: $ line
diff --git a/test/snapshots/chordcut.snap b/test/snapshots/chordcut.snap
index fe191f64..56170cce 100644
--- a/test/snapshots/chordcut.snap
+++ b/test/snapshots/chordcut.snap
@@ -7,64 +7,64 @@
# left during a right (look) drag cancels the gesture entirely.
lines f.txt 5
lines g.txt 2
-# Source-local column splitting deliberately leaves the unrelated right
-# column wide. Give the caller half enough cells that the selected
+# The narrow-window fallback splits below the source shell and leaves the
+# unrelated right column untouched. Give the caller enough cells that the selected
# `echo B''OO g.txt` remains one displayed row; this test is about chords, not
# soft-wrap traversal.
-start 30 120 -n 3
+start 31 120 -n 3
wait 8000 f.txt
stable 700 20000
# open f.txt: click a body spot, type the name, look it
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key i
text f.txt
key esc
settle 100
stable 400 5000
-press right 6 8
-release right 6 8
+press right 6 9
+release right 6 9
wait 10000 line 3
stable 700 15000
snap opened
# 1-2 Cut: left-drag over "line" on line 2, tap middle while holding
-press left 8 4
-drag left 11 4
-press middle 11 4
-release middle 11 4
-release left 11 4
+press left 8 9
+drag left 11 9
+press middle 11 9
+release middle 11 9
+release left 11 9
stable 400 5000
snap cut
# 1-2 then 1-3 in one hold = copy: line 3 keeps its text, register loaded
-press left 8 5
-drag left 11 5
-press middle 11 5
-release middle 11 5
-press right 11 5
-release right 11 5
-release left 11 5
+press left 8 10
+drag left 11 10
+press middle 11 10
+release middle 11 10
+press right 11 10
+release right 11 10
+release left 11 10
stable 400 5000
snap copied
# 1-3 at a bare click point: hold left past the end of line 4, tap right —
# the register splices in at the click
-press left 14 6
-press right 14 6
-release right 14 6
-release left 14 6
+press left 14 11
+press right 14 11
+release right 14 11
+release left 14 11
stable 400 5000
snap pointpaste
# 1-3 over a fresh selection replaces it with the register
-press left 9 7
-drag left 11 7
-press right 11 7
-release right 11 7
-release left 11 7
+press left 9 12
+drag left 11 12
+press right 11 12
+release right 11 12
+release left 11 12
stable 400 5000
snap replaced
# arm the cancel tests: append `echo B''OO g.txt` to line 2
-press left 10 4
-release left 10 4
+press left 10 9
+release left 10 9
stable 400 5000
key i
text echo B''OO g.txt
@@ -73,67 +73,67 @@ settle 100
stable 400 5000
# 2-3 cancel (acme textselect2): tap right during the middle execute-drag
# over `echo B''OO` — the command never runs (no BOO anywhere)
-press middle 10 4
-drag middle 19 4
-press right 19 4
-release right 19 4
-release middle 19 4
+press middle 10 9
+drag middle 19 9
+press right 19 9
+release right 19 9
+release middle 19 9
stable 700 8000
snap cancelexec
# the same drag released clean proves the word was live: BOO appears
-press middle 10 4
-drag middle 19 4
-release middle 19 4
+press middle 10 9
+drag middle 19 9
+release middle 19 9
wait 10000 BOO
stable 700 10000
snap execafter
# 3-1 cancel (acme textselect3): tap left during the right look-drag over
# g.txt — no pane opens
-press right 21 4
-drag right 25 4
-press left 25 4
-release left 25 4
-release right 25 4
+press right 21 9
+drag right 25 9
+press left 25 9
+release left 25 9
+release right 25 9
stable 700 8000
snap cancellook
# the same look released clean opens g.txt
-press right 21 4
-drag right 25 4
-release right 25 4
+press right 21 9
+drag right 25 9
+release right 25 9
wait 10000 line 2
stable 700 10000
snap lookafter
# a fresh left click dismisses the chord's leftover selection instead of
-# dragging the anchored span to the click: copy `line` on f.txt line 1
+# dragging the anchored span to the click: copy `line` on g.txt line 1
# (styled snap shows the selection), then click the next row (it's gone)
-press left 8 6
-drag left 11 6
-press middle 11 6
-release middle 11 6
-press right 11 6
-release right 11 6
-release left 11 6
+press left 8 14
+drag left 11 14
+press middle 11 14
+release middle 11 14
+press right 11 14
+release right 11 14
+release left 11 14
stable 400 5000
snapstyle chordsel
-press left 8 7
-release left 8 7
+press left 8 15
+release left 8 15
stable 400 5000
snapstyle clickdismiss
# tty paste chord: a mouse-listening app gets the click forwarded (SGR,
# body-relative) then the register between bracketed-paste markers —
# cat -v prints the received bytes visibly
-press left 35 11
-release left 35 11
+press left 35 22
+release left 35 22
stable 400 5000
key c-b
stable 600 8000
text stty -icanon -echo; printf '\x1b[?2004h\x1b[?1000h\x1b[?1006h'; cat -v
key enter
stable 700 8000
-press left 40 12
-press right 40 12
-release right 40 12
-release left 40 12
+press left 40 24
+press right 40 24
+release right 40 24
+release left 40 24
stable 700 8000
snap ttyprobe
# a plain prompt (mouse modes off) gets no click bytes — just the paste;
@@ -143,9 +143,9 @@ stable 600 8000
text stty sane; printf '\x1b[?1000l\x1b[?1006l'
key enter
stable 600 8000
-press left 40 12
-press right 40 12
-release right 40 12
-release left 40 12
+press left 40 24
+press right 40 24
+release right 40 24
+release left 40 24
stable 700 8000
snap ttyprompt
diff --git a/test/snapshots/cmdword.golden b/test/snapshots/cmdword.golden
index 4d3ad655..0ba57092 100644
--- a/test/snapshots/cmdword.golden
+++ b/test/snapshots/cmdword.golden
@@ -1,23 +1,24 @@
-== snap opened grid=120x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/cmdword/cwd/cmds.txt Save New Newtty Del
+== snap opened grid=120x31 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/cmdword/cwd/cmds.txt Save Tty Del Collapse
| 1 @`echo ZZ''E` @`echo ZZ''L` Look p.txt @`Look .`
-== snap atexec grid=120x30 cursor=7,2
-|16: /tmp/pardes-snap/cmdword/cwd Save New Newtty Del Filter
-|17: echo ZZ''E
-|18: ZZE
-== snap atlook grid=120x30 cursor=4,21
-|19: echo ZZ''L
-|20: ZZL
-== snap lookword grid=120x30 cursor=7,10
-|9: /tmp/pardes-snap/cmdword/cwd/p.txt Save New Newtty Del
-|10: 1 just text
-== snap nested grid=120x30 cursor=4,23
-|21: ls
-|22: cmds.txt p.txt zzmark.txt
-== snap execword grid=120x30 cursor=104,16
-|16: /tmp/pardes-snap/cmdword/cwd Save New Newtty Del Filter Exec
-== snap tagcmd grid=120x30 cursor=118,16
-|16: /tmp/pardes-snap/cmdword/cwd Save New Newtty Del Filter Exec @`echo ZZ''T`
-|23: echo ZZ''T
-|24: ZZT
+== snap atexec grid=120x31 cursor=7,3
+|17: /tmp/pardes-snap/cmdword/cwd Save Tty Del Togglettymode Filter Collapse
+|18: echo ZZ''E
+|19: ZZE
+== snap atlook grid=120x31 cursor=4,22
+|20: echo ZZ''L
+|21: ZZL
+== snap lookword grid=120x31 cursor=7,11
+|10: /tmp/pardes-snap/cmdword/cwd/p.txt Save Tty Del Collapse
+|11: 1 just text
+== snap nested grid=120x31 cursor=4,24
+|22: ls
+|23: cmds.txt p.txt zzmark.txt
+== snap execword grid=120x31 cursor=77,17
+|17: /tmp/pardes-snap/cmdword/cwd Save Tty Del Togglettymode Filter Collapse Exec
+== snap tagcmd grid=120x31 cursor=91,17
+|17: /tmp/pardes-snap/cmdword/cwd Save Tty Del Togglettymode Filter Collapse Exec @`echo ZZ''T`
+|24: echo ZZ''T
+|25: ZZT
diff --git a/test/snapshots/cmdword.snap b/test/snapshots/cmdword.snap
index fed51315..eb9d308d 100644
--- a/test/snapshots/cmdword.snap
+++ b/test/snapshots/cmdword.snap
@@ -18,37 +18,37 @@
file cmds.txt @`echo ZZ''E` @`echo ZZ''L` Look p.txt @`Look .`
file p.txt just text
file zzmark.txt x
-start 30 120 cmds.txt
-wait 8000 New Newcol
+start 31 120 cmds.txt
+wait 8000 Newcol Joincol
wait 8000 cmds.txt
stable 700 20000
snap opened
# a single middle CLICK inside the run (col 11 is inside `echo`) expands to the
# whole `@`echo ZZ''E`` and executes it in a shell; focus stays on the file
-press middle 11 3
-release middle 11 3
+press middle 11 4
+release middle 11 4
wait 10000 ZZE
stable 700 15000
snap atexec
# LOOK on the second one (col 24, inside its `echo`) runs it too AND focuses
# the shell that answered — that is the whole difference between the two verbs
-press right 24 3
-release right 24 3
+press right 24 4
+release right 24 4
wait 10000 ZZL
stable 700 15000
snap atlook
# `Look p.txt` middle-dragged: the builtin by NAME, with an argument
-press middle 36 3
-drag middle 45 3
-release middle 45 3
+press middle 36 4
+drag middle 45 4
+release middle 45 4
wait 10000 just text
stable 700 15000
snap lookword
# nesting: `@`Look .`` — Exec unwraps it, `Look .` is parsed as the ordinary
# Look builtin with an argument, and Look opens the directory (an existing
# shell there, ls'd — zzmark.txt is only ever in that listing)
-press middle 49 3
-release middle 49 3
+press middle 49 4
+release middle 49 4
wait 10000 zzmark.txt
stable 700 15000
snap nested
diff --git a/test/snapshots/collapse.golden b/test/snapshots/collapse.golden
new file mode 100644
index 00000000..8dcfd4d7
--- /dev/null
+++ b/test/snapshots/collapse.golden
@@ -0,0 +1,80 @@
+== snap before grid=160x25 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/collapse/cwd/kept.txt Save Tty Del Collapse
+| 1 KEEP-FIRST
+| 2 KEEP-SECOND
+| 3 KEEP-THIRD
+== snap middle-collapsed grid=160x25 cursor=7,3
+|3:
+|4:
+|5:
+== 9p middle-collapsed-cursor grid=160x25 cursor=none
+|0: Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+@0: 0-70 #b2c3b8,#1d2824,,tagline 71-159 d,#1d2824,,tagline
+|1: New Tty Find Grep Joincol
+@1: 0-24 #becfc4,#26362d,,tagline 25-159 d,#26362d,,tagline
+|2: /tmp/pardes-snap/collapse/cwd/kept.txt Save Tty Del Collapse
+@2: 0-1 #000000,#adcc91,,tagline 2-61 #becfc4,#26362d,,tagline 62-159 d,#26362d,,tagline
+|3:
+@3: 0-159 d,#35483d,,body
+|4:
+@4: 0-159 d,#35483d,,body
+|5:
+@5: 0-159 d,#35483d,,body
+|6:
+@6: 0-159 d,#35483d,,body
+|7:
+@7: 0-159 d,#35483d,,body
+|8:
+@8: 0-159 d,#35483d,,body
+|9:
+@9: 0-159 d,#35483d,,body
+|10:
+@10: 0-159 d,#35483d,,body
+|11:
+@11: 0-159 d,#35483d,,body
+|12:
+@12: 0-159 d,#35483d,,body
+|13:
+@13: 0-159 d,#35483d,,body
+|14:
+@14: 0-159 d,#35483d,,body
+|15:
+@15: 0-159 d,#35483d,,body
+|16:
+@16: 0-159 d,#35483d,,body
+|17:
+@17: 0-159 d,#35483d,,body
+|18:
+@18: 0-159 d,#35483d,,body
+|19:
+@19: 0-159 d,#35483d,,body
+|20:
+@20: 0-159 d,#35483d,,body
+|21:
+@21: 0-159 d,#35483d,,body
+|22:
+@22: 0-159 d,#35483d,,body
+|23:
+@23: 0-159 d,#35483d,,body
+|24:
+@24: 0-159 d,#35483d,,body
+== snap middle-restored grid=160x25 cursor=7,3
+|3: 1 KEEP-FIRST
+|4: 2 KEEP-SECOND
+|5: 3 KEEP-THIRD
+== snap tab-collapsed grid=160x25 cursor=54,2
+|3:
+|4:
+|5:
+== 9p tab-collapsed-cursor grid=160x25 cursor=54,2,bar
+== snap tab-restored grid=160x25 cursor=54,2
+|3: 1 KEEP-FIRST
+|4: 2 KEEP-SECOND
+|5: 3 KEEP-THIRD
+== file unchanged
+KEEP-FIRST
+KEEP-SECOND
+KEEP-THIRD
+== end file
diff --git a/test/snapshots/collapse.snap b/test/snapshots/collapse.snap
new file mode 100644
index 00000000..64f6bdb8
--- /dev/null
+++ b/test/snapshots/collapse.snap
@@ -0,0 +1,36 @@
+# A default pane-tag command collapses to one row and restores the body.
+# Exercise real middle clicks twice, then tag editing's Tab execution twice.
+file kept.txt KEEP-FIRST\nKEEP-SECOND\nKEEP-THIRD
+start 25 160 kept.txt
+wait 8000 KEEP-THIRD
+stable 500 15000
+snap before
+press middle @Collapse 3
+release middle @Collapse 3
+stable 500 8000
+snap middle-collapsed
+# The terminal remembers its last cursor position even when hidden. The core
+# screen explicitly reports null, guarding against a leaked body caret.
+snap9p middle-collapsed-cursor
+press middle @Collapse 3
+release middle @Collapse 3
+wait 8000 KEEP-THIRD
+stable 500 8000
+snap middle-restored
+press left @Collapse 3
+release left @Collapse 3
+key tab
+stable 500 8000
+snap tab-collapsed
+snap9p tab-collapsed-cursor
+press left @Collapse 3
+release left @Collapse 3
+key tab
+wait 8000 KEEP-THIRD
+stable 500 8000
+snap tab-restored
+# Save via the visible tag; the original bytes must survive all four toggles.
+press middle @Save 3
+release middle @Save 3
+stable 500 8000
+snapfile unchanged kept.txt
diff --git a/test/snapshots/cornerdrag-left.golden b/test/snapshots/cornerdrag-left.golden
index 2858dcaa..df10fd3d 100644
--- a/test/snapshots/cornerdrag-left.golden
+++ b/test/snapshots/cornerdrag-left.golden
@@ -1,10 +1,11 @@
-== snap right-split grid=100x30 cursor=54,8
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/cornerdrag-left/cwd Save New Ne /tmp/pardes-snap/cornerdrag-left/cwd Save New Ne
+== snap right-split grid=100x31 cursor=54,9
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/cornerdrag-left/cwd Save Tty De /tmp/pardes-snap/cornerdrag-left/cwd Save Tty De
| ls ls
| w.txt w.txt
|
-| /tmp/pardes-snap/cornerdrag-left/cwd Save New Ne
+| /tmp/pardes-snap/cornerdrag-left/cwd Save Tty De
| ls
| w.txt
|
@@ -15,18 +16,18 @@
|
|
|
-| /tmp/pardes-snap/cornerdrag-left/cwd Save New Ne
+| /tmp/pardes-snap/cornerdrag-left/cwd Save Tty De
| ls
| w.txt
-== snap hover-corner grid=100x30 cursor=54,8
-|1: /tmp/pardes-snap/cornerdrag-left/cwd Save New N╎ /tmp/pardes-snap/cornerdrag-left/cwd Save New Ne
-|2: ls ╎ ls
-|3: w.txt ╎ w.txt
-|4: ╎╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
-|5: ╎ /tmp/pardes-snap/cornerdrag-left/cwd Save New Ne
-|6: ╎ ls
-|7: ╎ w.txt
-|8: ╎
+== snap hover-corner grid=100x31 cursor=54,9
+|1: New Tty Find Grep Joincol ╎New Tty Find Grep Joincol
+|2: /tmp/pardes-snap/cornerdrag-left/cwd Save Tty D╎ /tmp/pardes-snap/cornerdrag-left/cwd Save Tty De
+|3: ls ╎ ls
+|4: w.txt ╎ w.txt
+|5: ╎
+|6: ╎ /tmp/pardes-snap/cornerdrag-left/cwd Save Tty De
+|7: ╎ ls
+|8: ╎ w.txt
|9: ╎
|10: ╎
|11: ╎
@@ -34,10 +35,10 @@
|13: ╎
|14: ╎
|15: ╎
-|16: /tmp/pardes-snap/cornerdrag-left/cwd Save New N╎
-|17: ls ╎
-|18: w.txt ╎
-|19: ╎
+|16: ╎
+|17: /tmp/pardes-snap/cornerdrag-left/cwd Save Tty D╎
+|18: ls ╎
+|19: w.txt ╎
|20: ╎
|21: ╎
|22: ╎
@@ -48,29 +49,28 @@
|27: ╎
|28: ╎
|29: ╎
-== snap hover-left-corner grid=100x30 cursor=54,8
-|4: ╎
-|15: ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
-== snap corner-drag grid=100x30 cursor=54,8
-|1: /tmp/pardes-snap/cornerdrag╎left/cwd Save New Ne /tmp/pardes-snap/cornerdrag-left/cwd Save New Ne
-|2: ls ╎ ls
-|3: w.txt ╎ w.txt
-|4: ╎
-|5: ╎ /tmp/pardes-snap/cornerdrag-left/cwd Save New Ne
-|6: ╎ ls
-|7: ╎ w.txt
-|8: ╎
+|30: ╎
+== snap hover-left-corner grid=100x31 cursor=54,9
+== snap corner-drag grid=100x31 cursor=54,9
+|1: New Tty Find Grep Joincol ╎ New Tty Find Grep Joincol
+|2: /tmp/pardes-snap/cornerdrag╎left/cwd Save Tty De /tmp/pardes-snap/cornerdrag-left/cwd Save Tty De
+|3: ls ╎ ls
+|4: w.txt ╎ w.txt
+|5: ╎
+|6: ╎ /tmp/pardes-snap/cornerdrag-left/cwd Save Tty De
+|7: ╎ ls
+|8: ╎ w.txt
|9: ╎
|10: ╎
-|11: ╎╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
-|12: ╎
+|11: ╎
+|12: ╎╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
|13: ╎
|14: ╎
|15: ╎
-|16: /tmp/pardes-snap/cornerdrag╎left/cwd Save New Ne
-|17: ls ╎
-|18: w.txt ╎
-|19: ╎
+|16: ╎
+|17: /tmp/pardes-snap/cornerdrag╎left/cwd Save Tty De
+|18: ls ╎
+|19: w.txt ╎
|20: ╎
|21: ╎
|22: ╎
@@ -81,11 +81,12 @@
|27: ╎
|28: ╎
|29: ╎
-== snap corner-done grid=100x30 cursor=34,15
-|1: /tmp/pardes-snap/cornerdrag- /tmp/pardes-snap/cornerdrag-left/cwd Save New Newtty Del Filter
-|2: ls ls
-|3: w.txt w.txt
-|4:
+|30: ╎
+== snap corner-done grid=100x31 cursor=34,16
+|1: New Tty Find Grep Joincol New Tty Find Grep Joincol
+|2: /tmp/pardes-snap/cornerdrag- /tmp/pardes-snap/cornerdrag-left/cwd Save Tty Del Togglettymode Filt
+|3: ls ls
+|4: w.txt w.txt
|5:
|6:
|7:
@@ -93,14 +94,14 @@
|9:
|10:
|11:
-|12: /tmp/pardes-snap/cornerdrag-left/cwd Save New Newtty Del Filter
-|13: ls
-|14: w.txt
-|15:
-|16: /tmp/pardes-snap/cornerdrag-
-|17: ls
-|18: w.txt
-|19:
+|12:
+|13: /tmp/pardes-snap/cornerdrag-left/cwd Save Tty Del Togglettymode Filt
+|14: ls
+|15: w.txt
+|16:
+|17: /tmp/pardes-snap/cornerdrag-
+|18: ls
+|19: w.txt
|20:
|21:
|22:
@@ -111,3 +112,4 @@
|27:
|28:
|29:
+|30:
diff --git a/test/snapshots/cornerdrag-left.snap b/test/snapshots/cornerdrag-left.snap
index c90dbc76..e76bfb89 100644
--- a/test/snapshots/cornerdrag-left.snap
+++ b/test/snapshots/cornerdrag-left.snap
@@ -8,7 +8,7 @@
# at ITS own row. The two corners on col 49 are then row 16 (col 0's seam, the
# one that already worked) and row 5 (col 1's, the one this script is about).
file w.txt x
-start 30 100 -n 3
+start 31 100 -n 3
wait 8000 w.txt
stable 700 20000
# a second pane in the RIGHT column
@@ -31,11 +31,11 @@ snap hover-left-corner
# grab col 1's corner and drag down-left: the column preview and col 1's row
# preview both follow the one mouse, the row dashes lying to the RIGHT of the v
# line because they are the right column's
-press left 50 5
-drag left 30 12
+press left 50 6
+drag left 30 13
stable 400 5000
snap corner-drag
-release left 30 12
+release left 30 13
motion 45 25
stable 500 8000
snap corner-done
diff --git a/test/snapshots/cornerdrag.golden b/test/snapshots/cornerdrag.golden
index cc709bd5..003bf0d8 100644
--- a/test/snapshots/cornerdrag.golden
+++ b/test/snapshots/cornerdrag.golden
@@ -1,6 +1,7 @@
-== snap hover-corner grid=100x30 cursor=4,4
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/cornerdrag/cwd Save New Newtty╎ /tmp/pardes-snap/cornerdrag/cwd Save New Newtty
+== snap hover-corner grid=100x31 cursor=4,5
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol ╎New Tty Find Grep Joincol
+| /tmp/pardes-snap/cornerdrag/cwd Save Tty Del To╎ /tmp/pardes-snap/cornerdrag/cwd Save Tty Del Tog
| ls ╎ ls
| w.txt ╎ w.txt
| ╎
@@ -14,8 +15,8 @@
| ╎
| ╎
| ╎
-|╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
-| /tmp/pardes-snap/cornerdrag/cwd Save New Newtty╎
+| ╎
+| /tmp/pardes-snap/cornerdrag/cwd Save Tty Del To╎
| ls ╎
| w.txt ╎
| ╎
@@ -29,11 +30,11 @@
| ╎
| ╎
| ╎
-== snap edge-drag grid=100x30 cursor=4,4
-|1: /tmp/pardes-snap/cornerdrag╎cwd Save New Newtty /tmp/pardes-snap/cornerdrag/cwd Save New Newtty
-|2: ls ╎ ls
-|3: w.txt ╎ w.txt
-|4: ╎
+== snap edge-drag grid=100x31 cursor=4,5
+|1: New Tty Find Grep Joincol ╎ New Tty Find Grep Joincol
+|2: /tmp/pardes-snap/cornerdrag╎cwd Save Tty Del Tog /tmp/pardes-snap/cornerdrag/cwd Save Tty Del Tog
+|3: ls ╎ ls
+|4: w.txt ╎ w.txt
|5: ╎
|6: ╎
|7: ╎
@@ -45,10 +46,10 @@
|13: ╎
|14: ╎
|15: ╎
-|16: /tmp/pardes-snap/cornerdrag╎cwd Save New Newtty
-|17: ls ╎
-|18: w.txt ╎
-|19: ╎
+|16: ╎
+|17: /tmp/pardes-snap/cornerdrag╎cwd Save Tty Del Tog
+|18: ls ╎
+|19: w.txt ╎
|20: ╎
|21: ╎
|22: ╎
@@ -59,11 +60,12 @@
|27: ╎
|28: ╎
|29: ╎
-== snap edge-done grid=100x30 cursor=4,4
-|1: /tmp/pardes-snap/cornerdrag/ /tmp/pardes-snap/cornerdrag/cwd Save New Newtty Del Filter
-|2: ls ls
-|3: w.txt w.txt
-|4:
+|30: ╎
+== snap edge-done grid=100x31 cursor=4,5
+|1: New Tty Find Grep Joincol New Tty Find Grep Joincol
+|2: /tmp/pardes-snap/cornerdrag/ /tmp/pardes-snap/cornerdrag/cwd Save Tty Del Togglettymode Filter Co
+|3: ls ls
+|4: w.txt w.txt
|5:
|6:
|7:
@@ -75,10 +77,10 @@
|13:
|14:
|15:
-|16: /tmp/pardes-snap/cornerdrag/
-|17: ls
-|18: w.txt
-|19:
+|16:
+|17: /tmp/pardes-snap/cornerdrag/
+|18: ls
+|19: w.txt
|20:
|21:
|22:
@@ -89,15 +91,16 @@
|27:
|28:
|29:
-== snap corner-drag grid=100x30 cursor=4,4
-|1: /tmp/pardes-snap/cornerdrag/ /tmp/pardes-snap/cornerdrag╎cwd Save New Newtty Del Filter
-|2: ls ls ╎
-|3: w.txt w.txt ╎
-|4: ╎
+|30:
+== snap corner-drag grid=100x31 cursor=4,5
+|1: New Tty Find Grep Joincol New Tty Find Grep Joincol ╎
+|2: /tmp/pardes-snap/cornerdrag/ /tmp/pardes-snap/cornerdrag╎cwd Save Tty Del Togglettymode Filter Co
+|3: ls ls ╎
+|4: w.txt w.txt ╎
|5: ╎
|6: ╎
-|7: ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
-|8: ╎
+|7: ╎
+|8: ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
|9: ╎
|10: ╎
|11: ╎
@@ -105,10 +108,10 @@
|13: ╎
|14: ╎
|15: ╎
-|16: /tmp/pardes-snap/cornerdrag/ ╎
-|17: ls ╎
-|18: w.txt ╎
-|19: ╎
+|16: ╎
+|17: /tmp/pardes-snap/cornerdrag/ ╎
+|18: ls ╎
+|19: w.txt ╎
|20: ╎
|21: ╎
|22: ╎
@@ -119,18 +122,19 @@
|27: ╎
|28: ╎
|29: ╎
-== snap corner-done grid=100x30 cursor=4,4
-|1: /tmp/pardes-snap/cornerdrag/cwd Save New Newtty Del Filter /tmp/pardes-snap/cornerdrag/cwd Save N
-|2: ls ls
-|3: w.txt w.txt
-|4:
+|30: ╎
+== snap corner-done grid=100x31 cursor=4,5
+|1: New Tty Find Grep Joincol New Tty Find Grep Joincol
+|2: /tmp/pardes-snap/cornerdrag/cwd Save Tty Del Togglettymode /tmp/pardes-snap/cornerdrag/cwd Save T
+|3: ls ls
+|4: w.txt w.txt
|5:
|6:
|7:
-|8: /tmp/pardes-snap/cornerdrag/cwd Save New Newtty Del Filter
-|9: ls
-|10: w.txt
-|11:
+|8:
+|9: /tmp/pardes-snap/cornerdrag/cwd Save Tty Del Togglettymode
+|10: ls
+|11: w.txt
|12:
|13:
|14:
@@ -149,18 +153,19 @@
|27:
|28:
|29:
-== snap clamp-x grid=100x30 cursor=4,4
-|1: /tmp/pardes-snap/cornerdrag/cwd Save New Newtty Del Filter /tmp/pardes-snap/cornerdrag/╎wd Save N
-|2: ls ls ╎
-|3: w.txt w.txt ╎
-|4: ╎
+|30:
+== snap clamp-x grid=100x31 cursor=4,5
+|1: New Tty Find Grep Joincol New Tty Find Grep Joincol ╎
+|2: /tmp/pardes-snap/cornerdrag/cwd Save Tty Del Togglettymode /tmp/pardes-snap/cornerdrag/╎wd Save T
+|3: ls ls ╎
+|4: w.txt w.txt ╎
|5: ╎
|6: ╎
|7: ╎
-|8: /tmp/pardes-snap/cornerdrag/cwd Save New Newtty Del Filter ╎
-|9: ls ╎
-|10: w.txt ╎
-|11: ╎
+|8: ╎
+|9: /tmp/pardes-snap/cornerdrag/cwd Save Tty Del Togglettymode ╎
+|10: ls ╎
+|11: w.txt ╎
|12: ╎
|13: ╎
|14: ╎
@@ -168,8 +173,8 @@
|16: ╎
|17: ╎
|18: ╎
-|19: ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
-|20: ╎
+|19: ╎
+|20: ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
|21: ╎
|22: ╎
|23: ╎
@@ -179,18 +184,19 @@
|27: ╎
|28: ╎
|29: ╎
-== snap clamp-y grid=100x30 cursor=4,4
-|1: /tmp/pardes-snap/cornerdrag/cwd Save New Newtty Del Filte╎ /tmp/pardes-snap/cornerdrag/cwd Save N
-|2: ls ╎ ls
-|3: w.txt ╎ w.txt
-|4: ╎
+|30: ╎
+== snap clamp-y grid=100x31 cursor=4,5
+|1: New Tty Find Grep Joincol ╎New Tty Find Grep Joincol
+|2: /tmp/pardes-snap/cornerdrag/cwd Save Tty Del Togglettymod╎ /tmp/pardes-snap/cornerdrag/cwd Save T
+|3: ls ╎ ls
+|4: w.txt ╎ w.txt
|5: ╎
|6: ╎
|7: ╎
-|8: /tmp/pardes-snap/cornerdrag/cwd Save New Newtty Del Filte╎
-|9: ls ╎
-|10: w.txt ╎
-|11: ╎
+|8: ╎
+|9: /tmp/pardes-snap/cornerdrag/cwd Save Tty Del Togglettymod╎
+|10: ls ╎
+|11: w.txt ╎
|12: ╎
|13: ╎
|14: ╎
@@ -207,13 +213,14 @@
|25: ╎
|26: ╎
|27: ╎
-|28: ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
-|29: ╎
-== snap clamp-done grid=100x30 cursor=4,4
-|1: /tmp/pardes-snap/cornerdrag/cwd Save New Newtty Del Filter /tmp/pardes-snap/cornerdrag/cwd Save N
-|2: ls ls
-|3: w.txt w.txt
-|4:
+|28: ╎
+|29: ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
+|30: ╎
+== snap clamp-done grid=100x31 cursor=4,5
+|1: New Tty Find Grep Joincol New Tty Find Grep Joincol
+|2: /tmp/pardes-snap/cornerdrag/cwd Save Tty Del Togglettymode /tmp/pardes-snap/cornerdrag/cwd Save T
+|3: ls ls
+|4: w.txt w.txt
|5:
|6:
|7:
@@ -238,4 +245,5 @@
|26:
|27:
|28:
-|29: /tmp/pardes-snap/cornerdrag/cwd Save New Newtty Del Filter
+|29:
+|30: /tmp/pardes-snap/cornerdrag/cwd Save Tty Del Togglettymode
diff --git a/test/snapshots/cornerdrag.snap b/test/snapshots/cornerdrag.snap
index 1ad5d5ae..0fbfe8a4 100644
--- a/test/snapshots/cornerdrag.snap
+++ b/test/snapshots/cornerdrag.snap
@@ -5,7 +5,7 @@
# The layout is windowops': col 0 (x 0, w 50) holds panes 0 (rows 1-15) and 1
# (rows 16-29), col 1 holds one pane. The corner is col 49, row 15.
file w.txt x
-start 30 100 -n 3
+start 31 100 -n 3
wait 8000 w.txt
stable 700 20000
# hover the corner: BOTH hints light, before anything is grabbed
@@ -15,37 +15,37 @@ snap hover-corner
# CONTROL: the same vertical edge ten rows off the crossing is a plain edge.
# The identical diagonal drag moves the column and nothing else — pane 0 still
# ends on row 15, and the preview is one dash, not two
-press left 50 6
-drag left 30 24
+press left 50 7
+drag left 30 25
stable 400 5000
snap edge-drag
-release left 30 24
+release left 30 25
motion 45 25
stable 500 8000
snap edge-done
# the corner itself, now at col 0's new last col (29) and still row 15: drag it
# up and to the right and both boundaries follow the one mouse
-press left 30 16
-drag left 60 8
+press left 30 17
+drag left 60 9
stable 400 5000
snap corner-drag
-release left 60 8
+release left 60 9
motion 45 25
stable 500 8000
snap corner-done
# clamp interaction, half one: shove the corner off the right edge while
# staying mid-height. The column preview parks at its MINW stop; the row
# preview keeps tracking the mouse exactly
-press left 60 8
-drag left 99 20
+press left 60 9
+drag left 99 21
stable 400 5000
snap clamp-x
# half two, the mirror: below the bottom at mid-width. Now the ROW preview
# parks (the lower pane keeps its tag row) and the COLUMN keeps tracking
-drag left 60 30
+drag left 60 31
stable 400 5000
snap clamp-y
-release left 60 30
+release left 60 31
motion 45 25
stable 500 8000
snap clamp-done
diff --git a/test/snapshots/cursorline.golden b/test/snapshots/cursorline.golden
index 9f503745..161655c8 100644
--- a/test/snapshots/cursorline.golden
+++ b/test/snapshots/cursorline.golden
@@ -1,55 +1,57 @@
-== snap top grid=150x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/cursorline/cwd/cur.txt Save New Newtty Del /tmp/pardes-snap/cursorline/cwd Save New Newtty Del Filter
-| 1 line 1 ls
-| 2 line 2 cur.txt
+== snap top grid=150x31 cursor=7,7
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/cursorline/cwd Save Tty Del Togglettymode Filter Collaps /tmp/pardes-snap/cursorline/cwd Save Tty Del Togglettymode Filter Collaps
+| ls ls
+| cur.txt cur.txt
+|
+| /tmp/pardes-snap/cursorline/cwd/cur.txt Save Tty Del Collapse
+| 1 line 1
+| 2 line 2
| 3 line 3
| 4 line 4
| 5 line 5
-|╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
-| /tmp/pardes-snap/cursorline/cwd Save New Newtty Del Filter
-| ls
-| cur.txt
-|
-|
-|
-| cur.txt
-|
-| /tmp/pardes-snap/cursorline/cwd Save New Newtty Del Filter
+| 6 line 6
+| 7 line 7
+| 8 line 8
+| 9 line 9
+| 10 line 10
+| /tmp/pardes-snap/cursorline/cwd Save Tty Del Togglettymode Filter Collaps
| ls
| cur.txt
-== style top grid=150x30
-|0: 0-74 #949494,#121212, 75-149 d,#121212,
-|1: 0-1 #ffffff,#626262, 2-60 #949494,#121212, 61-74 d,#121212, 75-76 #ffffff,#262626, 77-134 #949494,#121212, 135-149 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-12 #bdbdbd,#080808, 13-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|3: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|4: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|5: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|6: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|7: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|8: 0-1 #ffffff,#262626, 2-60 #949494,#121212, 61-74 d,#121212, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|11: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-10 #bdbdbd,#080808, 11-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|16: 0-1 #ffffff,#262626, 2-60 #949494,#121212, 61-74 d,#121212, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|19: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|29: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-== snap down3 grid=150x30 cursor=7,5
-== style down3 grid=150x30
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|5: 0-0 d,#121212, 1-1 d,#080808, 2-6 #949494,#121212, 7-12 #bdbdbd,#080808, 13-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
+== style top grid=150x31
+|0: 0-70 #b2c3b8,#1d2824, 71-149 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-74 d,#26362d, 75-99 #b2c3b8,#1d2824, 100-149 d,#1d2824,
+|2: 0-1 #ffffff,#4c6356, 2-74 #b2c3b8,#1d2824, 75-76 #ffffff,#4c6356, 77-149 #b2c3b8,#1d2824,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|5: 0-0 d,#637f6a, 1-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|6: 0-1 #000000,#adcc91, 2-62 #becfc4,#26362d, 63-74 d,#26362d, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-12 #e5eee5,#0d1410, 13-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|11: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|12: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|13: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|14: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|15: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|16: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|17: 0-1 #ffffff,#4c6356, 2-74 #b2c3b8,#1d2824, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|20: 0-0 d,#637f6a, 1-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+== snap down3 grid=150x31 cursor=7,10
+== style down3 grid=150x31
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-12 #e5eee5,#0d1410, 13-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
diff --git a/test/snapshots/cursorline.snap b/test/snapshots/cursorline.snap
index 5519287e..fab438f1 100644
--- a/test/snapshots/cursorline.snap
+++ b/test/snapshots/cursorline.snap
@@ -1,19 +1,19 @@
-# cursor-line gutter: the line number on the cursor's row takes the tag style
+# cursor-line gutter: the line number on the cursor's row gets quiet bold ink
# and follows modal movement (gg to the top, then jjj down three lines)
lines cur.txt 20
-start 30 150 -n 3
+start 31 150 -n 3
wait 8000 cur.txt
stable 700 20000
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key i
text cur.txt
key esc
settle 100
stable 400 5000
-press right 6 8
-release right 6 8
+press right 6 9
+release right 6 9
stable 700 15000
key g g
stable 400 5000
diff --git a/test/snapshots/doccol.golden b/test/snapshots/doccol.golden
index 0f9b5c7e..318ac564 100644
--- a/test/snapshots/doccol.golden
+++ b/test/snapshots/doccol.golden
@@ -1,20 +1,21 @@
-== snap boot grid=100x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/doccol/cwd/a.txt Save New Newtt /tmp/pardes-snap/doccol/cwd Save New Newtty Del
+== snap boot grid=100x31 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/doccol/cwd/a.txt Save Tty Del C /tmp/pardes-snap/doccol/cwd Save Tty Del Togglet
| 1 AAA ls
| a.txt b.txt c.txt
-== snap two-docs grid=100x30 cursor=7,17
-|16: /tmp/pardes-snap/doccol/cwd/b.txt Save New Newtt
-|17: 1 BBB
-|18: 2 B-TWO
-== snap moved grid=100x30 cursor=57,20
-|16:
+== snap two-docs grid=100x31 cursor=7,18
+|17: /tmp/pardes-snap/doccol/cwd/b.txt Save Tty Del C
+|18: 1 BBB
+|19: 2 B-TWO
+== snap moved grid=100x31 cursor=57,21
|17:
|18:
-|19: /tmp/pardes-snap/doccol/cwd/b.txt Save New Newtt
-|20: 1 BBB
-|21: 2 B-TWO
-== snap worked grid=100x30 cursor=59,21
-== snap third grid=100x30 cursor=57,26
-|25: /tmp/pardes-snap/doccol/cwd/c.txt Save New Newtt
-|26: 1 CCC
+|19:
+|20: /tmp/pardes-snap/doccol/cwd/b.txt Save Tty Del C
+|21: 1 BBB
+|22: 2 B-TWO
+== snap worked grid=100x31 cursor=59,22
+== snap third grid=100x31 cursor=57,27
+|26: /tmp/pardes-snap/doccol/cwd/c.txt Save Tty Del C
+|27: 1 CCC
diff --git a/test/snapshots/doccol.snap b/test/snapshots/doccol.snap
index 6b722450..677d5dff 100644
--- a/test/snapshots/doccol.snap
+++ b/test/snapshots/doccol.snap
@@ -13,7 +13,7 @@ file c.txt CCC
# boot used to hand over — and SPC w h comes back to a.txt, which is where the
# boot left focus. (`New`/`Newcol` open an empty +New scratch now, not a
# shell, so the shell has to be asked for by name.)
-start 30 100 a.txt
+start 31 100 a.txt
wait 8000 AAA
stable 700 20000
key a-n
@@ -25,31 +25,31 @@ stable 400 5000
snap boot
# look b.txt in the shell's ls output: the second doc splits the first, so
# both docs are in the left column and a.txt is the lower-numbered pane
-press right 60 4
-release right 60 4
+press right 60 5
+release right 60 5
wait 10000 BBB
stable 700 20000
snap two-docs
# drag b.txt's layout box (the gutter cells of its tag row) into the right
# column, below the shell
-press left 1 17
-drag left 75 20
-release left 75 20
+press left 1 18
+drag left 75 21
+release left 75 21
stable 700 15000
snap moved
# use a.txt, then b.txt: what counts is the doc last USED, so a.txt being the
# most recent for a moment must not survive the click into b.txt
-press left 5 3
-release left 5 3
+press left 5 4
+release left 5 4
stable 400 5000
-press left 60 21
-release left 60 21
+press left 60 22
+release left 60 22
key j
stable 400 5000
snap worked
# look c.txt from the shell: below b.txt, in the right column
-press right 67 4
-release right 67 4
+press right 67 5
+release right 67 5
wait 10000 CCC
stable 700 20000
snap third
diff --git a/test/snapshots/dump.golden b/test/snapshots/dump.golden
index fbbfd92b..18c30327 100644
--- a/test/snapshots/dump.golden
+++ b/test/snapshots/dump.golden
@@ -2,20 +2,30 @@
.{
.magic = "pardes-dump",
.version = 1,
- .screen = .{ .cols = 100, .rows = 30 },
+ .screen = .{ .cols = 100, .rows = 31 },
.active = 0,
- .topbar = "New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill",
- .theme = "helix",
- .columns = .{ .{ .weight = 1, .panes = .{ 0, 1 } }, .{ .weight = 1, .panes = .{2} } },
+ .topbar = "Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill",
+ .topbar_custom = null,
+ .theme = "orchard",
+ .columns = .{ .{
+ .tag = null,
+ .weight = 1,
+ .panes = .{ 0, 1 },
+ }, .{
+ .tag = null,
+ .weight = 1,
+ .panes = .{2},
+ } },
.panes = .{
.{
.kind = .terminal,
- .tag = "/tmp/pardes-snap/dump/cwd Save New Newtty Del Filter",
+ .tag = "/tmp/pardes-snap/dump/cwd Save Tty Del Togglettymode Filter Collapse",
.body = "ls\nd.txt\n\n\n\n typed-marker\n\n\n\n\n\n\n\n",
.scroll = 0,
.cols = 48,
.rows = 14,
.vweight = 1,
+ .collapsed = false,
.tag_tail = null,
.terminal = .{
.cwd = "/tmp/pardes-snap/dump/cwd",
@@ -28,12 +38,13 @@
},
.{
.kind = .terminal,
- .tag = "/tmp/pardes-snap/dump/cwd Save New Newtty Del Filter",
+ .tag = "/tmp/pardes-snap/dump/cwd Save Tty Del Togglettymode Filter Collapse",
.body = "ls\nd.txt\n\n\n\n\n\n\n\n\n\n\n",
.scroll = 0,
.cols = 48,
.rows = 13,
.vweight = 1,
+ .collapsed = false,
.tag_tail = null,
.terminal = .{
.cwd = "/tmp/pardes-snap/dump/cwd",
@@ -46,12 +57,13 @@
},
.{
.kind = .terminal,
- .tag = "/tmp/pardes-snap/dump/cwd Save New Newtty Del Filter",
+ .tag = "/tmp/pardes-snap/dump/cwd Save Tty Del Togglettymode Filter Collapse",
.body = "ls\nd.txt\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
.scroll = 0,
.cols = 48,
.rows = 28,
.vweight = 1,
+ .collapsed = false,
.tag_tail = null,
.terminal = .{
.cwd = "/tmp/pardes-snap/dump/cwd",
diff --git a/test/snapshots/dump.snap b/test/snapshots/dump.snap
index ddac01a2..485c4932 100644
--- a/test/snapshots/dump.snap
+++ b/test/snapshots/dump.snap
@@ -1,10 +1,10 @@
# Dump serializes the session to this fixture's $DUMP path.
file d.txt x
-start 30 100 -n 3
+start 31 100 -n 3
wait 8000 d.txt
stable 700 20000
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key i
text typed-marker
diff --git a/test/snapshots/edit.golden b/test/snapshots/edit.golden
index c37c9aef..17c86be0 100644
--- a/test/snapshots/edit.golden
+++ b/test/snapshots/edit.golden
@@ -1,6 +1,7 @@
-== snap inserted grid=100x30 cursor=16,9
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/edit/cwd Save New Newtty Del Fi /tmp/pardes-snap/edit/cwd Save New Newtty Del Fi
+== snap inserted grid=100x31 cursor=16,10
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/edit/cwd Save Tty Del Toggletty /tmp/pardes-snap/edit/cwd Save Tty Del Toggletty
| ls ls
| e.txt e.txt
|
@@ -15,37 +16,38 @@
|
|
|
-| /tmp/pardes-snap/edit/cwd Save New Newtty Del Fi
+| /tmp/pardes-snap/edit/cwd Save Tty Del Toggletty
| ls
| e.txt
-== style inserted grid=100x30
-|0: 0-74 #949494,#121212, 75-99 d,#121212,
-|1: 0-1 #ffffff,#626262, 2-49 #949494,#121212, 50-51 #ffffff,#262626, 52-99 #949494,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|4: 0-0 d,#444444, 1-49 d,#080808, 50-50 d,#444444, 51-99 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|8: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-15 #bdbdbd,#080808, 16-49 d,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|11: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|16: 0-1 #ffffff,#262626, 2-49 #949494,#121212, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|19: 0-0 d,#444444, 1-49 d,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|29: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
+== style inserted grid=100x31
+|0: 0-70 #b2c3b8,#1d2824, 71-99 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-49 d,#26362d, 50-74 #b2c3b8,#1d2824, 75-99 d,#1d2824,
+|2: 0-1 #000000,#adcc91, 2-49 #becfc4,#26362d, 50-51 #ffffff,#4c6356, 52-99 #b2c3b8,#1d2824,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|5: 0-0 d,#637f6a, 1-49 d,#0d1410, 50-50 d,#637f6a, 51-99 d,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-15 #e5eee5,#0d1410, 16-49 d,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|17: 0-1 #ffffff,#4c6356, 2-49 #b2c3b8,#1d2824, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|20: 0-0 d,#637f6a, 1-49 d,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
diff --git a/test/snapshots/edit.snap b/test/snapshots/edit.snap
index 5a0b610e..f1234741 100644
--- a/test/snapshots/edit.snap
+++ b/test/snapshots/edit.snap
@@ -1,10 +1,10 @@
# insert-mode splice: click into a body row, type, escape back to normal
file e.txt x
-start 30 100 -n 3
+start 31 100 -n 3
wait 8000 e.txt
stable 700 20000
-press left 5 10
-release left 5 10
+press left 5 11
+release left 5 11
stable 400 8000
key i
text hello-insert
diff --git a/test/snapshots/exec-bigdrag.golden b/test/snapshots/exec-bigdrag.golden
index 48ea1a6a..6b86db0d 100644
--- a/test/snapshots/exec-bigdrag.golden
+++ b/test/snapshots/exec-bigdrag.golden
@@ -1,6 +1,7 @@
-== snap alive grid=200x60 cursor=119,37
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/exec-bigdrag/cwd Save New Newtty Del Filter /tmp/pardes-snap/exec-bigdrag/cwd Save New Newtty Del Filter
+== snap alive grid=200x61 cursor=119,38
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/exec-bigdrag/cwd Save Tty Del Togglettymode Filter Collapse /tmp/pardes-snap/exec-bigdrag/cwd Save Tty Del Togglettymode Filter Collapse
| ls bash: line: command not found
| big.txt 4line 2705line 2706line 2707line 2708line 2709line 2710line 2711line 2712line 2713line 2714lin
| bash: 4line: command not found
@@ -30,7 +31,7 @@
| bash: 2835line: command not found
| 2846line 2847line 2848line 2849line 2850line 2851line 2852line 2853line 2854line 2855line 285
| bash: 2846line: command not found
-| /tmp/pardes-snap/exec-bigdrag/cwd Save New Newtty Del Filter e 2857line 2858line 2859line 2860line 2861line 2862line 2863line 2864line 2865line 2866line 28
+| /tmp/pardes-snap/exec-bigdrag/cwd Save Tty Del Togglettymode Filter Collapse e 2857line 2858line 2859line 2860line 2861line 2862line 2863line 2864line 2865line 2866line 28
| ls bash: e: command not found
| big.txt ne 2868line 2869line 2870line 2871line 2872line 2873line 2874line 2875line 2876line 2877line 2
| bash: ne: command not found
diff --git a/test/snapshots/exec-bigdrag.snap b/test/snapshots/exec-bigdrag.snap
index 91ff1727..ce7aef25 100644
--- a/test/snapshots/exec-bigdrag.snap
+++ b/test/snapshots/exec-bigdrag.snap
@@ -3,38 +3,38 @@
# 64-slot effect ring and panic the core (assert in emit). Needs a big grid:
# the selection must exceed 64*64 bytes, more than any 30x100 pane can hold.
lines big.txt 3000
-start 60 200 -n 3
+start 61 200 -n 3
wait 8000 big.txt
stable 500 20000
-press left 105 8
-release left 105 8
+press left 105 9
+release left 105 9
stable 300 5000
key i
text tr -d '\n' < big.txt
key esc
settle 100
-press middle 105 8
-drag middle 126 8
-release middle 126 8
+press middle 105 9
+drag middle 126 9
+release middle 126 9
stable 800 30000
# the accidental sweep over the full-height right pane, then release
-press middle 105 4
-drag middle 150 30
-drag middle 198 58
-release middle 198 58
+press middle 105 5
+drag middle 150 31
+drag middle 198 59
+release middle 198 59
stable 500 8000
stable 800 30000
# still alive: type and execute a marker command
-press left 105 40
-release left 105 40
+press left 105 41
+release left 105 41
stable 300 5000
key i
text echo alive-o''k
key esc
settle 100
-press middle 105 40
-drag middle 119 40
-release middle 119 40
+press middle 105 41
+drag middle 119 41
+release middle 119 41
wait 10000 alive-ok
stable 800 20000
snap alive
diff --git a/test/snapshots/exec.golden b/test/snapshots/exec.golden
index 610b5449..849c8e0e 100644
--- a/test/snapshots/exec.golden
+++ b/test/snapshots/exec.golden
@@ -1,6 +1,7 @@
-== snap exec grid=100x30 cursor=16,7
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/exec/cwd Save New Newtty Del Fi /tmp/pardes-snap/exec/cwd Save New Newtty Del Fi
+== snap exec grid=100x31 cursor=16,8
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/exec/cwd Save Tty Del Toggletty /tmp/pardes-snap/exec/cwd Save Tty Del Toggletty
| ls ls
| e.txt e.txt
|
@@ -15,20 +16,20 @@
|
|
|
-| /tmp/pardes-snap/exec/cwd Save New Newtty Del Fi
+| /tmp/pardes-snap/exec/cwd Save Tty Del Toggletty
| ls
| e.txt
-== snap kept grid=100x30 cursor=6,2
-|2: ZZARG ls
-|3: ./c.sh e.txt
+== snap kept grid=100x31 cursor=6,3
+|3: ZZARG ls
+|4: ./c.sh e.txt
+|9:
+== snap chord grid=100x31 cursor=6,3
+|9: CHORDARG:ZZARG
+== snap deleted grid=100x31 cursor=4,5
+|3: ls ls
+|4: e.txt e.txt
|8:
-== snap chord grid=100x30 cursor=6,2
-|8: CHORDARG:ZZARG
-== snap deleted grid=100x30 cursor=4,4
-|2: ls ls
-|3: e.txt e.txt
-|7:
-|8:
-|16:
+|9:
|17:
|18:
+|19:
diff --git a/test/snapshots/exec.snap b/test/snapshots/exec.snap
index 7baae645..38f74e35 100644
--- a/test/snapshots/exec.snap
+++ b/test/snapshots/exec.snap
@@ -2,20 +2,20 @@
# the middle drag captures the kept left selection as a trailing argument;
# middle-click Del on the pane tag closes the pane
file e.txt x
-start 30 100 -n 3
+start 31 100 -n 3
wait 8000 e.txt
stable 700 20000
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key i
text echo MID''OK
key esc
settle 100
stable 400 5000
-press middle 5 8
-drag middle 16 8
-release middle 16 8
+press middle 5 9
+drag middle 16 9
+release middle 16 9
wait 10000 MIDOK
stable 700 10000
snap exec
@@ -30,18 +30,18 @@ wait 10000 ./c.sh
stable 700 10000
key c-b
stable 600 8000
-press left 3 3
-drag left 7 3
-release left 7 3
+press left 3 4
+drag left 7 4
+release left 7 4
stable 400 5000
snap kept
-send \x1b[<1;4;4M\x1b[<0;4;4M\x1b[<1;4;4m
+send \x1b[<1;4;5M\x1b[<0;4;5M\x1b[<1;4;5m
wait 10000 CHORDARG:ZZARG
stable 700 10000
snap chord
# middle-click Del in THIS pane's tag: row 2 carries both panes' tags, so the
# occurrence is spelled out rather than left to the leftmost-match default
-press middle @Del#1 2
-release middle @Del#1 2
+press middle @Del#1 3
+release middle @Del#1 3
stable 700 10000
snap deleted
diff --git a/test/snapshots/fileedit.golden b/test/snapshots/fileedit.golden
index 5976de1d..bf0eccdb 100644
--- a/test/snapshots/fileedit.golden
+++ b/test/snapshots/fileedit.golden
@@ -1,35 +1,44 @@
-== snap edited grid=150x30 cursor=17,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/fileedit/cwd/f.txt * Save New Newtty Del /tmp/pardes-snap/fileedit/cwd Save New Newtty Del Filter
-| 1 liEDIT''MEne 1 ls
-| 2 line 2 f.txt
+== snap edited grid=150x31 cursor=17,7
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/fileedit/cwd Save Tty Del Togglettymode Filter Collapse /tmp/pardes-snap/fileedit/cwd Save Tty Del Togglettymode Filter Collapse
+| ls ls
+| f.txt f.txt
+|
+| /tmp/pardes-snap/fileedit/cwd/f.txt * Save Tty Del Collapse
+| 1 liEDIT''MEne 1
+| 2 line 2
| 3 line 3
| 4 line 4
| 5 line 5
| 6 line 6
-| /tmp/pardes-snap/fileedit/cwd Save New Newtty Del Filter
-| ls
-| f.txt
-|
-|
-|
-| f.txt
-|
-| /tmp/pardes-snap/fileedit/cwd Save New Newtty Del Filter
+| 7 line 7
+| 8 line 8
+| 9 line 9
+| 10 line 10
+| /tmp/pardes-snap/fileedit/cwd Save Tty Del Togglettymode Filter Collapse
| ls
| f.txt
-== snap deleted grid=150x30 cursor=7,3
-|3: 2 line 3 f.txt
-|4: 3 line 4
-|5: 4 line 5
-|6: 5 line 6
-|7: 6 line 7
-== snap undone grid=150x30 cursor=13,3
-|3: 2 line 2 f.txt
-|4: 3 line 3
-|5: 4 line 4
-|6: 5 line 5
-|7: 6 line 6
+== snap deleted grid=150x31 cursor=7,8
+|8: 2 line 3
+|9: 3 line 4
+|10: 4 line 5
+|11: 5 line 6
+|12: 6 line 7
+|13: 7 line 8
+|14: 8 line 9
+|15: 9 line 10
+|16: 10 line 11
+== snap undone grid=150x31 cursor=13,8
+|8: 2 line 2
+|9: 3 line 3
+|10: 4 line 4
+|11: 5 line 5
+|12: 6 line 6
+|13: 7 line 7
+|14: 8 line 8
+|15: 9 line 9
+|16: 10 line 10
== file saved
liEDIT''MEne 1
line 2
diff --git a/test/snapshots/fileedit.snap b/test/snapshots/fileedit.snap
index 46e6c787..8b924ebd 100644
--- a/test/snapshots/fileedit.snap
+++ b/test/snapshots/fileedit.snap
@@ -1,22 +1,22 @@
# file panes: modal editing on real content, undo, Save writes to disk
lines f.txt 20
-start 30 150 -n 3
+start 31 150 -n 3
wait 8000 f.txt
stable 700 20000
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key i
text f.txt
key esc
settle 100
-press right 6 8
-release right 6 8
+press right 6 9
+release right 6 9
wait 10000 line 3
stable 700 15000
# edit line 1: click it, insert, esc
-press left 10 3
-release left 10 3
+press left 10 8
+release left 10 8
stable 400 5000
key i
text EDIT''ME
@@ -33,9 +33,8 @@ snap deleted
key u
stable 400 5000
snap undone
-# Save through the file pane's own tag. The local-column split contract keeps
-# this source column narrow, so its tail is initially clipped; `:` focuses that
-# same tag and `w` reveals/selects Save before the ordinary execute key runs it.
+# Save through the file pane's own tag: `:` focuses that same tag and `w`
+# selects Save before the ordinary execute key runs it.
key :
stable 400 5000
key w tab
diff --git a/test/snapshots/filewatch.golden b/test/snapshots/filewatch.golden
index e2c8a598..6eca9bca 100644
--- a/test/snapshots/filewatch.golden
+++ b/test/snapshots/filewatch.golden
@@ -1,6 +1,7 @@
-== snap edited grid=210x30 cursor=15,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/filewatch/cwd/w.txt * Save New Newtty Del /tmp/pardes-snap/filewatch/cwd Save New Newtty Del Filter
+== snap edited grid=210x31 cursor=15,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/filewatch/cwd/w.txt * Save Tty Del Collapse /tmp/pardes-snap/filewatch/cwd Save Tty Del Togglettymode Filter Collapse
| 1 liMYEDITne 1 ls
| 2 line 2 sub w.txt
| 3 /tmp/pardes-snap/filewatch/cwd/sub/s.txt
@@ -15,7 +16,7 @@
| 12 line 12
| 13
|
-| /tmp/pardes-snap/filewatch/cwd/sub/s.txt Save New Newtty Del
+| /tmp/pardes-snap/filewatch/cwd/sub/s.txt Save Tty Del Collapse
| 1 line 1
| 2 line 2
| 3 line 3
@@ -25,47 +26,47 @@
| 7 line 7
| 8 line 8
| 9
-== snap reloaded grid=210x30 cursor=15,2
-|1: /tmp/pardes-snap/filewatch/cwd/w.txt Save New Newtty Del /tmp/pardes-snap/filewatch/cwd Save New Newtty Del Filter
-|2: 1 EXTERNAL ls
-|3: 2 sub w.txt
-|4:
+== snap reloaded grid=210x31 cursor=15,3
+|2: /tmp/pardes-snap/filewatch/cwd/w.txt Save Tty Del Collapse /tmp/pardes-snap/filewatch/cwd Save Tty Del Togglettymode Filter Collapse
+|3: 1 EXTERNAL ls
+|4: 2 sub w.txt
|5:
|6:
-|7: w.txt
-|8:
+|7:
+|8: w.txt
|9:
|10:
|11:
|12:
|13:
|14:
-|15: --:--:-- reloaded /tmp/pardes-snap/filewatch/cwd/w.txt
-== snap reloaded_sub grid=210x30 cursor=15,2
-|17: 1 RENAMED
-|18: 2
-|19:
+|15:
+|16: --:--:-- reloaded /tmp/pardes-snap/filewatch/cwd/w.txt
+== snap reloaded_sub grid=210x31 cursor=15,3
+|18: 1 RENAMED
+|19: 2
|20:
|21:
|22:
|23:
|24:
|25:
-|29: --:--:-- reloaded /tmp/pardes-snap/filewatch/cwd/sub/s.txt
-== snap undone grid=210x30 cursor=15,2
-|1: /tmp/pardes-snap/filewatch/cwd/w.txt * Save New Newtty Del /tmp/pardes-snap/filewatch/cwd Save New Newtty Del Filter
-|2: 1 liMYEDITne 1 ls
-|3: 2 line 2 sub w.txt
-|4: 3 /tmp/pardes-snap/filewatch/cwd/sub/s.txt
-|5: 4 line 4
-|6: 5 line 5
-|7: 6 line 6 w.txt
-|8: 7 line 7
-|9: 8 line 8
-|10: 9 line 9
-|11: 10 line 10
-|12: 11 line 11
-|13: 12 line 12
-|14: 13
-|15:
-|29:
+|26:
+|30: --:--:-- reloaded /tmp/pardes-snap/filewatch/cwd/sub/s.txt
+== snap undone grid=210x31 cursor=15,3
+|2: /tmp/pardes-snap/filewatch/cwd/w.txt * Save Tty Del Collapse /tmp/pardes-snap/filewatch/cwd Save Tty Del Togglettymode Filter Collapse
+|3: 1 liMYEDITne 1 ls
+|4: 2 line 2 sub w.txt
+|5: 3 /tmp/pardes-snap/filewatch/cwd/sub/s.txt
+|6: 4 line 4
+|7: 5 line 5
+|8: 6 line 6 w.txt
+|9: 7 line 7
+|10: 8 line 8
+|11: 9 line 9
+|12: 10 line 10
+|13: 11 line 11
+|14: 12 line 12
+|15: 13
+|16:
+|30:
diff --git a/test/snapshots/filewatch.snap b/test/snapshots/filewatch.snap
index 25862cb7..a27740f0 100644
--- a/test/snapshots/filewatch.snap
+++ b/test/snapshots/filewatch.snap
@@ -18,30 +18,30 @@
dirmk sub
file w.txt line 1\nline 2\n/tmp/pardes-snap/filewatch/cwd/sub/s.txt\nline 4\nline 5\nline 6\nline 7\nline 8\nline 9\nline 10\nline 11\nline 12\n
lines sub/s.txt 8
-start 30 210 -n 1
+start 31 210 -n 1
wait 8000 w.txt
stable 700 20000
# open w.txt as a file pane: type the name into the shell, right-click it
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key i
text w.txt
key esc
settle 100
-press right 6 8
-release right 6 8
+press right 6 9
+release right 6 9
wait 10000 line 4
stable 700 15000
# ...and open sub/s.txt from the path sitting on line 3 of that pane, so the
# second watched pane is in a DIFFERENT directory from the first
-press right 20 5
-release right 20 5
+press right 20 6
+release right 20 6
wait 10000 line 8
stable 700 15000
# an UNSAVED edit on line 1 of w.txt
-press left 10 3
-release left 10 3
+press left 10 4
+release left 10 4
stable 400 5000
key i
text MYEDIT
@@ -59,8 +59,8 @@ wait 10000 RENAMED
stable 700 10000
snap reloaded_sub
# back in the file pane: one undo and the unsaved edit is there again
-press left 10 3
-release left 10 3
+press left 10 4
+release left 10 4
stable 400 5000
key u
stable 400 5000
diff --git a/test/snapshots/find.golden b/test/snapshots/find.golden
index 96e5a26a..a8d072f3 100644
--- a/test/snapshots/find.golden
+++ b/test/snapshots/find.golden
@@ -1,6 +1,7 @@
-== snap group grid=120x40 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/find/cwd/here.txt Save New Newtty Del
+== snap group grid=120x41 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/find/cwd/here.txt Save Tty Del Collapse
| 1 Find
|
|
@@ -39,83 +40,84 @@
|
|
| SPC f
-== snap armed grid=120x40 cursor=9,39
-|39: Find /
-== snap typing grid=120x40 cursor=12,39
-|39: Find /zqm
-== snap results grid=120x40 cursor=7,2
-|36: /tmp/pardes-snap/find/cwd/+Search Save New Newtty Del
-|37: 1 sub/ZQMARK-beta.txt
+== snap armed grid=120x41 cursor=9,40
+|40: Find /
+== snap typing grid=120x41 cursor=12,40
+|40: Find /zqm
+== snap results grid=120x41 cursor=7,3
+|37: /tmp/pardes-snap/find/cwd/+Search Save Tty Del Collapse
+|38: 1 sub/ZQMARK-beta.txt
+|39: 2 sub/nest/zqmark-gamma.txt
+|40: 3 zqmark-alpha.txt
+== snap first grid=120x41 cursor=7,21
+|20: /tmp/pardes-snap/find/cwd/sub/ZQMARK-beta.txt Save Tty Del Collapse
+|21: 1 beta body
+== style first grid=120x41
+|0: 0-70 #b2c3b8,#1d2824, 71-119 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-119 d,#26362d,
+|2: 0-1 #ffffff,#4c6356, 2-57 #b2c3b8,#1d2824, 58-119 d,#1d2824,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-119 d,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|17: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|20: 0-1 #000000,#adcc91, 2-68 #becfc4,#26362d, 69-119 d,#26362d,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-15 #e5eee5,#0d1410, 16-119 d,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|31: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|32: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|33: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|34: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|35: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|36: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-119 d,#0d1410,
+|37: 0-1 #ffffff,#4c6356, 2-56 #b2c3b8,#1d2824, 57-119 d,#1d2824,
+|38: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-25 #e5eee5,#0d1410, 26-119 d,#0d1410,
+|39: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-31 #e5eee5,#0d1410, 32-119 d,#0d1410,
+|40: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-22 #e5eee5,#0d1410, 23-119 d,#0d1410,
+== snap second grid=120x41 cursor=7,30
+|29: /tmp/pardes-snap/find/cwd/sub/nest/zqmark-gamma.txt Save Tty Del Collapse
+|30: 1 gamma body
+== snap third grid=120x41 cursor=7,34
+|33: /tmp/pardes-snap/find/cwd/zqmark-alpha.txt Save Tty Del Collapse
+|34: 1 alpha body
|38: 2 sub/nest/zqmark-gamma.txt
|39: 3 zqmark-alpha.txt
-== snap first grid=120x40 cursor=7,20
-|19: /tmp/pardes-snap/find/cwd/sub/ZQMARK-beta.txt Save New Newtty Del
-|20: 1 beta body
-== style first grid=120x40
-|0: 0-74 #949494,#121212, 75-119 d,#121212,
-|1: 0-1 #ffffff,#262626, 2-99 #949494,#121212, 100-119 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-119 d,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|8: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|11: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|16: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|19: 0-1 #ffffff,#626262, 2-99 #949494,#121212, 100-119 d,#121212,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-15 #bdbdbd,#080808, 16-119 d,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|29: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|30: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|31: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|32: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|33: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|34: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|35: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-119 d,#080808,
-|36: 0-1 #ffffff,#262626, 2-99 #949494,#121212, 100-119 d,#121212,
-|37: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-25 #bdbdbd,#080808, 26-119 d,#080808,
-|38: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-31 #bdbdbd,#080808, 32-119 d,#080808,
-|39: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-22 #bdbdbd,#080808, 23-119 d,#080808,
-== snap second grid=120x40 cursor=7,29
-|28: /tmp/pardes-snap/find/cwd/sub/nest/zqmark-gamma.txt Save New Newtty Del
-|29: 1 gamma body
-== snap third grid=120x40 cursor=7,33
-|32: /tmp/pardes-snap/find/cwd/zqmark-alpha.txt Save New Newtty Del
-|33: 1 alpha body
-|37: 2 sub/nest/zqmark-gamma.txt
-|38: 3 zqmark-alpha.txt
-|39: 4
-== snap back grid=120x40 cursor=7,29
-|37: 1 sub/ZQMARK-beta.txt
+|40: 4
+== snap back grid=120x41 cursor=7,30
+|38: 1 sub/ZQMARK-beta.txt
+|39: 2 sub/nest/zqmark-gamma.txt
+|40: 3 zqmark-alpha.txt
+== snap word grid=120x41 cursor=7,30
+|19: Find /
+== snap cancel grid=120x41 cursor=7,39
+== snap nomatch grid=120x41 cursor=7,39
+|2: /tmp/pardes-snap/find/cwd/here.txt Save Tty Del Collapse Find /
+|18: /tmp/pardes-snap/find/cwd/+Search Save Tty Del Collapse
+|19: 1
|38: 2 sub/nest/zqmark-gamma.txt
|39: 3 zqmark-alpha.txt
-== snap word grid=120x40 cursor=7,29
-|18: Find /
-== snap cancel grid=120x40 cursor=7,38
-== snap nomatch grid=120x40 cursor=7,38
-|1: /tmp/pardes-snap/find/cwd/here.txt Save New Newtty Del Find /
-|17: /tmp/pardes-snap/find/cwd/+Search Save New Newtty Del
-|18: 1
-|37: 2 sub/nest/zqmark-gamma.txt
-|38: 3 zqmark-alpha.txt
-|39: 4
-== snap refit grid=120x40 cursor=7,2
-== snap topbar grid=120x40 cursor=12,33
-|34: /tmp/pardes-snap/find/cwd/+Search Save New Newtty Del
-|35: 1 zqmark-alpha.txt
+|40: 4
+== snap refit grid=120x41 cursor=7,3
+== snap topbar grid=120x41 cursor=12,34
+|35: /tmp/pardes-snap/find/cwd/+Search Save Tty Del Collapse
+|36: 1 zqmark-alpha.txt
diff --git a/test/snapshots/find.snap b/test/snapshots/find.snap
index bc051b4b..fbd585f7 100644
--- a/test/snapshots/find.snap
+++ b/test/snapshots/find.snap
@@ -17,7 +17,7 @@ file sub/ZQMARK-beta.txt beta body
file sub/nest/zqmark-gamma.txt gamma body
file other.txt nothing to match here
file .git/zqmark-hidden.txt hidden body
-start 40 120 here.txt
+start 41 120 here.txt
wait 8000 here.txt
stable 700 20000
# SPC f is a GROUP now (Find + New + Save): the indicator stays on the tag
@@ -65,8 +65,8 @@ stable 700 15000
snap back
# executing the WORD Find (middle-click in a body) arms the same input — the
# enum IS the dispatch — and Esc abandons it, restoring the tag tail
-press middle 8 3
-release middle 8 3
+press middle 8 4
+release middle 8 4
stable 700 10000
snap word
key esc
@@ -77,8 +77,8 @@ snap cancel
# somewhere else — so click back into here.txt first. That is not bookkeeping:
# a search never refills the buffer it was asked FROM (fillResults skips it),
# so `owned by here.txt` is the whole premise of the two steps below.
-press left 8 3
-release left 8 3
+press left 8 4
+release left 8 4
stable 400 5000
# a no-match walk opens an empty list of its own. It is exactly as tall as its
# results — one blank row plus its tag — and it stacks above the earlier one,
@@ -103,8 +103,8 @@ snap nomatch
# happens to point at. Asked from here.txt again (the click, as above), and
# the LIST it rewrites is therefore the `nomatch` frame unchanged, down to the
# byte — only the cursor comes back with it.
-press left 8 3
-release left 8 3
+press left 8 4
+release left 8 4
stable 400 5000
key space
key f
@@ -120,9 +120,9 @@ snap refit
# Find walks for that name with nothing typed and no input armed. Row 34 is
# `alpha body`: the three found files stack in the order the looks above
# OPENED them, which is beta, gamma, alpha down the column.
-press left 8 34
-drag left 13 34
-release left 13 34
+press left 8 35
+drag left 13 35
+release left 13 35
stable 400 5000
press middle @Find 1
release middle @Find 1
diff --git a/test/snapshots/fsearch.golden b/test/snapshots/fsearch.golden
index 4b7832e6..6fdbb42f 100644
--- a/test/snapshots/fsearch.golden
+++ b/test/snapshots/fsearch.golden
@@ -1,74 +1,94 @@
-== snap opened grid=180x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/fsearch/cwd/g.txt Save New Newtty Del /tmp/pardes-snap/fsearch/cwd Save New Newtty Del Filter
-| 1 l1 ls
-| 2 MARK a g.txt
+== snap opened grid=180x31 cursor=7,7
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/fsearch/cwd Save Tty Del Togglettymode Filter Collapse /tmp/pardes-snap/fsearch/cwd Save Tty Del Togglettymode Filter Collapse
+| ls ls
+| g.txt g.txt
+|
+| /tmp/pardes-snap/fsearch/cwd/g.txt Save Tty Del Collapse
+| 1 l1
+| 2 MARK a
| 3 l3
| 4 l4
| 5 l5
-|╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
-| /tmp/pardes-snap/fsearch/cwd Save New Newtty Del Filter
-| ls
-| g.txt
-|
-|
-|
-| g.txt
-|
-| /tmp/pardes-snap/fsearch/cwd Save New Newtty Del Filter
+| 6 MARK b
+| 7 l7
+| 8 l8
+| 9 l9
+| 10 MARK c
+| /tmp/pardes-snap/fsearch/cwd Save Tty Del Togglettymode Filter Collapse
| ls
| g.txt
-== snap typing grid=180x30 cursor=8,7
-== snap results grid=180x30 cursor=10,3
-|4: /tmp/pardes-snap/fsearch/cwd/+Search Save New Newtty Del
-|5: 1 g.txt:2:1-4 MARK a
-|6: 2 g.txt:6:1-4 MARK b
-== style results grid=180x30
-|0: 0-74 #949494,#121212, 75-179 d,#121212,
-|1: 0-1 #ffffff,#626262, 2-69 #949494,#121212, 70-89 d,#121212, 90-91 #ffffff,#262626, 92-159 #949494,#121212, 160-179 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-8 #bdbdbd,#080808, 9-89 d,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|3: 0-0 d,#121212, 1-1 d,#080808, 2-6 #949494,#121212, 7-10 #080808,#80a0ff, 11-12 #bdbdbd,#080808, 13-89 d,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|4: 0-1 #ffffff,#262626, 2-69 #949494,#121212, 70-89 d,#121212, 90-90 d,#444444, 91-179 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-24 #bdbdbd,#080808, 25-89 d,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-24 #bdbdbd,#080808, 25-89 d,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|7: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-25 #bdbdbd,#080808, 26-89 d,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|8: 0-1 #ffffff,#262626, 2-69 #949494,#121212, 70-89 d,#121212, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-89 #bdbdbd,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-89 #bdbdbd,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|11: 0-0 d,#444444, 1-89 d,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-89 #bdbdbd,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-89 #bdbdbd,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-8 #bdbdbd,#080808, 9-89 d,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-89 #bdbdbd,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|16: 0-1 #ffffff,#262626, 2-69 #949494,#121212, 70-89 d,#121212, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-89 #bdbdbd,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-89 #bdbdbd,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|19: 0-0 d,#444444, 1-89 d,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-89 #bdbdbd,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-89 #bdbdbd,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-89 #bdbdbd,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-89 #bdbdbd,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-89 #bdbdbd,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-89 #bdbdbd,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-89 #bdbdbd,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-89 #bdbdbd,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-89 #bdbdbd,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-|29: 0-0 d,#444444, 1-1 d,#080808, 2-89 #bdbdbd,#080808, 90-90 d,#444444, 91-91 d,#080808, 92-179 #bdbdbd,#080808,
-== snap second grid=180x30 cursor=10,3
-|2: 5 l5 ls
-|3: 6 MARK b g.txt
-== snap third grid=180x30 cursor=10,3
-|2: 9 l9 ls
-|3: 10 MARK c g.txt
-|5: 2 g.txt:6:1-4 MARK b
-|6: 3 g.txt:10:1-4 MARK c
-== snap back grid=180x30 cursor=10,3
-|2: 5 l5 ls
-|3: 6 MARK b g.txt
-|5: 1 g.txt:2:1-4 MARK a
-|6: 2 g.txt:6:1-4 MARK b
-== snap cancel grid=180x30 cursor=10,3
-== snap nomatch grid=180x30 cursor=7,6
-|3: /tmp/pardes-snap/fsearch/cwd/+Search Save New Newtty Del g.txt
-|5: 2 g.txt:6:1-4 MARK b
-|6: 3 g.txt:10:1-4 MARK c
+== snap typing grid=180x31 cursor=8,16
+|16: /MARK
+== snap results grid=180x31 cursor=10,8
+|13: /tmp/pardes-snap/fsearch/cwd/+Search Save Tty Del Collapse
+|14: 1 g.txt:2:1-4 MARK a
+|15: 2 g.txt:6:1-4 MARK b
+|16: 3 g.txt:10:1-4 MARK c
+== style results grid=180x31
+|0: 0-70 #b2c3b8,#1d2824, 71-179 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-89 d,#26362d, 90-114 #b2c3b8,#1d2824, 115-179 d,#1d2824,
+|2: 0-1 #ffffff,#4c6356, 2-72 #b2c3b8,#1d2824, 73-89 d,#1d2824, 90-91 #ffffff,#4c6356, 92-162 #b2c3b8,#1d2824, 163-179 d,#1d2824,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-89 #e5eee5,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-89 #e5eee5,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|5: 0-0 d,#637f6a, 1-89 d,#0d1410, 90-90 d,#637f6a, 91-179 d,#0d1410,
+|6: 0-1 #000000,#adcc91, 2-57 #becfc4,#26362d, 58-89 d,#26362d, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-8 #e5eee5,#0d1410, 9-89 d,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-10 #f5f7ee,#405d4b, 11-12 #e5eee5,#0d1410, 13-89 d,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-8 #e5eee5,#0d1410, 9-89 d,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|10: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-8 #e5eee5,#0d1410, 9-89 d,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|11: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-8 #e5eee5,#0d1410, 9-89 d,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|12: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-89 d,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|13: 0-1 #ffffff,#4c6356, 2-59 #b2c3b8,#1d2824, 60-89 d,#1d2824, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-17 #59675c,#0d1410, 18-18 #e5eee5,#0d1410, 19-22 #f7e4a5,#57472a, 23-24 #e5eee5,#0d1410, 25-89 d,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-17 #59675c,#0d1410, 18-18 #e5eee5,#0d1410, 19-22 #f7e4a5,#57472a, 23-24 #e5eee5,#0d1410, 25-89 d,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|16: 0-0 d,#152019, 1-1 d,#0d1410, 2-18 #59675c,#0d1410, 19-19 #e5eee5,#0d1410, 20-23 #f7e4a5,#57472a, 24-25 #e5eee5,#0d1410, 26-89 d,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|17: 0-1 #ffffff,#4c6356, 2-72 #b2c3b8,#1d2824, 73-89 d,#1d2824, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-89 #e5eee5,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-89 #e5eee5,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|20: 0-0 d,#637f6a, 1-89 d,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-89 #e5eee5,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-89 #e5eee5,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-89 #e5eee5,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-89 #e5eee5,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-89 #e5eee5,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-89 #e5eee5,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-89 #e5eee5,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-89 #e5eee5,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-89 #e5eee5,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-89 #e5eee5,#0d1410, 90-90 d,#637f6a, 91-91 d,#0d1410, 92-179 #e5eee5,#0d1410,
+== snap second grid=180x31 cursor=10,10
+|7: 3 l3
+|8: 4 l4
+|9: 5 l5
+|10: 6 MARK b
+|11: 7 l7
+|12: 8 l8
+== snap third grid=180x31 cursor=10,10
+|7: 7 l7
+|8: 8 l8
+|9: 9 l9
+|10: 10 MARK c
+|11: 11 l11
+|12: 12 l12
+|14: 2 g.txt:6:1-4 MARK b
+|15: 3 g.txt:10:1-4 MARK c
+|16: 4
+== snap back grid=180x31 cursor=10,10
+|7: 3 l3
+|8: 4 l4
+|9: 5 l5
+|10: 6 MARK b
+|11: 7 l7
+|12: 8 l8
+|14: 1 g.txt:2:1-4 MARK a
+|15: 2 g.txt:6:1-4 MARK b
+|16: 3 g.txt:10:1-4 MARK c
+== snap cancel grid=180x31 cursor=10,10
+== snap nomatch grid=180x31 cursor=7,15
+|11: /tmp/pardes-snap/fsearch/cwd/+Search Save Tty Del Collapse
+|12: 1
+|14: 2 g.txt:6:1-4 MARK b
+|15: 3 g.txt:10:1-4 MARK c
+|16: 4
diff --git a/test/snapshots/fsearch.snap b/test/snapshots/fsearch.snap
index 3752909b..4e4ef864 100644
--- a/test/snapshots/fsearch.snap
+++ b/test/snapshots/fsearch.snap
@@ -9,20 +9,20 @@
# (every search gets its own, stacked under the pane) with nothing in it for n
# to stop on, and goes nowhere.
file g.txt l1\nMARK a\nl3\nl4\nl5\nMARK b\nl7\nl8\nl9\nMARK c\nl11\nl12
-start 30 180 -n 3
+start 31 180 -n 3
wait 8000 g.txt
stable 700 20000
# open g.txt: type the name in the shell, look it (as in look-file.snap)
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key i
text g.txt
key esc
settle 100
stable 400 5000
-press right 6 8
-release right 6 8
+press right 6 9
+release right 6 9
wait 10000 MARK a
stable 700 15000
snap opened
diff --git a/test/snapshots/ghostty-mid.golden b/test/snapshots/ghostty-mid.golden
index e648d3ac..106bc063 100644
--- a/test/snapshots/ghostty-mid.golden
+++ b/test/snapshots/ghostty-mid.golden
@@ -1,6 +1,7 @@
-== snap ghostty-mid grid=100x30 cursor=4,6
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/ghostty-mid/cwd Save New Newtty /tmp/pardes-snap/ghostty-mid/cwd Save New Newtty
+== snap ghostty-mid grid=100x31 cursor=4,7
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/ghostty-mid/cwd Save Tty Del To /tmp/pardes-snap/ghostty-mid/cwd Save Tty Del To
| ZZPAD ls
| ./g.sh g.txt
| ./g.sh
@@ -15,6 +16,6 @@
|
|
|
-| /tmp/pardes-snap/ghostty-mid/cwd Save New Newtty
+| /tmp/pardes-snap/ghostty-mid/cwd Save Tty Del To
| ls
| g.txt
diff --git a/test/snapshots/ghostty-mid.snap b/test/snapshots/ghostty-mid.snap
index 792b5572..cb3088b4 100644
--- a/test/snapshots/ghostty-mid.snap
+++ b/test/snapshots/ghostty-mid.snap
@@ -8,11 +8,11 @@
# gtk-enable-primary-paste=false (apprt/gtk/class/surface.zig, gcMouseDown/
# gcMouseUp) — the bytes below simply never get sent.
file g.txt x
-start 30 100 -n 3
+start 31 100 -n 3
wait 8000 g.txt
stable 700 20000
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key c-b
stable 600 8000
@@ -23,10 +23,10 @@ stable 700 10000
key c-b
stable 600 8000
send \x1b[I
-send \x1b[<35;10;8M\x1b[<35;7;6M\x1b[<35;4;4M
-send \x1b[<1;4;4M
-send \x1b[<1;4;4m
-send \x1b[<35;6;4M
+send \x1b[<35;10;9M\x1b[<35;7;7M\x1b[<35;4;5M
+send \x1b[<1;4;5M
+send \x1b[<1;4;5m
+send \x1b[<35;6;5M
wait 10000 GHOSTOK
stable 700 10000
snap ghostty-mid
diff --git a/test/snapshots/grep.golden b/test/snapshots/grep.golden
index 75161201..795ceddf 100644
--- a/test/snapshots/grep.golden
+++ b/test/snapshots/grep.golden
@@ -1,43 +1,41 @@
-== snap opened grid=180x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/grep/cwd/a.txt Save New Newtty Del /tmp/pardes-snap/grep/cwd Save New Newtty Del Filter
-| 1 hello TARGET one ls
-| 2 nothing here a.txt noise.txt sub
+== snap opened grid=180x31 cursor=7,7
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/grep/cwd Save Tty Del Togglettymode Filter Collapse /tmp/pardes-snap/grep/cwd Save Tty Del Togglettymode Filter Collapse
+| ls ls
+| a.txt noise.txt sub a.txt noise.txt sub
+|
+| /tmp/pardes-snap/grep/cwd/a.txt Save Tty Del Collapse
+| 1 hello TARGET one
+| 2 nothing here
| 3 last TARGET line
|
|
-|╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
-| /tmp/pardes-snap/grep/cwd Save New Newtty Del Filter
-| ls
-| a.txt noise.txt sub
|
|
|
-| a.txt
|
-| /tmp/pardes-snap/grep/cwd Save New Newtty Del Filter
+|
+| /tmp/pardes-snap/grep/cwd Save Tty Del Togglettymode Filter Collapse
| ls
| a.txt noise.txt sub
-== snap typing grid=180x30 cursor=15,7
-|7: Grep /TARGET
-== snap results grid=180x30 cursor=7,2
-|4: /tmp/pardes-snap/grep/cwd/+Search Save New Newtty Del
-|5: 1 a.txt:1:7-12 hello TARGET one
-|6: 2 a.txt:3:6-11 last TARGET line
-|7: 3 sub/b.txt:2:1-6 TARGET inside sub
-== snap first grid=180x30 cursor=18,2
-== snap opened-hit grid=180x30 cursor=12,14
-|2: 2 nothing here ls
-|3: 3 last TARGET line a.txt noise.txt sub
-|5: 2 a.txt:3:6-11 last TARGET line
-|6: 3 sub/b.txt:2:1-6 TARGET inside sub
-|7: 4
-|12: /tmp/pardes-snap/grep/cwd/sub/b.txt Save New Newtty Del
-|13: 1 deep
-|14: 2 TARGET inside sub
-== snap nomatch grid=180x30 cursor=2,10
-|14: /tmp/pardes-snap/grep/cwd/sub/+Search Save New Newtty Del
-|15: 1
-== snap chordsel grid=180x30 cursor=19,2
-== snap chord grid=180x30 cursor=19,2
-|3: /tmp/pardes-snap/grep/cwd/+Search Save New Newtty Del a.txt noise.txt sub
+== snap typing grid=180x31 cursor=15,16
+|16: Grep /TARGET
+== snap results grid=180x31 cursor=7,7
+|13: /tmp/pardes-snap/grep/cwd/+Search Save Tty Del Collapse
+|14: 1 a.txt:1:7-12 hello TARGET one
+|15: 2 a.txt:3:6-11 last TARGET line
+|16: 3 sub/b.txt:2:1-6 TARGET inside sub
+== snap first grid=180x31 cursor=18,7
+== snap opened-hit grid=180x31 cursor=12,11
+|9: /tmp/pardes-snap/grep/cwd/sub/b.txt Save Tty Del Collapse
+|10: 1 deep
+|11: 2 TARGET inside sub
+|14: 2 a.txt:3:6-11 last TARGET line
+|15: 3 sub/b.txt:2:1-6 TARGET inside sub
+|16: 4
+== snap nomatch grid=180x31 cursor=2,4
+|11: /tmp/pardes-snap/grep/cwd/sub/+Search Save Tty Del Collapse
+|12: 1
+== snap chordsel grid=180x31 cursor=19,7
+== snap chord grid=180x31 cursor=19,7
diff --git a/test/snapshots/grep.snap b/test/snapshots/grep.snap
index 7eeae8f5..84b8f415 100644
--- a/test/snapshots/grep.snap
+++ b/test/snapshots/grep.snap
@@ -14,21 +14,21 @@ dirmk sub
file a.txt hello TARGET one\nnothing here\nlast TARGET line
file sub/b.txt deep\nTARGET inside sub
file noise.txt nothing to see
-start 30 180 -n 3
+start 31 180 -n 3
wait 8000 a.txt
stable 700 20000
# open a.txt: a SECOND pane, whose directory the shell's cwd already covers —
# its root is dropped, which is what keeps the hits below un-duplicated
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key i
text a.txt
key esc
settle 100
stable 400 5000
-press right 6 8
-release right 6 8
+press right 6 9
+release right 6 9
wait 10000 hello TARGET
stable 700 15000
snap opened
@@ -89,9 +89,9 @@ snap nomatch
# walk on that word at once — no tag input, nothing typed. TARGET already has
# a list open from above, so this refills THAT one; only the zzqq list below is
# a second buffer, because only it is a different search.
-press left 14 3
-drag left 20 3
-release left 20 3
+press left @TARGET 8
+drag left @TARGET+6 8
+release left @TARGET+6 8
stable 400 5000
snap chordsel
press middle @Grep 1
diff --git a/test/snapshots/hscroll.golden b/test/snapshots/hscroll.golden
index 35061874..61e04e49 100644
--- a/test/snapshots/hscroll.golden
+++ b/test/snapshots/hscroll.golden
@@ -1,29 +1,29 @@
-== snap opened grid=90x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/hscroll/cwd/wide.txt Save /tmp/pardes-snap/hscroll/cwd Save New Newtt
-| 1 short1 END_A_MARKER_WAY_OUT_RIGHT_padp ls
-| wide.txt
+== snap opened grid=90x31 cursor=7,7
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/hscroll/cwd Save Tty Del T /tmp/pardes-snap/hscroll/cwd Save Tty Del T
+| ls ls
+| wide.txt wide.txt
+|
+| /tmp/pardes-snap/hscroll/cwd/wide.txt Save
+| 1 short1 END_A_MARKER_WAY_OUT_RIGHT_padp
+|
+|
|
|
|
-|╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
-| /tmp/pardes-snap/hscroll/cwd Save New Newtt
-| ls
-| wide.txt
|
|
|
-| wide.txt
|
-| /tmp/pardes-snap/hscroll/cwd Save New Newtt
+| /tmp/pardes-snap/hscroll/cwd Save Tty Del T
| ls
| wide.txt
-== snap wheeled grid=90x30 cursor=7,2
-|2: 1 ND_A_MARKER_WAY_OUT_RIGHT_padpadpadpad ls
-|7:
-== snap clamped grid=90x30 cursor=7,2
-|2: 1 short1 END_A_MARKER_WAY_OUT_RIGHT_padp ls
-== snap dollar grid=90x30 cursor=41,2
-|2: 1 padpadpadpadpadpadpadpadpadpad_TAIL ls
-== snap zero grid=90x30 cursor=7,2
-|2: 1 short1 END_A_MARKER_WAY_OUT_RIGHT_padp ls
+== snap wheeled grid=90x31 cursor=7,7
+|7: 1 ND_A_MARKER_WAY_OUT_RIGHT_padpadpadpad
+== snap clamped grid=90x31 cursor=7,7
+|7: 1 short1 END_A_MARKER_WAY_OUT_RIGHT_padp
+== snap dollar grid=90x31 cursor=41,7
+|7: 1 padpadpadpadpadpadpadpadpadpad_TAIL
+== snap zero grid=90x31 cursor=7,7
+|7: 1 short1 END_A_MARKER_WAY_OUT_RIGHT_padp
diff --git a/test/snapshots/hscroll.snap b/test/snapshots/hscroll.snap
index 078b56e4..6f73154f 100644
--- a/test/snapshots/hscroll.snap
+++ b/test/snapshots/hscroll.snap
@@ -4,7 +4,7 @@
# line pulls the view right, 0 snaps it back. Overscroll right is allowed;
# a cursor move reels it in.
file wide.txt short1 END_A_MARKER_WAY_OUT_RIGHT_padpadpadpadpadpadpadpadpadpadpadpadpadpad_TAIL
-start 30 90 -n 3
+start 31 90 -n 3
wait 8000 wide.txt
stable 700 20000
# soft wrap is ON by default and a wrapped body has nothing to scroll sideways
@@ -13,27 +13,27 @@ stable 700 20000
key space t w
stable 400 5000
# open wide.txt: click a body spot, type the name, look it
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key i
text wide.txt
key esc
settle 100
stable 400 5000
-press right 7 8
-release right 7 8
+press right 7 9
+release right 7 9
stable 700 15000
snap opened
# wheel right over the file pane: content shifts, line numbers stay
-send \x1b[<66;10;3M
-send \x1b[<66;10;3M
+send \x1b[<66;10;8M
+send \x1b[<66;10;8M
stable 400 5000
snap wheeled
# wheel back left past the start clamps at column 0
-send \x1b[<67;10;3M
-send \x1b[<67;10;3M
-send \x1b[<67;10;3M
+send \x1b[<67;10;8M
+send \x1b[<67;10;8M
+send \x1b[<67;10;8M
stable 400 5000
snap clamped
# $ walks the cursor to the line end: the view follows with the margin
diff --git a/test/snapshots/images.golden b/test/snapshots/images.golden
index a3e8c7c9..558b4d84 100644
--- a/test/snapshots/images.golden
+++ b/test/snapshots/images.golden
@@ -1,85 +1,97 @@
-== snap img-open grid=150x30 cursor=11,7
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| img petscii:off palette:commodore ascii:on /tmp/pardes-snap/images/cwd/pi /tmp/pardes-snap/images/cwd Save New Newtty Del Filter
-| )a▟Z▛🬮>{1\🬆🬻 ls
-| 🬻&z""─🬛█🬆🬻 pic.ppm
-| g`🬶🬬@🬕🬆🬻
-| ▙-=🬫🬆🬻
-| ▙.🬆🬻
-|╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
-| /tmp/pardes-snap/images/cwd Save New Newtty Del Filter
-| ls
-| pic.ppm
-|
-|
-|
-| pic.ppm
+== snap img-open grid=150x31 cursor=11,8
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/images/cwd Save Tty Del Togglettymode Filter Collapse /tmp/pardes-snap/images/cwd Save Tty Del Togglettymode Filter Collapse
+| ls ls
+| pic.ppm pic.ppm
|
-| /tmp/pardes-snap/images/cwd Save New Newtty Del Filter
+| img petscii:off palette:commodore ascii:on /tmp/pardes-snap/images/cwd/pi
+| 92@7%5Gm$D4▘🬵%🬨3'🬥🬆🬻
+| 🬥3▖╱{=CY,▌*)^M<▀🬎🬻
+| X▄jN.&🬺j*w3┼"🬥🬆🬻
+| ╱╳PxGXPV*q"(🬆~
+| HF[🬗█▀&t0^🬆🬻
+| 🬴X7─27/*🬆🬻
+| .g🬬🬎ks▛🬻
+| ▚i,V🬆🬹
+| mu🬆🬻
+| 🬆🬻
+| /tmp/pardes-snap/images/cwd Save Tty Del Togglettymode Filter Collapse
| ls
| pic.ppm
-== style img-open grid=150x30
-|0: 0-74 #949494,#121212, 75-149 d,#121212,
-|1: 0-1 #ffffff,#626262, 2-74 #949494,#121212, 75-76 #ffffff,#262626, 77-130 #949494,#121212, 131-149 d,#121212,
-|2: 0-0 d,#121212, 1-31 d,#080808, 32-33 #959595,#6c6c6c, 34-34 #6c6c6c,#959595, 35-35 #959595,#6c6c6c, 36-36 #6c6c6c,#959595, 37-37 #959595,#6c6c6c, 38-38 #6c6c6c,#959595, 39-41 #959595,#6c6c6c, 42-42 #6c6c6c,#6c5eb5, 43-43 #352879,#6c6c6c, 44-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|3: 0-0 d,#121212, 1-31 d,#080808, 32-34 #6c6c6c,#959595, 35-37 #959595,#6c6c6c, 38-39 #6c6c6c,#959595, 40-40 #6c6c6c,#6c5eb5, 41-41 #352879,#6c6c6c, 42-43 #352879,#352879, 44-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|4: 0-0 d,#121212, 1-31 d,#080808, 32-33 #959595,#6c6c6c, 34-35 #6c6c6c,#959595, 36-36 #959595,#6c6c6c, 37-37 #6c6c6c,#959595, 38-38 #6c6c6c,#6c5eb5, 39-39 #352879,#6c6c6c, 40-43 #352879,#352879, 44-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|5: 0-0 d,#121212, 1-31 d,#080808, 32-32 #6c6c6c,#959595, 33-34 #959595,#6c6c6c, 35-35 #6c6c6c,#959595, 36-36 #6c6c6c,#6c5eb5, 37-37 #352879,#959595, 38-43 #352879,#352879, 44-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|6: 0-0 d,#121212, 1-31 d,#080808, 32-33 #959595,#6c6c6c, 34-34 #959595,#6c5eb5, 35-35 #352879,#6c6c6c, 36-43 #352879,#352879, 44-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|7: 0-0 d,#121212, 1-31 d,#080808, 32-32 #6c6c6c,#6c5eb5, 33-33 #352879,#6c6c6c, 34-43 #352879,#352879, 44-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|8: 0-1 #ffffff,#262626, 2-74 #949494,#121212, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|11: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-10 #bdbdbd,#080808, 11-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|16: 0-1 #ffffff,#262626, 2-74 #949494,#121212, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|19: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|29: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-== style term-palette grid=150x30
-|2: 0-0 d,#121212, 1-31 d,#080808, 32-41 p8,p4, 42-42 p8,p12, 43-43 p12,p8, 44-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|3: 0-0 d,#121212, 1-31 d,#080808, 32-39 p8,p4, 40-40 p8,p12, 41-41 p12,p8, 42-43 p12,p12, 44-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|4: 0-0 d,#121212, 1-31 d,#080808, 32-32 p8,p4, 33-33 p4,p8, 34-37 p8,p4, 38-38 p8,p12, 39-40 p12,p8, 41-43 p12,p12, 44-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|5: 0-0 d,#121212, 1-31 d,#080808, 32-35 p8,p4, 36-36 p8,p12, 37-37 p12,p8, 38-43 p12,p12, 44-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|6: 0-0 d,#121212, 1-31 d,#080808, 32-32 p4,p8, 33-33 p8,p4, 34-34 p8,p12, 35-36 p12,p8, 37-43 p12,p12, 44-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|7: 0-0 d,#121212, 1-31 d,#080808, 32-32 p8,p12, 33-34 p12,p8, 35-43 p12,p12, 44-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-== snap no-ascii grid=150x30 cursor=11,7
-|1: img petscii:off palette:terminal ascii:off /tmp/pardes-snap/images/cwd/pi /tmp/pardes-snap/images/cwd Save New Newtty Del Filter
-|2: █████🬻████🬝▄ ls
-|3: ████████🬝▄ pic.ppm
-|4: ███🬬██🬝▄█
-|5: ████🬝▄
-|6: ██🬝▄█
-== snap tag-edit grid=400x30 cursor=85,1
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| img petscii:off palette:terminal ascii:off /tmp/pardes-snap/images/cwd/pic.ppm Zork New Newtty Del /tmp/pardes-snap/images/cwd Save New Newtty Del Filter
-| █████🬻████🬝▄ ls
-| ████████🬝▄ pic.ppm
-| ███🬬██🬝▄█
-| ████🬝▄
-| ██🬝▄█
-| 🬝▄█
-| /tmp/pardes-snap/images/cwd Save New Newtty Del Filter
-| ls
-| pic.ppm
-|
-|
-|
-| pic.ppm
+== style img-open grid=150x31
+|0: 0-70 #b2c3b8,#1d2824, 71-149 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-74 d,#26362d, 75-99 #b2c3b8,#1d2824, 100-149 d,#1d2824,
+|2: 0-1 #ffffff,#4c6356, 2-71 #b2c3b8,#1d2824, 72-74 d,#1d2824, 75-76 #ffffff,#4c6356, 77-146 #b2c3b8,#1d2824, 147-149 d,#1d2824,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|5: 0-0 d,#637f6a, 1-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|6: 0-1 #000000,#adcc91, 2-74 #becfc4,#26362d, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|7: 0-0 d,#152019, 1-27 d,#0d1410, 28-29 #959595,#6c6c6c, 30-30 #6c6c6c,#959595, 31-34 #959595,#6c6c6c, 35-35 #6c6c6c,#959595, 36-37 #959595,#6c6c6c, 38-38 #6c6c6c,#959595, 39-39 #959595,#6c6c6c, 40-40 #6c6c6c,#959595, 41-41 #959595,#6c6c6c, 42-42 #6c6c6c,#959595, 43-44 #959595,#6c6c6c, 45-45 #6c6c6c,#959595, 46-46 #959595,#6c5eb5, 47-47 #352879,#6c6c6c, 48-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|8: 0-0 d,#152019, 1-27 d,#0d1410, 28-28 #6c6c6c,#959595, 29-29 #959595,#6c6c6c, 30-30 #6c6c6c,#959595, 31-34 #959595,#6c6c6c, 35-38 #6c6c6c,#959595, 39-42 #959595,#6c6c6c, 43-43 #6c6c6c,#959595, 44-44 #6c6c6c,#352879, 45-45 #352879,#959595, 46-47 #352879,#352879, 48-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|9: 0-0 d,#152019, 1-27 d,#0d1410, 28-28 #959595,#6c6c6c, 29-29 #6c6c6c,#959595, 30-33 #959595,#6c6c6c, 34-34 #6c6c6c,#959595, 35-38 #959595,#6c6c6c, 39-39 #6c6c6c,#959595, 40-40 #959595,#6c6c6c, 41-41 #6c6c6c,#959595, 42-42 #959595,#6c5eb5, 43-43 #352879,#6c6c6c, 44-47 #352879,#352879, 48-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|10: 0-0 d,#152019, 1-27 d,#0d1410, 28-29 #959595,#6c6c6c, 30-30 #6c6c6c,#959595, 31-33 #959595,#6c6c6c, 34-34 #6c6c6c,#959595, 35-39 #959595,#6c6c6c, 40-40 #959595,#6c5eb5, 41-41 #6c6c6c,#352879, 42-47 #352879,#352879, 48-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|11: 0-0 d,#152019, 1-27 d,#0d1410, 28-28 #6c6c6c,#959595, 29-29 #959595,#6c6c6c, 30-34 #6c6c6c,#959595, 35-36 #959595,#6c6c6c, 37-37 #6c6c6c,#959595, 38-38 #6c6c6c,#6c5eb5, 39-39 #352879,#6c6c6c, 40-47 #352879,#352879, 48-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|12: 0-0 d,#152019, 1-27 d,#0d1410, 28-29 #6c6c6c,#959595, 30-31 #959595,#6c6c6c, 32-32 #6c6c6c,#959595, 33-34 #959595,#6c6c6c, 35-35 #6c6c6c,#959595, 36-36 #6c6c6c,#6c5eb5, 37-37 #352879,#6c6c6c, 38-47 #352879,#352879, 48-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|13: 0-0 d,#152019, 1-27 d,#0d1410, 28-29 #959595,#6c6c6c, 30-32 #6c6c6c,#959595, 33-33 #959595,#6c6c6c, 34-34 #6c6c6c,#352879, 35-35 #352879,#6c6c6c, 36-47 #352879,#352879, 48-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|14: 0-0 d,#152019, 1-27 d,#0d1410, 28-31 #959595,#6c6c6c, 32-32 #959595,#6c5eb5, 33-33 #352879,#6c5eb5, 34-47 #352879,#352879, 48-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|15: 0-0 d,#152019, 1-27 d,#0d1410, 28-28 #6c6c6c,#959595, 29-29 #959595,#6c6c6c, 30-30 #6c6c6c,#6c5eb5, 31-31 #352879,#6c6c6c, 32-47 #352879,#352879, 48-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|16: 0-0 d,#152019, 1-27 d,#0d1410, 28-28 #6c6c6c,#6c5eb5, 29-29 #352879,#6c6c6c, 30-47 #352879,#352879, 48-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|17: 0-1 #ffffff,#4c6356, 2-71 #b2c3b8,#1d2824, 72-74 d,#1d2824, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|20: 0-0 d,#637f6a, 1-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+== style term-palette grid=150x31
+|7: 0-0 d,#152019, 1-27 d,#0d1410, 28-28 p8,p5, 29-30 p8,p4, 31-31 p4,p8, 32-35 p8,p4, 36-37 p4,p8, 38-39 p8,p4, 40-40 p4,p8, 41-42 p8,p4, 43-43 p4,p8, 44-46 p8,p4, 47-47 p12,p8, 48-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|8: 0-0 d,#152019, 1-27 d,#0d1410, 28-30 p8,p4, 31-33 p4,p8, 34-34 p8,p4, 35-36 p4,p8, 37-37 p8,p4, 38-41 p4,p8, 42-42 p8,p4, 43-43 p4,p8, 44-44 p8,p12, 45-46 p12,p8, 47-47 p12,p12, 48-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|9: 0-0 d,#152019, 1-27 d,#0d1410, 28-28 p8,p4, 29-29 p4,p8, 30-30 p8,p4, 31-31 p4,p8, 32-32 p8,p4, 33-33 p4,p8, 34-35 p8,p4, 36-37 p4,p8, 38-38 p8,p5, 39-41 p8,p4, 42-42 p4,p8, 43-44 p12,p8, 45-47 p12,p12, 48-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|10: 0-0 d,#152019, 1-27 d,#0d1410, 28-29 p8,p4, 30-34 p4,p8, 35-36 p8,p4, 37-38 p4,p8, 39-39 p8,p4, 40-40 p4,p8, 41-41 p12,p8, 42-47 p12,p12, 48-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|11: 0-0 d,#152019, 1-27 d,#0d1410, 28-28 p4,p8, 29-29 p8,p4, 30-31 p4,p8, 32-32 p8,p4, 33-33 p4,p8, 34-34 p8,p4, 35-36 p4,p8, 37-37 p8,p4, 38-38 p8,p12, 39-39 p12,p8, 40-47 p12,p12, 48-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|12: 0-0 d,#152019, 1-27 d,#0d1410, 28-28 p8,p4, 29-31 p4,p8, 32-35 p8,p4, 36-36 p4,p8, 37-37 p12,p8, 38-47 p12,p12, 48-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|13: 0-0 d,#152019, 1-27 d,#0d1410, 28-32 p8,p4, 33-33 p4,p8, 34-34 p8,p12, 35-36 p12,p8, 37-47 p12,p12, 48-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|14: 0-0 d,#152019, 1-27 d,#0d1410, 28-28 p8,p4, 29-29 p4,p8, 30-30 p8,p4, 31-32 p4,p8, 33-33 p12,p8, 34-34 p8,p12, 35-47 p12,p12, 48-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|15: 0-0 d,#152019, 1-27 d,#0d1410, 28-29 p4,p8, 30-30 p8,p12, 31-32 p12,p8, 33-47 p12,p12, 48-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|16: 0-0 d,#152019, 1-27 d,#0d1410, 28-28 p8,p12, 29-29 p12,p8, 30-47 p12,p12, 48-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+== snap no-ascii grid=150x31 cursor=11,8
+|6: img petscii:off palette:terminal ascii:off /tmp/pardes-snap/images/cwd/pi
+|7: ███╱█🬻██🬺██🬻███╱██🬴▄
+|8: 🬬██╱███╱🬻🬝🬻🬬████🬝🬵█
+|9: █╲█🬴████╲╱█🬝██▟▄█
+|10: ██╲╱╲█🬝█████╱🬵
+|11: ╱█████████🬝▄
+|12: █│█████🬝🬝🬹
+|13: ██████🬝▄█
+|14: 🬜🬬██🬸▄╲
+|15: 🬺█🬝🬵█
+|16: 🬝▄
+== snap tag-edit grid=400x31 cursor=86,6
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/images/cwd Save Tty Del Togglettymode Filter Collapse /tmp/pardes-snap/images/cwd Save Tty Del Togglettymode Filter Collapse
+| ls ls
+| pic.ppm pic.ppm
|
-| /tmp/pardes-snap/images/cwd Save New Newtty Del Filter
+| img petscii:off palette:terminal ascii:off /tmp/pardes-snap/images/cwd/pic.ppm Zork Tty Del Collapse
+| ███╱█🬻██🬺██🬻███╱██🬴▄
+| 🬬██╱███╱🬻🬝🬻🬬████🬝🬵█
+| █╲█🬴████╲╱█🬝██▟▄█
+| ██╲╱╲█🬝█████╱🬵
+| ╱█████████🬝▄
+| █│█████🬝🬝🬹
+| ██████🬝▄█
+| 🬜🬬██🬸▄╲
+| 🬺█🬝🬵█
+| 🬝▄
+| /tmp/pardes-snap/images/cwd Save Tty Del Togglettymode Filter Collapse
| ls
| pic.ppm
diff --git a/test/snapshots/images.snap b/test/snapshots/images.snap
index 6b9a53d0..6288a3ba 100644
--- a/test/snapshots/images.snap
+++ b/test/snapshots/images.snap
@@ -1,21 +1,21 @@
# image panes: right-click a .ppm opens petscii glyph art (no kitty in the
# harness). The tag starts with the renderer's plain state fields followed by
-# its path and `New Del`; the fields are display-only, while their toggles are
+# its path and `Tty Del`; the fields are display-only, while their toggles are
# builtins under SPC t (the old clickable tag words sat past the pane's right
# edge, so clicking them only ever hit the neighbouring shell's tag).
ppmdiag pic.ppm
-start 30 150 -n 3
+start 31 150 -n 3
wait 8000 pic.ppm
stable 700 20000
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key i
text pic.ppm
key esc
settle 100
-press right 6 8
-release right 6 8
+press right 6 9
+release right 6 9
wait 10000 img
stable 700 20000
snap img-open
@@ -41,13 +41,13 @@ snap no-ascii
# prefix is wider than this source-local column, so widen the grid for this
# final assertion. (A column-border drag intentionally takes width from only
# one neighbour, which cannot expose this 82-column prefix.) Then click the
-# visible tail itself, at its `New`. This proves the image tag is an ordinary
+# visible tail itself, at its `Tty`. This proves the image tag is an ordinary
# editor rather than accidentally typing at a clipped read-only path.
-resize 30 400
+resize 31 400
stable 400 5000
-press left 82 2
-release left 82 2
+press left @Tty 7
+release left @Tty 7
stable 400 5000
-text Zork
+send Zork\x20
stable 400 5000
snap tag-edit
diff --git a/test/snapshots/jumps.golden b/test/snapshots/jumps.golden
index 44af4b2d..3005135c 100644
--- a/test/snapshots/jumps.golden
+++ b/test/snapshots/jumps.golden
@@ -1,6 +1,7 @@
-== snap start grid=150x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/jumps/cwd/big.txt Save New Newtty Del
+== snap start grid=150x31 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/jumps/cwd/big.txt Save Tty Del Collapse
| 1 line 1
| 2 line 2
| 3 line 3
@@ -29,191 +30,193 @@
| 26 line 26
| 27 line 27
| 28 line 28
-== snap to-shell grid=150x30 cursor=79,4
-|1: /tmp/pardes-snap/jumps/cwd/big.txt Save New Newtty Del /tmp/pardes-snap/jumps/cwd Save New Newtty Del Filter
-|2: 1 line 1 ls
-|3: 2 line 2 big.txt
-== snap to-file grid=150x30 cursor=7,2
-== snap goto-100 grid=150x30 cursor=7,26
-|2: 76 line 76 ls
-|3: 77 line 77 big.txt
-|4: 78 line 78
-|5: 79 line 79
-|6: 80 line 80
-|7: 81 line 81
-|8: 82 line 82
-|9: 83 line 83
-|10: 84 line 84
-|11: 85 line 85
-|12: 86 line 86
-|13: 87 line 87
-|14: 88 line 88
-|15: 89 line 89
-|16: 90 line 90
-|17: 91 line 91
-|18: 92 line 92
-|19: 93 line 93
-|20: 94 line 94
-|21: 95 line 95
-|22: 96 line 96
-|23: 97 line 97
-|24: 98 line 98
-|25: 99 line 99
-|26: 100 line 100
-|27: 101 line 101
-|28: 102 line 102
-|29: 103 line 103
-== snap back-in-file grid=150x30 cursor=7,2
-|2: 1 line 1 ls
-|3: 2 line 2 big.txt
-|4: 3 line 3
-|5: 4 line 4
-|6: 5 line 5
-|7: 6 line 6
-|8: 7 line 7
-|9: 8 line 8
-|10: 9 line 9
-|11: 10 line 10
-|12: 11 line 11
-|13: 12 line 12
-|14: 13 line 13
-|15: 14 line 14
-|16: 15 line 15
-|17: 16 line 16
-|18: 17 line 17
-|19: 18 line 18
-|20: 19 line 19
-|21: 20 line 20
-|22: 21 line 21
-|23: 22 line 22
-|24: 23 line 23
-|25: 24 line 24
-|26: 25 line 25
-|27: 26 line 26
-|28: 27 line 27
-|29: 28 line 28
-== snap back-to-shell grid=150x30 cursor=79,4
-== snap forward-file grid=150x30 cursor=7,2
-== snap forward-100 grid=150x30 cursor=7,16
-|2: 86 line 86 ls
-|3: 87 line 87 big.txt
-|4: 88 line 88
-|5: 89 line 89
-|6: 90 line 90
-|7: 91 line 91
-|8: 92 line 92
-|9: 93 line 93
-|10: 94 line 94
-|11: 95 line 95
-|12: 96 line 96
-|13: 97 line 97
-|14: 98 line 98
-|15: 99 line 99
-|16: 100 line 100
-|17: 101 line 101
-|18: 102 line 102
-|19: 103 line 103
-|20: 104 line 104
-|21: 105 line 105
-|22: 106 line 106
-|23: 107 line 107
-|24: 108 line 108
-|25: 109 line 109
-|26: 110 line 110
-|27: 111 line 111
-|28: 112 line 112
-|29: 113 line 113
-== snap last grid=150x30 cursor=79,4
-== snap last-back grid=150x30 cursor=7,16
-== snap jumplist grid=150x30 cursor=7,16
-|25: /tmp/pardes-snap/jumps/cwd/+Jumps Save New Newtty Del
-|26: 1 @p1:3:3 /tmp/pardes-snap/jumps/cwd
+== snap to-shell grid=150x31 cursor=79,5
+|1: New Tty Find Grep Joincol New Tty Find Grep Joincol
+|2: /tmp/pardes-snap/jumps/cwd/big.txt Save Tty Del Collapse /tmp/pardes-snap/jumps/cwd Save Tty Del Togglettymode Filter Collapse
+|3: 1 line 1 ls
+|4: 2 line 2 big.txt
+== snap to-file grid=150x31 cursor=7,3
+== snap goto-100 grid=150x31 cursor=7,27
+|3: 76 line 76 ls
+|4: 77 line 77 big.txt
+|5: 78 line 78
+|6: 79 line 79
+|7: 80 line 80
+|8: 81 line 81
+|9: 82 line 82
+|10: 83 line 83
+|11: 84 line 84
+|12: 85 line 85
+|13: 86 line 86
+|14: 87 line 87
+|15: 88 line 88
+|16: 89 line 89
+|17: 90 line 90
+|18: 91 line 91
+|19: 92 line 92
+|20: 93 line 93
+|21: 94 line 94
+|22: 95 line 95
+|23: 96 line 96
+|24: 97 line 97
+|25: 98 line 98
+|26: 99 line 99
+|27: 100 line 100
+|28: 101 line 101
+|29: 102 line 102
+|30: 103 line 103
+== snap back-in-file grid=150x31 cursor=7,3
+|3: 1 line 1 ls
+|4: 2 line 2 big.txt
+|5: 3 line 3
+|6: 4 line 4
+|7: 5 line 5
+|8: 6 line 6
+|9: 7 line 7
+|10: 8 line 8
+|11: 9 line 9
+|12: 10 line 10
+|13: 11 line 11
+|14: 12 line 12
+|15: 13 line 13
+|16: 14 line 14
+|17: 15 line 15
+|18: 16 line 16
+|19: 17 line 17
+|20: 18 line 18
+|21: 19 line 19
+|22: 20 line 20
+|23: 21 line 21
+|24: 22 line 22
+|25: 23 line 23
+|26: 24 line 24
+|27: 25 line 25
+|28: 26 line 26
+|29: 27 line 27
+|30: 28 line 28
+== snap back-to-shell grid=150x31 cursor=79,5
+== snap forward-file grid=150x31 cursor=7,3
+== snap forward-100 grid=150x31 cursor=7,17
+|3: 86 line 86 ls
+|4: 87 line 87 big.txt
+|5: 88 line 88
+|6: 89 line 89
+|7: 90 line 90
+|8: 91 line 91
+|9: 92 line 92
+|10: 93 line 93
+|11: 94 line 94
+|12: 95 line 95
+|13: 96 line 96
+|14: 97 line 97
+|15: 98 line 98
+|16: 99 line 99
+|17: 100 line 100
+|18: 101 line 101
+|19: 102 line 102
+|20: 103 line 103
+|21: 104 line 104
+|22: 105 line 105
+|23: 106 line 106
+|24: 107 line 107
+|25: 108 line 108
+|26: 109 line 109
+|27: 110 line 110
+|28: 111 line 111
+|29: 112 line 112
+|30: 113 line 113
+== snap last grid=150x31 cursor=79,5
+== snap last-back grid=150x31 cursor=7,17
+== snap jumplist grid=150x31 cursor=7,17
+|26: /tmp/pardes-snap/jumps/cwd/+Jumps Save Tty Del Collapse
+|27: 1 @p1:3:3 /tmp/pardes-snap/jumps/cwd
+|28: 2 /tmp/pardes-snap/jumps/cwd/big.txt:1:1 line 1
+|29: 3 @p1:3:3 /tmp/pardes-snap/jumps/cwd
+|30: 4 /tmp/pardes-snap/jumps/cwd/big.txt:100:1 line 100
+== snap step1-shell grid=150x31 cursor=79,5
+== style step1-shell grid=150x31
+|0: 0-70 #b2c3b8,#1d2824, 71-149 d,#1d2824,
+|1: 0-24 #b2c3b8,#1d2824, 25-74 d,#1d2824, 75-99 #becfc4,#26362d, 100-149 d,#26362d,
+|2: 0-1 #ffffff,#4c6356, 2-57 #b2c3b8,#1d2824, 58-74 d,#1d2824, 75-76 #000000,#adcc91, 77-145 #becfc4,#26362d, 146-149 d,#26362d,
+|3: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|4: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|5: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|6: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|7: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|8: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|9: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|10: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|11: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|14: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|15: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|16: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|17: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-14 #e5eee5,#0d1410, 15-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|18: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-14 #e5eee5,#0d1410, 15-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|19: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-14 #e5eee5,#0d1410, 15-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|20: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-14 #e5eee5,#0d1410, 15-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|21: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-14 #e5eee5,#0d1410, 15-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|22: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-14 #e5eee5,#0d1410, 15-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|23: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-14 #e5eee5,#0d1410, 15-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|24: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-14 #e5eee5,#0d1410, 15-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|25: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-14 #e5eee5,#0d1410, 15-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|26: 0-1 #ffffff,#4c6356, 2-56 #b2c3b8,#1d2824, 57-74 d,#1d2824, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-13 #59675c,#0d1410, 14-40 #e5eee5,#0d1410, 41-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-44 #59675c,#0d1410, 45-51 #e5eee5,#0d1410, 52-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-13 #59675c,#0d1410, 14-40 #e5eee5,#0d1410, 41-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|30: 0-0 d,#152019, 1-1 d,#0d1410, 2-46 #59675c,#0d1410, 47-55 #e5eee5,#0d1410, 56-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+== snap step2-file grid=150x31 cursor=7,3
+|3: 1 line 1 ls
+|4: 2 line 2 big.txt
+|5: 3 line 3
+|6: 4 line 4
+|7: 5 line 5
+|8: 6 line 6
+|9: 7 line 7
+|10: 8 line 8
+|11: 9 line 9
+|12: 10 line 10
+|13: 11 line 11
+|14: 12 line 12
+|15: 13 line 13
+|16: 14 line 14
+|17: 15 line 15
+|18: 16 line 16
+|19: 17 line 17
+|20: 18 line 18
+|21: 19 line 19
+|22: 20 line 20
+|23: 21 line 21
+|24: 22 line 22
+|25: 23 line 23
+== snap step4-line100 grid=150x31 cursor=7,14
+|3: 89 line 89 ls
+|4: 90 line 90 big.txt
+|5: 91 line 91
+|6: 92 line 92
+|7: 93 line 93
+|8: 94 line 94
+|9: 95 line 95
+|10: 96 line 96
+|11: 97 line 97
+|12: 98 line 98
+|13: 99 line 99
+|14: 100 line 100
+|15: 101 line 101
+|16: 102 line 102
+|17: 103 line 103
+|18: 104 line 104
+|19: 105 line 105
+|20: 106 line 106
+|21: 107 line 107
+|22: 108 line 108
+|23: 109 line 109
+|24: 110 line 110
+|25: 111 line 111
|27: 2 /tmp/pardes-snap/jumps/cwd/big.txt:1:1 line 1
|28: 3 @p1:3:3 /tmp/pardes-snap/jumps/cwd
|29: 4 /tmp/pardes-snap/jumps/cwd/big.txt:100:1 line 100
-== snap step1-shell grid=150x30 cursor=79,4
-== style step1-shell grid=150x30
-|0: 0-74 #949494,#121212, 75-149 d,#121212,
-|1: 0-1 #ffffff,#262626, 2-55 #949494,#121212, 56-74 d,#121212, 75-76 #ffffff,#626262, 77-129 #949494,#121212, 130-149 d,#121212,
-|2: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|3: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|4: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|5: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|6: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|7: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|8: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|9: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|10: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|11: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|13: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|14: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|15: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|16: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-14 #bdbdbd,#080808, 15-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|17: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-14 #bdbdbd,#080808, 15-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|18: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-14 #bdbdbd,#080808, 15-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|19: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-14 #bdbdbd,#080808, 15-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|20: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-14 #bdbdbd,#080808, 15-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|21: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-14 #bdbdbd,#080808, 15-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|22: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-14 #bdbdbd,#080808, 15-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|23: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-14 #bdbdbd,#080808, 15-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|24: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-14 #bdbdbd,#080808, 15-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|25: 0-1 #ffffff,#262626, 2-55 #949494,#121212, 56-74 d,#121212, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-40 #bdbdbd,#080808, 41-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-51 #bdbdbd,#080808, 52-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-40 #bdbdbd,#080808, 41-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|29: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-55 #bdbdbd,#080808, 56-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-== snap step2-file grid=150x30 cursor=7,2
-|2: 1 line 1 ls
-|3: 2 line 2 big.txt
-|4: 3 line 3
-|5: 4 line 4
-|6: 5 line 5
-|7: 6 line 6
-|8: 7 line 7
-|9: 8 line 8
-|10: 9 line 9
-|11: 10 line 10
-|12: 11 line 11
-|13: 12 line 12
-|14: 13 line 13
-|15: 14 line 14
-|16: 15 line 15
-|17: 16 line 16
-|18: 17 line 17
-|19: 18 line 18
-|20: 19 line 19
-|21: 20 line 20
-|22: 21 line 21
-|23: 22 line 22
-|24: 23 line 23
-== snap step4-line100 grid=150x30 cursor=7,13
-|2: 89 line 89 ls
-|3: 90 line 90 big.txt
-|4: 91 line 91
-|5: 92 line 92
-|6: 93 line 93
-|7: 94 line 94
-|8: 95 line 95
-|9: 96 line 96
-|10: 97 line 97
-|11: 98 line 98
-|12: 99 line 99
-|13: 100 line 100
-|14: 101 line 101
-|15: 102 line 102
-|16: 103 line 103
-|17: 104 line 104
-|18: 105 line 105
-|19: 106 line 106
-|20: 107 line 107
-|21: 108 line 108
-|22: 109 line 109
-|23: 110 line 110
-|24: 111 line 111
-|26: 2 /tmp/pardes-snap/jumps/cwd/big.txt:1:1 line 1
-|27: 3 @p1:3:3 /tmp/pardes-snap/jumps/cwd
-|28: 4 /tmp/pardes-snap/jumps/cwd/big.txt:100:1 line 100
-|29: 5
-== snap step-back grid=150x30 cursor=79,4
-== snap look-row grid=150x30 cursor=7,13
+|30: 5
+== snap step-back grid=150x31 cursor=79,5
+== snap look-row grid=150x31 cursor=7,14
diff --git a/test/snapshots/jumps.snap b/test/snapshots/jumps.snap
index 52791ed1..e4816f88 100644
--- a/test/snapshots/jumps.snap
+++ b/test/snapshots/jumps.snap
@@ -10,7 +10,7 @@
# Focus and position both show in the golden's `cursor=` header: that is the
# ACTIVE pane's cursor, so each snap is named by where it should land.
lines big.txt 200
-start 30 150 big.txt
+start 31 150 big.txt
wait 8000 big.txt
stable 700 20000
# a FILE boots alone now, so this is one column holding big.txt, focused, and
@@ -113,7 +113,7 @@ snap step-back
# again, this time by clicking it: the walk above scrolled the list by one, so
# the last four screen rows are its rows 2 through 5 and row 4 is the second
# from the bottom.
-press right 16 29
-release right 16 29
+press right 16 30
+release right 16 30
stable 700 15000
snap look-row
diff --git a/test/snapshots/layout-close.golden b/test/snapshots/layout-close.golden
index 69de749a..9e573802 100644
--- a/test/snapshots/layout-close.golden
+++ b/test/snapshots/layout-close.golden
@@ -1,18 +1,19 @@
-== snap built grid=140x40 cursor=4,16
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/layout-close/cwd Save New Newtty Del Filter /tmp/pardes-snap/layout-close/cwd Save New Newtty Del Filter
+== snap built grid=140x41 cursor=4,17
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/layout-close/cwd Save Tty Del Togglettymode Filter /tmp/pardes-snap/layout-close/cwd Save Tty Del Togglettymode Filter
| ls ls
| marker.txt marker.txt
|
-| /tmp/pardes-snap/layout-close/cwd Save New Newtty Del Filter
+| /tmp/pardes-snap/layout-close/cwd Save Tty Del Togglettymode Filter
| ls
| marker.txt
|
-| /tmp/pardes-snap/layout-close/cwd Save New Newtty Del Filter
+| /tmp/pardes-snap/layout-close/cwd Save Tty Del Togglettymode Filter
| ls
| marker.txt
|
-| /tmp/pardes-snap/layout-close/cwd Save New Newtty Del Filter
+| /tmp/pardes-snap/layout-close/cwd Save Tty Del Togglettymode Filter
| ls
| marker.txt
|
@@ -20,29 +21,31 @@
|
|
|
-| /tmp/pardes-snap/layout-close/cwd Save New Newtty Del Filter
+| /tmp/pardes-snap/layout-close/cwd Save Tty Del Togglettymode Filter
| ls
| marker.txt
-== snap altc grid=140x40 cursor=39,4
-|1: /tmp/pardes-snap/layout-close/cwd /tmp/pardes-snap/layout-close/cwd /tmp/pardes-snap/layout-close/cwd Save New Newtty Del Filter
-|2: ls ls ls
-|3: marker.txt marker.txt marker.txt
-|5: /tmp/pardes-snap/layout-close/cwd
-|9: /tmp/pardes-snap/layout-close/cwd
-|13:
+== snap altc grid=140x41 cursor=39,5
+|1: New Tty Find Grep Joincol New Tty Find Grep Joincol New Tty Find Grep Joincol
+|2: /tmp/pardes-snap/layout-close/cwd /tmp/pardes-snap/layout-close/cwd /tmp/pardes-snap/layout-close/cwd Save Tty Del Togglettymode Filter
+|3: ls ls ls
+|4: marker.txt marker.txt marker.txt
+|6: /tmp/pardes-snap/layout-close/cwd
+|10: /tmp/pardes-snap/layout-close/cwd
|14:
|15:
-|21: /tmp/pardes-snap/layout-close/cwd
-== snap del grid=140x40 cursor=39,4
-|5:
+|16:
+|22: /tmp/pardes-snap/layout-close/cwd
+== snap del grid=140x41 cursor=39,5
|6:
|7:
-== snap exit grid=140x40 cursor=39,4
-|9:
+|8:
+== snap exit grid=140x41 cursor=39,5
|10:
|11:
-== snap colclose grid=140x40 cursor=4,7
-|1: /tmp/pardes-snap/layout-close/cwd Save New Newtty Del Filter /tmp/pardes-snap/layout-close/cwd Save New Newtty Del Filter
-|2: ls ls
-|3: marker.txt marker.txt
-|21: /tmp/pardes-snap/layout-close/cwd Save New Newtty Del Filter
+|12:
+== snap colclose grid=140x41 cursor=4,8
+|1: New Tty Find Grep Joincol New Tty Find Grep Joincol
+|2: /tmp/pardes-snap/layout-close/cwd Save Tty Del Togglettymode Filter /tmp/pardes-snap/layout-close/cwd Save Tty Del Togglettymode Filter
+|3: ls ls
+|4: marker.txt marker.txt
+|22: /tmp/pardes-snap/layout-close/cwd Save Tty Del Togglettymode Filter
diff --git a/test/snapshots/layout-close.snap b/test/snapshots/layout-close.snap
index d539d22b..3d28e1d5 100644
--- a/test/snapshots/layout-close.snap
+++ b/test/snapshots/layout-close.snap
@@ -2,13 +2,13 @@
# keeps its sizes: Alt-c move-out, tag Del, and shell exit (pty EOF); an
# emptied column hands its width to one neighbor
file marker.txt x
-start 40 140 -n 3
+start 41 140 -n 3
wait 8000 marker.txt
stable 700 20000
# build a left column of five: Alt-n three times from pane 0 (active follows
# the new pane, each split takes from the freshly split pane only)
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key a-n
stable 700 15000
@@ -25,8 +25,8 @@ snap altc
# Del the 2nd pane: source-local column insertion makes this column too narrow
# to expose its tag words, so focus its body and invoke the same pane-scoped
# builtin by chord. The pane above absorbs; the other panes keep their rows.
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key space d
stable 700 10000
@@ -34,8 +34,8 @@ snap del
# exit the (now) 2nd shell through its real tty: pty EOF, again only the pane
# above absorbs — and focus falls back to the
# pane that had it before this one (the moved-out column), not to slot 0
-press left 5 14
-release left 5 14
+press left 5 15
+release left 5 15
stable 400 5000
key c-b
stable 400 5000
@@ -45,8 +45,8 @@ stable 700 10000
snap exit
# exit the moved-out pane's shell: its column empties and returns its width to
# the source column it was carved from; the untouched right column stays put
-press left 40 8
-release left 40 8
+press left 40 9
+release left 40 9
stable 400 5000
key c-b
stable 400 5000
diff --git a/test/snapshots/layout-open.golden b/test/snapshots/layout-open.golden
index 776b1b0b..569f98b2 100644
--- a/test/snapshots/layout-open.golden
+++ b/test/snapshots/layout-open.golden
@@ -1,6 +1,7 @@
-== snap before grid=100x30 cursor=2,8
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/layout-open/cwd Save New Newtty /tmp/pardes-snap/layout-open/cwd Save New Newtty
+== snap before grid=100x31 cursor=2,9
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/layout-open/cwd Save Tty Del To /tmp/pardes-snap/layout-open/cwd Save Tty Del To
| ls ls
| sub sub
|
@@ -15,23 +16,21 @@
|
|
|
-| /tmp/pardes-snap/layout-open/cwd Save New Newtty
+| /tmp/pardes-snap/layout-open/cwd Save Tty Del To
| ls
| sub
-== snap altn-left grid=100x30 cursor=4,8
-|5: /tmp/pardes-snap/layout-open/cwd Save New Newtty
-|6: ls
-|7: sub
-== snap altn-right grid=100x30 cursor=54,8
-|5: /tmp/pardes-snap/layout-open/cwd Save New Newtty /tmp/pardes-snap/layout-open/cwd Save New Newtty
-|6: ls ls
-|7: sub sub
-== snap file-open grid=100x30 cursor=7,2
-|1: /tmp/pardes-snap/layout-open/cwd/sub/f.txt Save /tmp/pardes-snap/layout-open/cwd Save New Newtty
-|2: 1 echo 'TTY'OK ls
-|3: /tmp/pardes-snap/layout-open/cwd Save New Newtty sub
-|26: sub/f.txt
-== snap ttydir grid=100x30 cursor=7,2
-|9: /tmp/pardes-snap/layout-open/cwd/sub Save New Ne
-|10: echo 'TTY'OK
-|11: TTYOK
+== snap altn-left grid=100x31 cursor=4,9
+|6: /tmp/pardes-snap/layout-open/cwd Save Tty Del To
+|7: ls
+|8: sub
+== snap altn-right grid=100x31 cursor=54,9
+|6: /tmp/pardes-snap/layout-open/cwd Save Tty Del To /tmp/pardes-snap/layout-open/cwd Save Tty Del To
+|7: ls ls
+|8: sub sub
+== snap file-open grid=100x31 cursor=7,22
+|21: /tmp/pardes-snap/layout-open/cwd/sub/f.txt Save
+|22: 1 echo 'TTY'OK
+== snap ttydir grid=100x31 cursor=7,22
+|10: /tmp/pardes-snap/layout-open/cwd/sub Save Tty De
+|11: echo 'TTY'OK
+|12: TTYOK
diff --git a/test/snapshots/layout-open.snap b/test/snapshots/layout-open.snap
index 1198b685..d7d7e19e 100644
--- a/test/snapshots/layout-open.snap
+++ b/test/snapshots/layout-open.snap
@@ -1,17 +1,16 @@
# every pane open splits ONE existing pane, the rest of the column keeps its
# sizes: Alt-n splits the active pane, an execute-spawned shell for a file's
-# dir splits only the bottom pane of the rightmost column. The first looked-up
-# file is the exception: it takes a NEW leftmost column, splitting nothing —
-# and takes width only from the column that opened it; unrelated columns stay
-# at the exact same x/width
+# dir splits only the bottom pane of the rightmost column. At this narrow
+# width the first looked-up file also splits below its source, leaving every
+# unrelated pane (including the ones above the source) at its exact rectangle.
dirmk sub
file sub/f.txt echo 'TTY'OK
-start 30 100 -n 3
+start 31 100 -n 3
wait 8000 sub
stable 700 20000
# give pane 0 (top-left) some content so its content-height split is visible
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key i
text echo one; echo two
@@ -25,33 +24,32 @@ key a-n
stable 700 15000
snap altn-left
# make the right column two panes (Alt-n in a fresh column, trivial split)
-press left 70 8
-release left 70 8
+press left 70 9
+release left 70 9
stable 400 5000
key a-n
stable 700 15000
snap altn-right
-# look sub/f.txt from the bottom-left shell: the first doc takes a new leftmost
-# column of its own — every pane keeps its rows, the source column alone pays
-# half its width, and the right column keeps its exact rectangle
-press left 5 27
-release left 5 27
+# look sub/f.txt from the bottom-left shell: the first doc splits this shell,
+# not the top-left pane. Both panes above it and the entire right column stay put.
+press left 5 28
+release left 5 28
stable 400 5000
key i
text sub/f.txt
key esc
settle 100
stable 400 5000
-press right 7 27
-release right 7 27
+press right 7 28
+release right 7 28
stable 700 15000
snap file-open
# execute the file's command (middle drag over line 1): no shell has cwd sub/,
# so one is forked at the bottom of the rightmost column, splitting only the
# pane above it
-press middle 8 3
-drag middle 19 3
-release middle 19 3
+press middle 8 23
+drag middle 19 23
+release middle 19 23
wait 10000 TTYOK
motion 40 25
stable 700 10000
diff --git a/test/snapshots/leader.golden b/test/snapshots/leader.golden
index fd4fbf98..d084250c 100644
--- a/test/snapshots/leader.golden
+++ b/test/snapshots/leader.golden
@@ -1,6 +1,7 @@
-== snap spc grid=100x40 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/leader/cwd/cmds.txt Save New Newtty Del
+== snap spc grid=100x41 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/leader/cwd/cmds.txt Save Tty Del Collapse
| 1 Help
|
|
@@ -39,32 +40,31 @@
|
|
| SPC
-== snap spc-h grid=100x40 cursor=7,2
-|39: SPC h
-== snap abandoned grid=100x40 cursor=7,2
-|39:
-== snap unmapped grid=100x40 cursor=7,2
-== snap help-group grid=100x40 cursor=7,22
-|21: /tmp/pardes-snap/leader/cwd/+Help Save New Newtty Del
-|22: 1 pardes builtins under SPC h
-|23: 2
-|24: 3 SPC h c Changelog topbar
-|25: 4 SPC h m Messages
-|26: 5 SPC h t Tutor topbar
-|27: 6
-== snap tutor grid=100x40 cursor=7,12
-|11: /Tutor Save New Newtty Del
-|12: 1
-|13: 2 PARDES TUTOR
-|14: 3 tmux + vi + acme, from scratch.
-|15: 4
-|16: 5 The model is acme's: EVERYTHING is text, editable and executable
-|17: 6 the same way. Modal editing (helix-style) lives on top of that.
-|18: 7 Press j until you reach the introduction.
-|19: 8
-|20: 9
-== snap deleted grid=100x40 cursor=7,22
-|11:
+== snap spc-h grid=100x41 cursor=7,3
+|40: SPC h
+== snap abandoned grid=100x41 cursor=7,3
+|40:
+== snap unmapped grid=100x41 cursor=7,3
+== snap help-group grid=100x41 cursor=7,23
+|22: /tmp/pardes-snap/leader/cwd/+Help Save Tty Del Collapse
+|23: 1 pardes builtins under SPC h
+|24: 2
+|25: 3 SPC h c Changelog topbar
+|26: 4 SPC h m Messages
+|27: 5 SPC h t Tutor topbar
+|28: 6
+== snap tutor grid=100x41 cursor=7,13
+|12: /Tutor Save Tty Del Collapse
+|13: 1
+|14: 2 PARDES TUTOR
+|15: 3 tmux + vi + acme, from scratch.
+|16: 4
+|17: 5 The model is acme's: EVERYTHING is text, editable and executable
+|18: 6 the same way. Modal editing (helix-style) lives on top of that.
+|19: 7 Press j until you reach the introduction.
+|20: 8
+|21: 9
+== snap deleted grid=100x41 cursor=7,23
|12:
|13:
|14:
@@ -74,32 +74,32 @@
|18:
|19:
|20:
-== snap help-window grid=100x40 cursor=7,22
-|22: 1 pardes builtins under SPC w
-|24: 3 SPC w h Left C-w h, C-w left
-|25: 4 SPC w j Down C-w j, C-w down
-|26: 5 SPC w k Up C-w k, C-w up
-|27: 6 SPC w l Right C-w l, C-w right
-|28: 7
-== snap help-language grid=100x40 cursor=7,22
-|22: 1 pardes builtins under SPC l
-|24: 3 SPC l C Callees
-|25: 4 SPC l D WsDiagnostics
-|26: 5 SPC l S WsSymbols
-|27: 6 SPC l T Subtypes
-|28: 7 SPC l a CodeAction
-|29: 8 SPC l c Callers
-|30: 9 SPC l d Diagnostics
-|31: 10 SPC l h SelectRefs
-|32: 11 SPC l i Lspinfo
-|33: 12 SPC l k Hover
-|34: 13 SPC l r Rename
-|35: 14 SPC l s Symbols
-|36: 15 SPC l t Supertypes
-|37: 16 SPC l w Lspwhy
-|38: 17
-== snap del-output grid=100x40 cursor=7,2
|21:
+== snap help-window grid=100x41 cursor=7,23
+|23: 1 pardes builtins under SPC w
+|25: 3 SPC w h Left C-w h, C-w left
+|26: 4 SPC w j Down C-w j, C-w down
+|27: 5 SPC w k Up C-w k, C-w up
+|28: 6 SPC w l Right C-w l, C-w right
+|29: 7
+== snap help-language grid=100x41 cursor=7,23
+|23: 1 pardes builtins under SPC l
+|25: 3 SPC l C Callees
+|26: 4 SPC l D WsDiagnostics
+|27: 5 SPC l S WsSymbols
+|28: 6 SPC l T Subtypes
+|29: 7 SPC l a CodeAction
+|30: 8 SPC l c Callers
+|31: 9 SPC l d Diagnostics
+|32: 10 SPC l h SelectRefs
+|33: 11 SPC l i Lspinfo
+|34: 12 SPC l k Hover
+|35: 13 SPC l r Rename
+|36: 14 SPC l s Symbols
+|37: 15 SPC l t Supertypes
+|38: 16 SPC l w Lspwhy
+|39: 17
+== snap del-output grid=100x41 cursor=7,3
|22:
|23:
|24:
@@ -117,3 +117,4 @@
|36:
|37:
|38:
+|39:
diff --git a/test/snapshots/leader.snap b/test/snapshots/leader.snap
index eb253b37..f018a88c 100644
--- a/test/snapshots/leader.snap
+++ b/test/snapshots/leader.snap
@@ -1,6 +1,6 @@
file cmds.txt Help
-start 40 100 cmds.txt
-wait 8000 New Newcol
+start 41 100 cmds.txt
+wait 8000 Newcol Joincol
wait 8000 cmds.txt
stable 700 20000
@@ -19,8 +19,8 @@ stable 400 5000
snap unmapped
# Executing Help as text opens the full index, not a filtered group.
-press middle @Help 3
-release middle @Help 3
+press middle @Help 4
+release middle @Help 4
wait 10000 pardes builtins, and how to run each:
wait 10000 ClipPasteBefore
key space h ?
diff --git a/test/snapshots/load.golden b/test/snapshots/load.golden
index bc5d5ddd..ebfe6a39 100644
--- a/test/snapshots/load.golden
+++ b/test/snapshots/load.golden
@@ -1,6 +1,7 @@
-== snap loaded grid=100x30 cursor=4,15
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/load/cwd Save New Newtty Del Fi /tmp/pardes-snap/load/cwd Save New Newtty Del Fi
+== snap loaded grid=100x31 cursor=4,16
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/load/cwd Save Tty Del Toggletty /tmp/pardes-snap/load/cwd Save Tty Del Toggletty
| echo LOAD''MARK; seq 1 40; echo E''ND ls
| LOADMARK d.txt
| 1
@@ -15,37 +16,38 @@
| 10
| 11
| 12
-| /tmp/pardes-snap/load/cwd Save New Newtty Del Fi
+| /tmp/pardes-snap/load/cwd Save Tty Del Toggletty
| ls
| d.txt
-== style loaded grid=100x30
-|0: 0-74 #949494,#121212, 75-99 d,#121212,
-|1: 0-1 #ffffff,#626262, 2-49 #949494,#121212, 50-51 #ffffff,#262626, 52-99 #949494,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|6: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|7: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|8: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|9: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|10: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|11: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|12: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|13: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|14: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|15: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|16: 0-1 #ffffff,#262626, 2-49 #949494,#121212, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|19: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|29: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
+== style loaded grid=100x31
+|0: 0-70 #b2c3b8,#1d2824, 71-99 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-49 d,#26362d, 50-74 #b2c3b8,#1d2824, 75-99 d,#1d2824,
+|2: 0-1 #000000,#adcc91, 2-49 #becfc4,#26362d, 50-51 #ffffff,#4c6356, 52-99 #b2c3b8,#1d2824,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|7: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|8: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|9: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|10: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|11: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|12: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|13: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|14: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|15: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|16: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|17: 0-1 #ffffff,#4c6356, 2-49 #b2c3b8,#1d2824, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|20: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
diff --git a/test/snapshots/load.snap b/test/snapshots/load.snap
index 8ae63b28..62c661b7 100644
--- a/test/snapshots/load.snap
+++ b/test/snapshots/load.snap
@@ -3,7 +3,7 @@
# own regression baseline). Shell output survives the replay; typed insert runs
# are an overlay and do not (same semantics as the old replay viewer).
file d.txt x
-start 30 100 -n 3
+start 31 100 -n 3
wait 8000 d.txt
stable 700 20000
key c-b
@@ -20,7 +20,7 @@ stable 500 8000
press middle @Dump 1
release middle @Dump 1
stable 600 8000
-start 30 100 -l $DUMP
+start 31 100 -l $DUMP
wait 8000 LOADMARK
stable 700 20000
snap loaded
diff --git a/test/snapshots/logquiet.golden b/test/snapshots/logquiet.golden
index 48dcd3a6..d5c4703b 100644
--- a/test/snapshots/logquiet.golden
+++ b/test/snapshots/logquiet.golden
@@ -1,6 +1,7 @@
-== snap quiet grid=100x30 cursor=62,4
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|$ /tmp/pardes-snap/logquiet/cwd Save New Newtty Del Filter
+== snap quiet grid=100x31 cursor=62,5
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+|$ /tmp/pardes-snap/logquiet/cwd Save Tty Del Togglettymode Filter Collapse
| $ ls
| $ printf '\033_Ga=q,i=1,s=1,v=1,f=24,t=d;AAAA\033\\\033[>0p'
| $ '\033_Ga=q,i=1,s=1,v=1,f=24,t=d;AAAA\033\\\033[>0p'Gi=1;OK
diff --git a/test/snapshots/logquiet.snap b/test/snapshots/logquiet.snap
index a16db2be..fb3e2653 100644
--- a/test/snapshots/logquiet.snap
+++ b/test/snapshots/logquiet.snap
@@ -5,8 +5,8 @@
# (`debug(kitty_gfx): executing kitty graphics command`) and a private CSI p
# (`warning(stream): ignoring unimplemented CSI p with intermediates: >`).
# The golden is the assertion that neither reaches the screen.
-start 30 100 -n 1
-wait 8000 New Newcol
+start 31 100 -n 1
+wait 8000 Newcol Joincol
stable 700 20000
key c-b
stable 600 8000
diff --git a/test/snapshots/look-center.golden b/test/snapshots/look-center.golden
index 94b2d0a5..7509da8f 100644
--- a/test/snapshots/look-center.golden
+++ b/test/snapshots/look-center.golden
@@ -1,34 +1,43 @@
-== snap center-open grid=150x30 cursor=7,5
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/look-center/cwd/big.txt Save New Newtty Del /tmp/pardes-snap/look-center/cwd Save New Newtty Del Filter
-| 97 line 97 ls
-| 98 line 98 big.txt
+== snap center-open grid=150x31 cursor=7,12
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/look-center/cwd Save Tty Del Togglettymode Filter Collap /tmp/pardes-snap/look-center/cwd Save Tty Del Togglettymode Filter Collap
+| ls ls
+| big.txt big.txt
+|
+| /tmp/pardes-snap/look-center/cwd/big.txt Save Tty Del Collapse
+| 95 line 95
+| 96 line 96
+| 97 line 97
+| 98 line 98
| 99 line 99
| 100 line 100
| 101 line 101
-|╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
-| /tmp/pardes-snap/look-center/cwd Save New Newtty Del Filter
-| ls
-| big.txt
-|
-|
-|
-| big.txt:100 big.txt:150 big.txt:2
-|
-| /tmp/pardes-snap/look-center/cwd Save New Newtty Del Filter
+| 102 line 102
+| 103 line 103
+| 104 line 104
+| /tmp/pardes-snap/look-center/cwd Save Tty Del Togglettymode Filter Collap
| ls
| big.txt
-== snap center-dedup grid=150x30 cursor=7,5
-|2: 147 line 147 ls
-|3: 148 line 148 big.txt
-|4: 149 line 149
-|5: 150 line 150
-|6: 151 line 151
-|7: 152 line 152
-== snap center-clamp grid=150x30 cursor=7,3
-|2: 1 line 1 ls
-|3: 2 line 2 big.txt
-|4: 3 line 3
-|5: 4 line 4
-|6: 5 line 5
-|7: 6 line 6
+== snap center-dedup grid=150x31 cursor=7,12
+|7: 145 line 145
+|8: 146 line 146 big.txt:150 big.txt:2
+|9: 147 line 147
+|10: 148 line 148
+|11: 149 line 149
+|12: 150 line 150
+|13: 151 line 151
+|14: 152 line 152
+|15: 153 line 153
+|16: 154 line 154
+== snap center-clamp grid=150x31 cursor=7,8
+|7: 1 line 1
+|8: 2 line 2 big.txt:150 big.txt:2
+|9: 3 line 3
+|10: 4 line 4
+|11: 5 line 5
+|12: 6 line 6
+|13: 7 line 7
+|14: 8 line 8
+|15: 9 line 9
+|16: 10 line 10
diff --git a/test/snapshots/look-center.snap b/test/snapshots/look-center.snap
index 1b11bfd8..25fb64b0 100644
--- a/test/snapshots/look-center.snap
+++ b/test/snapshots/look-center.snap
@@ -3,26 +3,34 @@
# the same path re-center the existing pane, and a look near line 1 clamps
# the scroll at 0 (no negative scroll)
lines big.txt 200
-start 30 150 -n 3
+start 31 150 -n 3
wait 8000 big.txt
stable 700 20000
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key i
text big.txt:100 big.txt:150 big.txt:2
key esc
settle 100
stable 400 5000
-press right 7 8
-release right 7 8
+press right 7 9
+release right 7 9
stable 700 15000
snap center-open
-press right 18 15
-release right 18 15
+# The narrow-window split keeps the source shell above the new file. Use the
+# unchanged right-hand shell for the remaining references, so they stay visible.
+press left 80 9
+release left 80 9
+key i
+text big.txt:150 big.txt:2
+key esc
+stable 400 5000
+press right 82 9
+release right 82 9
stable 700 15000
snap center-dedup
-press right 30 15
-release right 30 15
+press right 94 9
+release right 94 9
stable 700 15000
snap center-clamp
diff --git a/test/snapshots/look-dir.golden b/test/snapshots/look-dir.golden
index e6429b35..e859a3f4 100644
--- a/test/snapshots/look-dir.golden
+++ b/test/snapshots/look-dir.golden
@@ -1,10 +1,11 @@
-== snap dir-open grid=100x30 cursor=4,8
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/look-dir/cwd Save New Newtty De /tmp/pardes-snap/look-dir/cwd Save New Newtty De
+== snap dir-open grid=100x31 cursor=4,9
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/look-dir/cwd Save Tty Del Toggl /tmp/pardes-snap/look-dir/cwd Save Tty Del Toggl
| ls ls
| sub top.txt sub top.txt
|
-| /tmp/pardes-snap/look-dir/cwd/sub Save New Newtt
+| /tmp/pardes-snap/look-dir/cwd/sub Save Tty Del T
| ls
| inner.txt
|
@@ -15,6 +16,6 @@
|
|
|
-| /tmp/pardes-snap/look-dir/cwd Save New Newtty De
+| /tmp/pardes-snap/look-dir/cwd Save Tty Del Toggl
| ls
| sub top.txt
diff --git a/test/snapshots/look-dir.snap b/test/snapshots/look-dir.snap
index 918a5de5..caf29da8 100644
--- a/test/snapshots/look-dir.snap
+++ b/test/snapshots/look-dir.snap
@@ -2,19 +2,19 @@
dirmk sub
file sub/inner.txt inner-marker
file top.txt x
-start 30 100 -n 3
+start 31 100 -n 3
wait 8000 top.txt
stable 700 20000
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key i
text sub
key esc
settle 100
stable 400 5000
-press right 6 8
-release right 6 8
+press right 6 9
+release right 6 9
wait 10000 inner.txt
stable 700 20000
snap dir-open
diff --git a/test/snapshots/look-file-1col.golden b/test/snapshots/look-file-1col.golden
index fb364e87..553e1942 100644
--- a/test/snapshots/look-file-1col.golden
+++ b/test/snapshots/look-file-1col.golden
@@ -1,6 +1,17 @@
-== snap file-open-1col grid=100x30 cursor=7,8
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/look-file-1col/cwd/big.txt Save New Newtty Del
+== snap file-open-1col grid=100x31 cursor=7,19
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/look-file-1col/cwd Save Tty Del Togglettymode Filter Collapse
+| ls
+| big.txt
+|
+| /tmp/pardes-snap/look-file-1col/cwd/big.txt Save Tty Del Collapse
+| 28 line 28
+| 29 line 29
+| 30 line 30
+| 31 line 31
+| 32 line 32
+| 33 line 33
| 34 line 34
| 35 line 35
| 36 line 36
@@ -14,10 +25,8 @@
| 44 line 44
| 45 line 45
| 46 line 46
-| /tmp/pardes-snap/look-file-1col/cwd Save New Newtty Del Filter
-| ls
-| big.txt
-|
-|
-|
-| big.txt:40
+| 47 line 47
+| 48 line 48
+| 49 line 49
+| 50 line 50
+| 51 line 51
diff --git a/test/snapshots/look-file-1col.snap b/test/snapshots/look-file-1col.snap
index ce0ec78d..490aaf38 100644
--- a/test/snapshots/look-file-1col.snap
+++ b/test/snapshots/look-file-1col.snap
@@ -1,19 +1,18 @@
-# single column (-n 1): the session's FIRST doc always gets a column of its
-# own, so a look from the lone shell puts the file beside it (not below it) —
-# the shell keeps its own column, both halve the width
+# single narrow column (-n 1): the first document splits below its source
+# shell, like Tty. A new column would require at least 200 cells of width.
lines big.txt 60
-start 30 100 -n 1
+start 31 100 -n 1
wait 8000 big.txt
stable 700 20000
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key i
text big.txt:40
key esc
settle 100
stable 400 5000
-press right 7 8
-release right 7 8
+press right 7 9
+release right 7 9
stable 700 15000
snap file-open-1col
diff --git a/test/snapshots/look-file.golden b/test/snapshots/look-file.golden
index 80750476..dccbb07c 100644
--- a/test/snapshots/look-file.golden
+++ b/test/snapshots/look-file.golden
@@ -1,51 +1,53 @@
-== snap file-open grid=150x30 cursor=7,5
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/look-file/cwd/big.txt Save New Newtty Del /tmp/pardes-snap/look-file/cwd Save New Newtty Del Filter
-| 37 line 37 ls
-| 38 line 38 big.txt
+== snap file-open grid=150x31 cursor=7,12
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/look-file/cwd Save Tty Del Togglettymode Filter Collapse /tmp/pardes-snap/look-file/cwd Save Tty Del Togglettymode Filter Collapse
+| ls ls
+| big.txt big.txt
+|
+| /tmp/pardes-snap/look-file/cwd/big.txt Save Tty Del Collapse
+| 35 line 35
+| 36 line 36
+| 37 line 37
+| 38 line 38
| 39 line 39
| 40 line 40
| 41 line 41
-|╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
-| /tmp/pardes-snap/look-file/cwd Save New Newtty Del Filter
-| ls
-| big.txt
-|
-|
-|
-| big.txt:40
-|
-| /tmp/pardes-snap/look-file/cwd Save New Newtty Del Filter
+| 42 line 42
+| 43 line 43
+| 44 line 44
+| /tmp/pardes-snap/look-file/cwd Save Tty Del Togglettymode Filter Collapse
| ls
| big.txt
-== style file-open grid=150x30
-|0: 0-74 #949494,#121212, 75-149 d,#121212,
-|1: 0-1 #ffffff,#626262, 2-59 #949494,#121212, 60-74 d,#121212, 75-76 #ffffff,#262626, 77-133 #949494,#121212, 134-149 d,#121212,
-|2: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|3: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|4: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-13 #bdbdbd,#080808, 14-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|6: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|7: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|8: 0-1 #ffffff,#262626, 2-59 #949494,#121212, 60-74 d,#121212, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|11: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-13 #bdbdbd,#080808, 14-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|16: 0-1 #ffffff,#262626, 2-59 #949494,#121212, 60-74 d,#121212, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|19: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|29: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
+== style file-open grid=150x31
+|0: 0-70 #b2c3b8,#1d2824, 71-149 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-74 d,#26362d, 75-99 #b2c3b8,#1d2824, 100-149 d,#1d2824,
+|2: 0-1 #ffffff,#4c6356, 2-74 #b2c3b8,#1d2824, 75-76 #ffffff,#4c6356, 77-149 #b2c3b8,#1d2824,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|5: 0-0 d,#637f6a, 1-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|6: 0-1 #000000,#adcc91, 2-61 #becfc4,#26362d, 62-74 d,#26362d, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|7: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|8: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|9: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|10: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|11: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|13: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|14: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|15: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|16: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|17: 0-1 #ffffff,#4c6356, 2-74 #b2c3b8,#1d2824, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|20: 0-0 d,#637f6a, 1-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
diff --git a/test/snapshots/look-file.snap b/test/snapshots/look-file.snap
index 4b8b39b7..a6140155 100644
--- a/test/snapshots/look-file.snap
+++ b/test/snapshots/look-file.snap
@@ -1,19 +1,19 @@
# right-click look on a typed path:NN opens a file pane scrolled to the line;
# Enter chord on the same path focuses the existing pane (dedup)
lines big.txt 60
-start 30 150 -n 3
+start 31 150 -n 3
wait 8000 big.txt
stable 700 20000
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key i
text big.txt:40
key esc
settle 100
stable 400 5000
-press right 7 8
-release right 7 8
+press right 7 9
+release right 7 9
stable 700 15000
snap file-open
snapstyle file-open
diff --git a/test/snapshots/lookloaded.golden b/test/snapshots/lookloaded.golden
index 53b3781d..1ff8c44f 100644
--- a/test/snapshots/lookloaded.golden
+++ b/test/snapshots/lookloaded.golden
@@ -1,26 +1,35 @@
-== snap file-open grid=100x30 cursor=7,5
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/lookloaded/cwd/big.txt Save New /tmp/pardes-snap/lookloaded/cwd Save New Newtty
-| 37 line 37 ls
-| 38 line 38 big.txt
+== snap file-open grid=100x31 cursor=7,12
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/lookloaded/cwd Save Tty Del Tog /tmp/pardes-snap/lookloaded/cwd Save Tty Del Tog
+| ls ls
+| big.txt big.txt
+|
+| /tmp/pardes-snap/lookloaded/cwd/big.txt Save Tty
+| 35 line 35
+| 36 line 36
+| 37 line 37
+| 38 line 38
| 39 line 39
| 40 line 40
| 41 line 41
-|╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
-| /tmp/pardes-snap/lookloaded/cwd Save New Newtty
-| ls
-| big.txt
-|
-|
-|
-| big.txt:40 big.txt:10
-|
-| /tmp/pardes-snap/lookloaded/cwd Save New Newtty
+| 42 line 42
+| 43 line 43
+| 44 line 44
+| /tmp/pardes-snap/lookloaded/cwd Save Tty Del Tog
| ls
| big.txt
-== snap removed grid=100x30 cursor=4,13
-|7: 42 line 42
-|11: rm big.txt; echo GO''NE
-|12: GONE
-== snap look-noFS grid=100x30 cursor=44,7
-|7: ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
+== snap removed grid=100x31 cursor=54,7
+|5: rm big.txt; echo GO''NE
+|6: /tmp/pardes-snap/lookloaded/cwd/big.txt Save Tty GONE
+== snap look-noFS grid=100x31 cursor=7,12
+|7: 5 line 5
+|8: 6 line 6 big.txt:10
+|9: 7 line 7
+|10: 8 line 8
+|11: 9 line 9
+|12: 10 line 10
+|13: 11 line 11
+|14: 12 line 12
+|15: 13 line 13
+|16: 14 line 14
diff --git a/test/snapshots/lookloaded.snap b/test/snapshots/lookloaded.snap
index 5341a063..1f920a93 100644
--- a/test/snapshots/lookloaded.snap
+++ b/test/snapshots/lookloaded.snap
@@ -3,24 +3,25 @@
# loaded pane focuses and recenters even though realpath now fails. (This
# fs-last ordering is what lets the fs-less web build focus dump panes.)
lines big.txt 60
-start 30 100 -n 3
+start 31 100 -n 3
wait 8000 big.txt
stable 700 20000
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key i
text big.txt:40 big.txt:10
key esc
settle 100
stable 400 5000
-press right 7 8
-release right 7 8
+press right 7 9
+release right 7 9
stable 700 15000
snap file-open
-# back to the shell: rm the file from disk in tty mode
-press left 38 11
-release left 38 11
+# Use the unrelated right-hand shell to remove the file: the source shell now
+# stays above its file and is only a few rows tall.
+press left 70 12
+release left 70 12
stable 400 5000
key c-b
stable 600 8000
@@ -33,9 +34,15 @@ stable 600 8000
snap removed
# look big.txt:10: nothing on disk, but the pane is loaded — it focuses and
# recenters on line 10 (before this change: realpath fails, look no-ops)
-# The source-local split leaves this terminal narrower than before: :10 now
-# starts at column 41 (the old column 51 was just past the wrapped command).
-press right 45 8
-release right 45 8
+# Put a fresh reference in the right-hand shell, then look it. This ensures the
+# gesture hits the missing path rather than empty space after source resizing.
+press left 55 9
+release left 55 9
+key i
+text big.txt:10
+key esc
+stable 400 5000
+press right 57 9
+release right 57 9
stable 700 15000
snap look-noFS
diff --git a/test/snapshots/lookpanes.golden b/test/snapshots/lookpanes.golden
index a9ea5b25..73aab814 100644
--- a/test/snapshots/lookpanes.golden
+++ b/test/snapshots/lookpanes.golden
@@ -1,72 +1,74 @@
-== snap shells grid=130x50 cursor=122,3
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/lookpanes/cwd/beta/bmark.txt Save New Newtty D /tmp/pardes-snap/lookpanes/cwd Save New Newtty Del Filter
+== snap shells grid=130x51 cursor=122,4
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/lookpanes/cwd/beta/bmark.txt Save Tty Del Coll /tmp/pardes-snap/lookpanes/cwd Save Tty Del Togglettymode Filte
| 1 both.txt ls
| 2 b-marker alpha beta zzboot.txt zqonly.txt pick.txt twin.txt
|
-| /tmp/pardes-snap/lookpanes/cwd/alpha Save New Newtty Del Filter
+| /tmp/pardes-snap/lookpanes/cwd/alpha Save Tty Del Togglettymode
| ls
| amark.txt both.txt pick.txt twin.txt zqonly.txt
-== snap other-dir grid=130x50 cursor=7,27
-|26: /tmp/pardes-snap/lookpanes/cwd/alpha/zqonly.txt Save New Newtty
-|27: 1 ONLY-IN-ALPHA
-== snap clicked-wins grid=130x50 cursor=7,15
-|14: /tmp/pardes-snap/lookpanes/cwd/beta/both.txt Save New Newtty De
-|15: 1 BOTH-FROM-BETA
-== snap mru-alpha grid=130x50 cursor=7,21
-|20: /tmp/pardes-snap/lookpanes/cwd/alpha/pick.txt Save New Newtty D
-|21: 1 PICK-FROM-ALPHA
-== snap mru-beta grid=130x50 cursor=7,9
-|8: /tmp/pardes-snap/lookpanes/cwd/beta/twin.txt Save New Newtty De
-|9: 1 TWIN-FROM-BETA
-== style mru-beta grid=130x50
-|0: 0-74 #949494,#121212, 75-129 d,#121212,
-|1: 0-1 #ffffff,#262626, 2-64 #949494,#121212, 65-66 #ffffff,#262626, 67-129 #949494,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-14 #bdbdbd,#080808, 15-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-14 #bdbdbd,#080808, 15-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-121 #bdbdbd,#080808, 122-129 d,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-129 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-66 #ffffff,#262626, 67-129 #949494,#121212,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|8: 0-1 #ffffff,#626262, 2-64 #949494,#121212, 65-65 d,#444444, 66-129 d,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-20 #bdbdbd,#080808, 21-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|11: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|14: 0-1 #ffffff,#262626, 2-64 #949494,#121212, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-20 #bdbdbd,#080808, 21-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|16: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|19: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|20: 0-1 #ffffff,#262626, 2-64 #949494,#121212, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-21 #bdbdbd,#080808, 22-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|26: 0-1 #ffffff,#262626, 2-64 #949494,#121212, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-19 #bdbdbd,#080808, 20-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|29: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|30: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|31: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|32: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|33: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|34: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|35: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|36: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|37: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|38: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|39: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|40: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|41: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|42: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|43: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|44: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|45: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|46: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|47: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|48: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
-|49: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-64 d,#080808, 65-65 d,#444444, 66-66 d,#080808, 67-129 #bdbdbd,#080808,
+== snap other-dir grid=130x51 cursor=7,28
+|27: /tmp/pardes-snap/lookpanes/cwd/alpha/zqonly.txt Save Tty Del Co
+|28: 1 ONLY-IN-ALPHA
+== snap clicked-wins grid=130x51 cursor=7,16
+|15: /tmp/pardes-snap/lookpanes/cwd/beta/both.txt Save Tty Del Colla
+|16: 1 BOTH-FROM-BETA
+== snap mru-alpha grid=130x51 cursor=7,22
+|21: /tmp/pardes-snap/lookpanes/cwd/alpha/pick.txt Save Tty Del Coll
+|22: 1 PICK-FROM-ALPHA
+== snap mru-beta grid=130x51 cursor=7,10
+|9: /tmp/pardes-snap/lookpanes/cwd/beta/twin.txt Save Tty Del Colla
+|10: 1 TWIN-FROM-BETA
+== style mru-beta grid=130x51
+|0: 0-70 #b2c3b8,#1d2824, 71-129 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-64 d,#26362d, 65-89 #b2c3b8,#1d2824, 90-129 d,#1d2824,
+|2: 0-1 #ffffff,#4c6356, 2-64 #b2c3b8,#1d2824, 65-66 #ffffff,#4c6356, 67-129 #b2c3b8,#1d2824,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-14 #e5eee5,#0d1410, 15-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-14 #e5eee5,#0d1410, 15-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-121 #e5eee5,#0d1410, 122-129 d,#0d1410,
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-129 d,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-66 #ffffff,#4c6356, 67-129 #b2c3b8,#1d2824,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|9: 0-1 #000000,#adcc91, 2-64 #becfc4,#26362d, 65-65 d,#637f6a, 66-129 d,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-20 #e5eee5,#0d1410, 21-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|15: 0-1 #ffffff,#4c6356, 2-64 #b2c3b8,#1d2824, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-20 #e5eee5,#0d1410, 21-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|17: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|20: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|21: 0-1 #ffffff,#4c6356, 2-64 #b2c3b8,#1d2824, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-21 #e5eee5,#0d1410, 22-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|27: 0-1 #ffffff,#4c6356, 2-64 #b2c3b8,#1d2824, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-19 #e5eee5,#0d1410, 20-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|31: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|32: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|33: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|34: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|35: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|36: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|37: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|38: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|39: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|40: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|41: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|42: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|43: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|44: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|45: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|46: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|47: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|48: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|49: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
+|50: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-64 d,#0d1410, 65-65 d,#637f6a, 66-66 d,#0d1410, 67-129 #e5eee5,#0d1410,
diff --git a/test/snapshots/lookpanes.snap b/test/snapshots/lookpanes.snap
index f05b5ec7..3bc8055c 100644
--- a/test/snapshots/lookpanes.snap
+++ b/test/snapshots/lookpanes.snap
@@ -20,7 +20,7 @@ file beta/both.txt BOTH-FROM-BETA
# directory at that) and Alt-c puts it in a column of its own on the right;
# its first line is a word to look FROM that pane
file beta/bmark.txt both.txt\nb-marker
-start 50 130 beta/bmark.txt
+start 51 130 beta/bmark.txt
wait 8000 b-marker
stable 700 20000
key a-n
@@ -31,14 +31,14 @@ key space w h
stable 400 5000
# an ordinary dir look on the shell's own ls output: a shell in ./alpha,
# split below it
-press right 70 4
-release right 70 4
+press right 70 5
+release right 70 5
wait 10000 amark.txt
stable 700 20000
# type the words to look into what is left of the workdir shell (past its own
# ls output, on the same row: its last row is the resize handle)
-press left 95 4
-release left 95 4
+press left 95 5
+release left 95 5
stable 400 5000
key i
text zqonly.txt pick.txt twin.txt
@@ -47,41 +47,41 @@ settle 100
stable 400 5000
snap shells
# make the beta pane the most recently focused, so the walk has to pass it
-press left 10 3
-release left 10 3
+press left 10 4
+release left 10 4
stable 700 10000
# zqonly.txt is only under alpha: the clicked shell's cwd fails, beta fails,
# the alpha shell answers. Before, this word became a search.
-press right 99 4
-release right 99 4
+press right 99 5
+release right 99 5
wait 10000 ONLY-IN-ALPHA
stable 700 20000
snap other-dir
# both.txt is in BOTH dirs and alpha is now the most recent (its file pane
# just opened), but the CLICK still wins: looked inside the beta pane it
# opens beta's copy
-press right 10 3
-release right 10 3
+press right 10 4
+release right 10 4
wait 10000 BOTH-FROM-BETA
stable 700 20000
snap clicked-wins
# from a pane whose own dir holds neither copy the access order decides:
# focus the alpha shell, look pick.txt (in both dirs) -> alpha's
-press left 70 12
-release left 70 12
+press left 70 13
+release left 70 13
stable 700 10000
-press right 109 4
-release right 109 4
+press right 109 5
+release right 109 5
wait 10000 PICK-FROM-ALPHA
stable 700 20000
snap mru-alpha
# focus the beta pane instead and the same look flips: twin.txt is in both
# dirs, beta is most recent, beta's copy opens
-press left 10 3
-release left 10 3
+press left 10 4
+release left 10 4
stable 700 10000
-press right 118 4
-release right 118 4
+press right 118 5
+release right 118 5
wait 10000 TWIN-FROM-BETA
stable 700 20000
snap mru-beta
diff --git a/test/snapshots/lookrange.golden b/test/snapshots/lookrange.golden
index 50610a39..4e916932 100644
--- a/test/snapshots/lookrange.golden
+++ b/test/snapshots/lookrange.golden
@@ -1,13 +1,67 @@
-== snap opened grid=150x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/lookrange/cwd/look.txt Save New Newtty Del
+== snap opened grid=150x31 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/lookrange/cwd/look.txt Save Tty Del Collapse
| 1 r.txt:3-5
| 2 r.txt:7:4-9
| 3 r.txt:3:2-5:3
| 4 r.txt:8:6-99:9
-== snap wholelines grid=150x30 cursor=11,21
-|16: /tmp/pardes-snap/lookrange/cwd/r.txt Save New Newtty Del
-|17: 1 aaaa
+== snap wholelines grid=150x31 cursor=11,22
+|17: /tmp/pardes-snap/lookrange/cwd/r.txt Save Tty Del Collapse
+|18: 1 aaaa
+|19: 2 bbbb
+|20: 3 cccc dccc
+|21: 4 dddd
+|22: 5 eeee
+|23: 6 ffff
+|24: 7 gg NEEDLE gg
+|25: 8 hhhh NEEDLE
+|26: 9 iiii
+== style wholelines grid=150x31
+|0: 0-70 #b2c3b8,#1d2824, 71-149 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-149 d,#26362d,
+|2: 0-1 #ffffff,#4c6356, 2-62 #b2c3b8,#1d2824, 63-149 d,#1d2824,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-15 #e5eee5,#0d1410, 16-149 d,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-17 #e5eee5,#0d1410, 18-149 d,#0d1410,
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-19 #e5eee5,#0d1410, 20-149 d,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-20 #e5eee5,#0d1410, 21-149 d,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|17: 0-1 #000000,#adcc91, 2-59 #becfc4,#26362d, 60-149 d,#26362d,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
+|20: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 #f5f7ee,#405d4b,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 #f5f7ee,#405d4b,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-11 #f5f7ee,#405d4b, 12-149 d,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-18 #e5eee5,#0d1410, 19-149 d,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-17 #e5eee5,#0d1410, 18-149 d,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+== snap onelinespan grid=150x31 cursor=15,24
+== style onelinespan grid=150x31
+|20: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-15 #e5eee5,#0d1410, 16-149 d,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-9 #e5eee5,#0d1410, 10-15 #f5f7ee,#405d4b, 16-18 #e5eee5,#0d1410, 19-149 d,#0d1410,
+== snap fullspan grid=150x31 cursor=9,22
+== style fullspan grid=150x31
+|20: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-7 #e5eee5,#0d1410, 8-149 #f5f7ee,#405d4b,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 #f5f7ee,#405d4b,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-9 #f5f7ee,#405d4b, 10-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-18 #e5eee5,#0d1410, 19-149 d,#0d1410,
+== snap stale grid=150x31 cursor=10,25
|18: 2 bbbb
|19: 3 cccc dccc
|20: 4 dddd
@@ -16,51 +70,42 @@
|23: 7 gg NEEDLE gg
|24: 8 hhhh NEEDLE
|25: 9 iiii
-== style wholelines grid=150x30
-|0: 0-74 #949494,#121212, 75-149 d,#121212,
-|1: 0-1 #ffffff,#262626, 2-129 #949494,#121212, 130-149 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-15 #bdbdbd,#080808, 16-149 d,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-17 #bdbdbd,#080808, 18-149 d,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-19 #bdbdbd,#080808, 20-149 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-20 #bdbdbd,#080808, 21-149 d,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|8: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|11: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|16: 0-1 #ffffff,#626262, 2-129 #949494,#121212, 130-149 d,#121212,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-149 d,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-149 d,#080808,
-|19: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 #080808,#80a0ff,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 #080808,#80a0ff,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-11 #080808,#80a0ff, 12-149 d,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-149 d,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-18 #bdbdbd,#080808, 19-149 d,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-17 #bdbdbd,#080808, 18-149 d,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-149 d,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|29: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-== snap onelinespan grid=150x30 cursor=15,23
-== style onelinespan grid=150x30
-|19: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-15 #bdbdbd,#080808, 16-149 d,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-149 d,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-149 d,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-9 #bdbdbd,#080808, 10-15 #080808,#80a0ff, 16-18 #bdbdbd,#080808, 19-149 d,#080808,
-== snap fullspan grid=150x30 cursor=9,21
-== style fullspan grid=150x30
-|19: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-7 #bdbdbd,#080808, 8-149 #080808,#80a0ff,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 #080808,#80a0ff,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-9 #080808,#80a0ff, 10-10 #bdbdbd,#080808, 11-149 d,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-18 #bdbdbd,#080808, 19-149 d,#080808,
-== snap stale grid=150x30 cursor=10,24
-|17: 2 bbbb
+|26:
+== style stale grid=150x31
+|18: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-15 #e5eee5,#0d1410, 16-149 d,#0d1410,
+|20: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-18 #e5eee5,#0d1410, 19-149 d,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-11 #e5eee5,#0d1410, 12-149 #f5f7ee,#405d4b,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-10 #f5f7ee,#405d4b, 11-149 d,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+== snap hit1 grid=150x31 cursor=15,24
+|18: 1 aaaa
+|19: 2 bbbb
+|20: 3 cccc dccc
+|21: 4 dddd
+|22: 5 eeee
+|23: 6 ffff
+|24: 7 gg NEEDLE gg
+|25: 8 hhhh NEEDLE
+|26: 9 iiii
+|28: /tmp/pardes-snap/lookrange/cwd/+Search Save Tty Del Collapse
+|29: 1 r.txt:7:4-9 gg NEEDLE gg
+|30: 2 r.txt:8:6-11 hhhh NEEDLE
+== style hit1 grid=150x31
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
+|20: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-15 #e5eee5,#0d1410, 16-149 d,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-9 #e5eee5,#0d1410, 10-15 #f5f7ee,#405d4b, 16-18 #e5eee5,#0d1410, 19-149 d,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-17 #e5eee5,#0d1410, 18-149 d,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
+|28: 0-1 #ffffff,#4c6356, 2-61 #b2c3b8,#1d2824, 62-149 d,#1d2824,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-17 #59675c,#0d1410, 18-21 #e5eee5,#0d1410, 22-27 #f7e4a5,#57472a, 28-30 #e5eee5,#0d1410, 31-149 d,#0d1410,
+|30: 0-0 d,#152019, 1-1 d,#0d1410, 2-18 #59675c,#0d1410, 19-24 #e5eee5,#0d1410, 25-30 #f7e4a5,#57472a, 31-149 d,#0d1410,
+== snap hit2 grid=150x31 cursor=17,23
|18: 3 cccc dccc
|19: 4 dddd
|20: 5 eeee
@@ -69,18 +114,17 @@
|23: 8 hhhh NEEDLE
|24: 9 iiii
|25:
-== style stale grid=150x30
-|17: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-149 d,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-15 #bdbdbd,#080808, 16-149 d,#080808,
-|19: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-149 d,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-149 d,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-149 d,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-18 #bdbdbd,#080808, 19-149 d,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-11 #bdbdbd,#080808, 12-149 #080808,#80a0ff,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-10 #080808,#80a0ff, 11-149 d,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-== snap hit1 grid=150x30 cursor=15,23
-|17: 1 aaaa
+|26:
+== style hit2 grid=150x31
+|18: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-15 #e5eee5,#0d1410, 16-149 d,#0d1410,
+|19: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
+|20: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-18 #e5eee5,#0d1410, 19-149 d,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-11 #e5eee5,#0d1410, 12-17 #f5f7ee,#405d4b, 18-149 d,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+== snap back grid=150x31 cursor=15,23
|18: 2 bbbb
|19: 3 cccc dccc
|20: 4 dddd
@@ -89,52 +133,10 @@
|23: 7 gg NEEDLE gg
|24: 8 hhhh NEEDLE
|25: 9 iiii
-|27: /tmp/pardes-snap/lookrange/cwd/+Search Save New Newtty Del
-|28: 1 r.txt:7:4-9 gg NEEDLE gg
-|29: 2 r.txt:8:6-11 hhhh NEEDLE
-== style hit1 grid=150x30
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-149 d,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-149 d,#080808,
-|19: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-15 #bdbdbd,#080808, 16-149 d,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-149 d,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-9 #bdbdbd,#080808, 10-15 #080808,#80a0ff, 16-18 #bdbdbd,#080808, 19-149 d,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-17 #bdbdbd,#080808, 18-149 d,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-149 d,#080808,
-|27: 0-1 #ffffff,#262626, 2-129 #949494,#121212, 130-149 d,#121212,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-30 #bdbdbd,#080808, 31-149 d,#080808,
-|29: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-30 #bdbdbd,#080808, 31-149 d,#080808,
-== snap hit2 grid=150x30 cursor=17,22
-|17: 3 cccc dccc
-|18: 4 dddd
-|19: 5 eeee
-|20: 6 ffff
-|21: 7 gg NEEDLE gg
-|22: 8 hhhh NEEDLE
-|23: 9 iiii
-|24:
-|25:
-== style hit2 grid=150x30
-|17: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-15 #bdbdbd,#080808, 16-149 d,#080808,
-|18: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-149 d,#080808,
-|19: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-149 d,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-18 #bdbdbd,#080808, 19-149 d,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-11 #bdbdbd,#080808, 12-17 #080808,#80a0ff, 18-149 d,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-149 d,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-== snap back grid=150x30 cursor=15,22
-|17: 2 bbbb
-|18: 3 cccc dccc
-|19: 4 dddd
-|20: 5 eeee
-|21: 6 ffff
-|22: 7 gg NEEDLE gg
-|23: 8 hhhh NEEDLE
-|24: 9 iiii
-== style back grid=150x30
-|17: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-149 d,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-15 #bdbdbd,#080808, 16-149 d,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-149 d,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-9 #bdbdbd,#080808, 10-15 #080808,#80a0ff, 16-18 #bdbdbd,#080808, 19-149 d,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-17 #bdbdbd,#080808, 18-149 d,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-149 d,#080808,
+== style back grid=150x31
+|18: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-15 #e5eee5,#0d1410, 16-149 d,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-9 #e5eee5,#0d1410, 10-15 #f5f7ee,#405d4b, 16-18 #e5eee5,#0d1410, 19-149 d,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-17 #e5eee5,#0d1410, 18-149 d,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-149 d,#0d1410,
diff --git a/test/snapshots/lookrange.snap b/test/snapshots/lookrange.snap
index b64607a1..c1fde9c6 100644
--- a/test/snapshots/lookrange.snap
+++ b/test/snapshots/lookrange.snap
@@ -14,36 +14,36 @@
# in the styles.
file r.txt aaaa\nbbbb\ncccc dccc\ndddd\neeee\nffff\ngg NEEDLE gg\nhhhh NEEDLE\niiii
file look.txt r.txt:3-5\nr.txt:7:4-9\nr.txt:3:2-5:3\nr.txt:8:6-99:9
-start 30 150 look.txt
+start 31 150 look.txt
wait 8000 r.txt:3-5
stable 700 20000
snap opened
# --- form 1: whole lines. r.txt opens BELOW look.txt (an ordinary look) with
# lines 3, 4 and 5 selected whole, terminators included — helix's own `x`.
-press right 10 3
-release right 10 3
+press right 10 4
+release right 10 4
wait 10000 cccc dccc
stable 700 15000
snap wholelines
snapstyle wholelines
# --- form 2: one line, a column span. r.txt is open now, so this re-uses that
# pane (focusPaneByPath) — the same route a `/` result row takes.
-press right 12 4
-release right 12 4
+press right 12 5
+release right 12 5
stable 700 15000
snap onelinespan
snapstyle onelinespan
# --- form 3: the general one, across both lines and columns
-press right 12 5
-release right 12 5
+press right 12 6
+release right 12 6
stable 700 15000
snap fullspan
snapstyle fullspan
# --- a STALE range: line 99 of a nine-line file, which is what a result row
# looks like once the file has changed underneath it. It must CLAMP — no crash,
# no garbage highlight — landing on the last cell that really exists.
-press right 12 6
-release right 12 6
+press right 12 7
+release right 12 7
stable 700 15000
snap stale
snapstyle stale
diff --git a/test/snapshots/lsp-client-edit.golden b/test/snapshots/lsp-client-edit.golden
index 15a477b2..02cc9a37 100644
--- a/test/snapshots/lsp-client-edit.golden
+++ b/test/snapshots/lsp-client-edit.golden
@@ -1,6 +1,7 @@
-== snap formatted grid=100x24 cursor=7,3
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/lsp-client-edit/cwd/main.rs * Save New Newtty Del
+== snap formatted grid=100x25 cursor=7,4
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/lsp-client-edit/cwd/main.rs * Save Tty Del Collapse
| 1 // formatted by mock
| 2 mod lib;
| 3
@@ -23,22 +24,22 @@
|
|
| formatted 1 range(s)
-== snap unformatted grid=100x24 cursor=7,2
-|2: 1 mod lib;
-|3: 2
-|4: 3 fn main() {
-|5: 4 let x = add(1, 2);
-|6: 5 let y = add(3, 4);
-|7: 6 let _ = x + y;
-|8: 7 }
-|9: 8
-|10:
-|23:
-== snap renamed grid=100x24 cursor=12,4
-|5: 4 let x = sum(1, 2);
-|6: 5 let y = sum(3, 4);
-|23: renamed 2 range(s)
-== snap unrenamed grid=100x24 cursor=12,4
-|5: 4 let x = add(1, 2);
-|6: 5 let y = add(3, 4);
-|23:
+== snap unformatted grid=100x25 cursor=7,3
+|3: 1 mod lib;
+|4: 2
+|5: 3 fn main() {
+|6: 4 let x = add(1, 2);
+|7: 5 let y = add(3, 4);
+|8: 6 let _ = x + y;
+|9: 7 }
+|10: 8
+|11:
+|24:
+== snap renamed grid=100x25 cursor=12,5
+|6: 4 let x = sum(1, 2);
+|7: 5 let y = sum(3, 4);
+|24: renamed 2 range(s)
+== snap unrenamed grid=100x25 cursor=12,5
+|6: 4 let x = add(1, 2);
+|7: 5 let y = add(3, 4);
+|24:
diff --git a/test/snapshots/lsp-client-edit.snap b/test/snapshots/lsp-client-edit.snap
index a9e66e51..456f5555 100644
--- a/test/snapshots/lsp-client-edit.snap
+++ b/test/snapshots/lsp-client-edit.snap
@@ -6,7 +6,7 @@
# u reverses each as a single transaction
file main.rs mod lib;\n\nfn main() {\n let x = add(1, 2);\n let y = add(3, 4);\n let _ = x + y;\n}\n
file lib.rs // mock fixture\npub fn add(a: i32, b: i32) -> i32 {\n a + b\n}\n
-start 24 100 main.rs
+start 25 100 main.rs
wait 8000 add(1, 2)
stable 700 20000
key =
@@ -18,8 +18,8 @@ wait 8000 mod lib;
stable 700 15000
snap unformatted
# rename through the leader prompt: both call sites change in one step
-press left 13 5
-release left 13 5
+press left 13 6
+release left 13 6
key space
key l
key r
diff --git a/test/snapshots/lsp-client.golden b/test/snapshots/lsp-client.golden
index d937889c..6e122e95 100644
--- a/test/snapshots/lsp-client.golden
+++ b/test/snapshots/lsp-client.golden
@@ -1,6 +1,7 @@
-== snap gd-jumped grid=100x24 cursor=16,15
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/lsp-client/cwd/main.rs Save New Newtty Del
+== snap gd-jumped grid=100x25 cursor=16,16
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/lsp-client/cwd/main.rs Save Tty Del Collapse
| 1 mod lib;
| 2
| 3 fn main() {
@@ -12,23 +13,23 @@
|
|
| --:--:-- lsp rust-analyzer: ready
-| /tmp/pardes-snap/lsp-client/cwd/lib.rs Save New Newtty Del
+| /tmp/pardes-snap/lsp-client/cwd/lib.rs Save Tty Del Collapse
| 1 // mock fixture
| 2 pub fn add(a: i32, b: i32) -> i32 {
| 3 a + b
| 4 }
| 5
-== snap gr-list grid=100x24 cursor=21,5
-|12:
-|20: /tmp/pardes-snap/lsp-client/cwd/+Search Save New Newtty Del
-|21: 1 lib.rs:2:8-10 pub fn add(a: i32, b: i32) -> i32 {
-|22: 2 main.rs:4:13-15 let x = add(1, 2);
-|23: 3 main.rs:5:13-15 let y = add(3, 4);
-== snap gr-opened grid=100x24 cursor=21,6
-|21: 2 main.rs:4:13-15 let x = add(1, 2);
-|22: 3 main.rs:5:13-15 let y = add(3, 4);
-|23: 4
-== snap gr-back grid=100x24 cursor=21,5
-|21: 1 lib.rs:2:8-10 pub fn add(a: i32, b: i32) -> i32 {
+== snap gr-list grid=100x25 cursor=21,6
+|13:
+|21: /tmp/pardes-snap/lsp-client/cwd/+Search Save Tty Del Collapse
+|22: 1 lib.rs:2:8-10 pub fn add(a: i32, b: i32) -> i32 {
+|23: 2 main.rs:4:13-15 let x = add(1, 2);
+|24: 3 main.rs:5:13-15 let y = add(3, 4);
+== snap gr-opened grid=100x25 cursor=21,7
|22: 2 main.rs:4:13-15 let x = add(1, 2);
|23: 3 main.rs:5:13-15 let y = add(3, 4);
+|24: 4
+== snap gr-back grid=100x25 cursor=21,6
+|22: 1 lib.rs:2:8-10 pub fn add(a: i32, b: i32) -> i32 {
+|23: 2 main.rs:4:13-15 let x = add(1, 2);
+|24: 3 main.rs:5:13-15 let y = add(3, 4);
diff --git a/test/snapshots/lsp-client.snap b/test/snapshots/lsp-client.snap
index 91c65975..541e7c7f 100644
--- a/test/snapshots/lsp-client.snap
+++ b/test/snapshots/lsp-client.snap
@@ -9,12 +9,12 @@
# gr -> sorted rows, selecting the next occurrence; n/N continue there.
file main.rs mod lib;\n\nfn main() {\n let x = add(1, 2);\n let y = add(3, 4);\n let _ = x + y;\n}\n
file lib.rs // mock fixture\npub fn add(a: i32, b: i32) -> i32 {\n a + b\n}\n
-start 24 100 main.rs
+start 25 100 main.rs
wait 8000 add(1, 2)
stable 700 20000
# cursor into the first `add` call, then helix's goto-definition
-press left 13 5
-release left 13 5
+press left 13 6
+release left 13 6
key g
key d
wait 10000 pub fn add
diff --git a/test/snapshots/lsp-rename.golden b/test/snapshots/lsp-rename.golden
index a241a93c..74ab41e2 100644
--- a/test/snapshots/lsp-rename.golden
+++ b/test/snapshots/lsp-rename.golden
@@ -1,6 +1,7 @@
-== snap renamed grid=110x24 cursor=17,9
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/lsp-rename/cwd/rename.zig * Save New Newtty Del
+== snap renamed grid=110x25 cursor=17,10
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/lsp-rename/cwd/rename.zig * Save Tty Del Collapse
| 1 const std = @import("std");
| 2
| 3 fn renamed_helper(x: u32) u32 {
@@ -23,10 +24,10 @@
|
|
| renamed 2 range(s)
-== snap undone grid=110x24 cursor=17,9
-|4: 3 fn helper(x: u32) u32 {
-|9: 8 _ = helper(41);
-|23:
-== snap redone grid=110x24 cursor=17,9
-|4: 3 fn renamed_helper(x: u32) u32 {
-|9: 8 _ = renamed_helper(41);
+== snap undone grid=110x25 cursor=17,10
+|5: 3 fn helper(x: u32) u32 {
+|10: 8 _ = helper(41);
+|24:
+== snap redone grid=110x25 cursor=17,10
+|5: 3 fn renamed_helper(x: u32) u32 {
+|10: 8 _ = renamed_helper(41);
diff --git a/test/snapshots/lsp-rename.snap b/test/snapshots/lsp-rename.snap
index c29b001e..63ca21db 100644
--- a/test/snapshots/lsp-rename.snap
+++ b/test/snapshots/lsp-rename.snap
@@ -2,12 +2,12 @@
# shadow filtering, and one-step undo/redo. The source has a same-spelled local
# which must not be changed when the top-level helper is renamed.
file rename.zig const std = @import("std");\n\nfn helper(x: u32) u32 {\n return x + 1;\n}\n\npub fn main() void {\n _ = helper(41);\n}\n\nfn shadowed() void {\n const helper: u32 = 7;\n _ = helper;\n}\n
-start 24 110 rename.zig
+start 25 110 rename.zig
wait 8000 helper(41)
stable 700 20000
# Put the cursor inside the top-level call, then use the helix rename binding.
-press left 18 10
-release left 18 10
+press left 18 11
+release left 18 11
key space
key l
key r
diff --git a/test/snapshots/lsp.golden b/test/snapshots/lsp.golden
index 3a5b0af8..f6d0739a 100644
--- a/test/snapshots/lsp.golden
+++ b/test/snapshots/lsp.golden
@@ -1,6 +1,7 @@
-== snap opened grid=120x40 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/lsp/cwd/a.zig Save New Newtty Del
+== snap opened grid=120x41 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/lsp/cwd/a.zig Save Tty Del Collapse
| 1 const std = @import("std");
| 2
| 3 fn helper(x: u32) u32 {
@@ -11,16 +12,16 @@
| 8 _ = helper(41);
| 9 }
| 10
-== snap cursor grid=120x40 cursor=17,9
-== snap definition grid=120x40 cursor=15,4
-== snap hover grid=120x40 cursor=15,4
-|37: /tmp/pardes-snap/lsp/cwd/+Hover Save New Newtty Del
-|38: 1 fn helper(x: u32) u32
-|39: 2 (fn (u32) u32)
-== snap symbols grid=120x40 cursor=15,4
-|33: /tmp/pardes-snap/lsp/cwd/+Search Save New Newtty Del
-|34: 1 a.zig:1:7-9 std
-|35: 2 a.zig:3:4-9 helper fn helper(x: u32) u32
-|36: 3 a.zig:7:8-11 main fn main() void
-== snap step grid=120x40 cursor=15,2
-== snap nothing grid=120x40 cursor=7,4
+== snap cursor grid=120x41 cursor=17,10
+== snap definition grid=120x41 cursor=15,5
+== snap hover grid=120x41 cursor=15,5
+|38: /tmp/pardes-snap/lsp/cwd/+Hover Save Tty Del Collapse
+|39: 1 fn helper(x: u32) u32
+|40: 2 (fn (u32) u32)
+== snap symbols grid=120x41 cursor=15,5
+|34: /tmp/pardes-snap/lsp/cwd/+Search Save Tty Del Collapse
+|35: 1 a.zig:1:7-9 std
+|36: 2 a.zig:3:4-9 helper fn helper(x: u32) u32
+|37: 3 a.zig:7:8-11 main fn main() void
+== snap step grid=120x41 cursor=15,3
+== snap nothing grid=120x41 cursor=7,5
diff --git a/test/snapshots/lsp.snap b/test/snapshots/lsp.snap
index 2eb17735..b40484ee 100644
--- a/test/snapshots/lsp.snap
+++ b/test/snapshots/lsp.snap
@@ -11,13 +11,13 @@
# symbol from std — so these goldens do not encode this machine's stdlib
# version or its install path.
file a.zig const std = @import("std");\n\nfn helper(x: u32) u32 {\n return x + 1;\n}\n\npub fn main() void {\n _ = helper(41);\n}\n
-start 40 120 a.zig
+start 41 120 a.zig
wait 8000 helper
stable 700 20000
snap opened
# park the cursor inside the CALL `helper(41)` (file line 8, grid row 9)
-press left 18 10
-release left 18 10
+press left 18 11
+release left 18 11
stable 400 5000
snap cursor
# gd on a call: exactly one location comes back, so it JUMPS rather than
@@ -49,8 +49,8 @@ stable 700 15000
snap step
# gd on something with no declaration behind it (a keyword) answers nothing,
# and nothing is a legal answer: no buffer opens, no error is rendered.
-press left 8 5
-release left 8 5
+press left 8 6
+release left 8 6
key g
key d
stable 700 10000
diff --git a/test/snapshots/lspcomplete.golden b/test/snapshots/lspcomplete.golden
index abfe91b9..3c4316c3 100644
--- a/test/snapshots/lspcomplete.golden
+++ b/test/snapshots/lspcomplete.golden
@@ -1,6 +1,7 @@
-== snap opened grid=120x40 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/lspcomplete/cwd/a.zig Save New Newtty Del
+== snap opened grid=120x41 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/lspcomplete/cwd/a.zig Save Tty Del Collapse
| 1 const Shade = enum {
| 2 verdigris,
| 3 cinnabar,
@@ -14,28 +15,30 @@
| 11
| 12 // note. see below
| 13
-== snap indent grid=120x40 cursor=11,11
-|1: ^ /tmp/pardes-snap/lspcomplete/cwd/a.zig * Save New Newtty Del
-|11: 10 }
-== snap commentindent grid=120x40 cursor=19,13
-|13: 12 // note. see below
-== snap athedot grid=120x40 cursor=16,9
-|9: 8 .
-== snap completion grid=120x40 cursor=16,9
-|37: /tmp/pardes-snap/lspcomplete/cwd/+Search Save New Newtty Del
-|38: 1 a.zig:2:5-13 verdigris verdigris,
-|39: 2 a.zig:3:5-12 cinnabar cinnabar,
-== snap refill grid=120x40 cursor=16,9
-== snap step grid=120x40 cursor=19,3
-|1: /tmp/pardes-snap/lspcomplete/cwd/a.zig * Save New Newtty Del
-== snap txtindent grid=120x40 cursor=15,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|^ /tmp/pardes-snap/lspcomplete/cwd/notes.txt * Save New Newtty Del
+== snap indent grid=120x41 cursor=11,12
+|2: ^ /tmp/pardes-snap/lspcomplete/cwd/a.zig * Save Tty Del Collapse
+|12: 10 }
+== snap commentindent grid=120x41 cursor=19,14
+|14: 12 // note. see below
+== snap athedot grid=120x41 cursor=16,10
+|10: 8 .
+== snap completion grid=120x41 cursor=16,10
+|38: /tmp/pardes-snap/lspcomplete/cwd/+Search Save Tty Del Collapse
+|39: 1 a.zig:2:5-13 verdigris verdigris,
+|40: 2 a.zig:3:5-12 cinnabar cinnabar,
+== snap refill grid=120x41 cursor=16,10
+== snap step grid=120x41 cursor=19,4
+|2: /tmp/pardes-snap/lspcomplete/cwd/a.zig * Save Tty Del Collapse
+== snap txtindent grid=120x41 cursor=15,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+|^ /tmp/pardes-snap/lspcomplete/cwd/notes.txt * Save Tty Del Collapse
| 1 abc. def ghi
| 2
-== snap nosemi grid=100x18 cursor=29,8
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|^ /tmp/pardes-snap/lspcomplete/cwd/c.zig * Save New Newtty Del
+== snap nosemi grid=100x19 cursor=29,9
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+|^ /tmp/pardes-snap/lspcomplete/cwd/c.zig * Save Tty Del Collapse
| 1 const Shade = enum {
| 2 verdigris,
| 3 cinnabar,
@@ -49,12 +52,13 @@
|
|
|
-| /tmp/pardes-snap/lspcomplete/cwd/+Search Save New Newtty Del
+| /tmp/pardes-snap/lspcomplete/cwd/+Search Save Tty Del Collapse
| 1 c.zig:2:5-13 verdigris verdigris,
| 2 c.zig:3:5-12 cinnabar cinnabar,
-== snap nobrace grid=100x18 cursor=16,9
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|^ /tmp/pardes-snap/lspcomplete/cwd/d.zig * Save New Newtty Del
+== snap nobrace grid=100x19 cursor=16,10
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+|^ /tmp/pardes-snap/lspcomplete/cwd/d.zig * Save Tty Del Collapse
| 1 const Shade = enum {
| 2 verdigris,
| 3 cinnabar,
@@ -68,6 +72,6 @@
|
|
|
-| /tmp/pardes-snap/lspcomplete/cwd/+Search Save New Newtty Del
+| /tmp/pardes-snap/lspcomplete/cwd/+Search Save Tty Del Collapse
| 1 d.zig:2:5-13 verdigris verdigris,
| 2 d.zig:3:5-12 cinnabar cinnabar,
diff --git a/test/snapshots/lspcomplete.snap b/test/snapshots/lspcomplete.snap
index 8baa870e..53ce7ef9 100644
--- a/test/snapshots/lspcomplete.snap
+++ b/test/snapshots/lspcomplete.snap
@@ -18,14 +18,14 @@
# script the only end-to-end coverage the feature has.
file a.zig const Shade = enum {\n verdigris,\n cinnabar,\n};\n\nfn pick(s: Shade) u8 {\n return switch (s) {\n \n };\n}\n\n// note. see below\n
file notes.txt abc.def ghi\n
-start 40 120 a.zig
+start 41 120 a.zig
wait 8000 verdigris
stable 700 20000
snap opened
# Tab with no dot before it is still Tab: line 10 is the closing `}`, and this
# is the plain insert_tab path putting spaces in front of it.
-press left 8 12
-release left 8 12
+press left 8 13
+release left 8 13
key i
key tab
stable 400 5000
@@ -38,8 +38,8 @@ settle 100
# retroactively when the empty answer arrives (lspResponse), on the condition
# that the cursor has not moved meanwhile. Four spaces go in after `// note.`
# and the keystroke is not eaten, which is the whole contract.
-press left 16 14
-release left 16 14
+press left 16 15
+release left 16 15
stable 400 5000
key i
key tab
@@ -49,8 +49,8 @@ key esc
settle 100
# Line 8 (grid row 9, 1-based click row 10) is the switch's empty body. End
# puts the cursor past its indent, and then the dot is typed.
-press left 8 10
-release left 8 10
+press left 8 11
+release left 8 11
stable 400 5000
key i
key end
@@ -98,11 +98,11 @@ snap step
# cursor, and Tab must still indent — synchronously this time, since the core
# never asks. The gate is lsp.speaks, which the core consults and the backend
# owns.
-start 40 120 notes.txt
+start 41 120 notes.txt
wait 8000 abc.def
stable 700 20000
-press left 12 3
-release left 12 3
+press left 12 4
+release left 12 4
key i
key tab
stable 400 5000
@@ -117,11 +117,11 @@ snap txtindent
# identifier spliced in, so the repair has to be chosen by whether it makes the
# dot reachable in the tree, never by counting errors.
file c.zig const Shade = enum {\n verdigris,\n cinnabar,\n};\n\npub fn nosemi() void {\n const z: Shade = \n}\n
-start 18 100 c.zig
+start 19 100 c.zig
wait 8000 nosemi
stable 700 20000
-press left 8 9
-release left 8 9
+press left 8 10
+release left 8 10
stable 400 5000
key i
key end
@@ -138,11 +138,11 @@ snap nosemi
# as well, on the same line (a spelling containing a newline would move every
# line number the rows are built from).
file d.zig const Shade = enum {\n verdigris,\n cinnabar,\n};\n\npub fn nobrace(s: Shade) void {\n switch (s) {\n \n}\n
-start 18 100 d.zig
+start 19 100 d.zig
wait 8000 nobrace
stable 700 20000
-press left 8 10
-release left 8 10
+press left 8 11
+release left 8 11
stable 400 5000
key i
key end
diff --git a/test/snapshots/lspcompletemoved.golden b/test/snapshots/lspcompletemoved.golden
index b9dd9bc3..6232a1f3 100644
--- a/test/snapshots/lspcompletemoved.golden
+++ b/test/snapshots/lspcompletemoved.golden
@@ -1,6 +1,7 @@
-== snap typedthrough grid=120x20 cursor=16,13
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|^ /tmp/pardes-snap/lspcompletemoved/cwd/a.zig * Save New Newtty Del
+== snap typedthrough grid=120x21 cursor=16,14
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+|^ /tmp/pardes-snap/lspcompletemoved/cwd/a.zig * Save Tty Del Collapse
| 1 const Shade = enum {
| 2 verdigris,
| 3 cinnabar,
diff --git a/test/snapshots/lspcompletemoved.snap b/test/snapshots/lspcompletemoved.snap
index 5f20b806..8351b310 100644
--- a/test/snapshots/lspcompletemoved.snap
+++ b/test/snapshots/lspcompletemoved.snap
@@ -15,11 +15,11 @@
# neither `// note. x` (the indent landing under the typing) nor
# `// note.x ` (the indent landing on top of it).
file a.zig const Shade = enum {\n verdigris,\n cinnabar,\n};\n\nfn pick(s: Shade) u8 {\n return switch (s) {\n \n };\n}\n\n// note. see below\n
-start 20 120 a.zig
+start 21 120 a.zig
wait 8000 verdigris
stable 700 20000
-press left 16 14
-release left 16 14
+press left 16 15
+release left 16 15
stable 400 5000
key i
key tab
diff --git a/test/snapshots/lspdebug.golden b/test/snapshots/lspdebug.golden
index 4dd7748e..e1b57c5e 100644
--- a/test/snapshots/lspdebug.golden
+++ b/test/snapshots/lspdebug.golden
@@ -1,6 +1,7 @@
-== snap opened grid=120x44 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/lspdebug/cwd/z.zig Save New Newtty Del
+== snap opened grid=120x45 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/lspdebug/cwd/z.zig Save Tty Del Collapse
| 1 const std = @import("std");
| 2
| 3 fn helper() u32 {
@@ -12,7 +13,7 @@
| 9 _ = v;
| 10 }
| 11
-== snap ctrlclick grid=120x44 cursor=15,4
-== snap plainclick grid=120x44 cursor=21,9
-== snap why-closed grid=120x44 cursor=7,4
-== snap report-closed grid=120x44 cursor=7,4
+== snap ctrlclick grid=120x45 cursor=15,5
+== snap plainclick grid=120x45 cursor=21,10
+== snap why-closed grid=120x45 cursor=7,5
+== snap report-closed grid=120x45 cursor=7,5
diff --git a/test/snapshots/lspdebug.snap b/test/snapshots/lspdebug.snap
index 514b24da..4021bc17 100644
--- a/test/snapshots/lspdebug.snap
+++ b/test/snapshots/lspdebug.snap
@@ -1,16 +1,16 @@
file z.zig const std = @import("std");\n\nfn helper() u32 {\n return 3;\n}\n\npub fn main() void {\n const v = helper();\n _ = v;\n}\n
-start 44 120 z.zig
+start 45 120 z.zig
wait 8000 fn helper
stable 700 20000
snap opened
# Ctrl-click jumps to the definition; plain click only moves the cursor.
-press ctrl-left 22 10
-release ctrl-left 22 10
+press ctrl-left 22 11
+release ctrl-left 22 11
stable 700 15000
snap ctrlclick
-press left 22 10
-release left 22 10
+press left 22 11
+release left 22 11
stable 700 15000
snap plainclick
diff --git a/test/snapshots/lsprelpath.golden b/test/snapshots/lsprelpath.golden
index 8dfc5e14..65fd08cd 100644
--- a/test/snapshots/lsprelpath.golden
+++ b/test/snapshots/lsprelpath.golden
@@ -1,6 +1,7 @@
-== snap absrow grid=100x34 cursor=16,6
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|^ /tmp/pardes-snap/lsprelpath/cwd/sub/parent.zig * Save New Newtty Del
+== snap absrow grid=100x35 cursor=16,7
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+|^ /tmp/pardes-snap/lsprelpath/cwd/sub/parent.zig * Save Tty Del Collapse
| 1 const shade = @import("../shade.zig");
| 2
| 3 pub fn pick(s: shade.Shade) u8 {
@@ -30,55 +31,57 @@
|
|
|
-| /tmp/pardes-snap/lsprelpath/cwd/sub/+Search Save New Newtty Del
+| /tmp/pardes-snap/lsprelpath/cwd/sub/+Search Save Tty Del Collapse
| 1 /tmp/pardes-snap/lsprelpath/cwd/shade.zig:2:5-13 verdigris verdigris,
| 2 /tmp/pardes-snap/lsprelpath/cwd/shade.zig:3:5-12 cinnabar cinnabar,
-== snap abslook grid=100x34 cursor=19,18
-|1: /tmp/pardes-snap/lsprelpath/cwd/sub/parent.zig * Save New Newtty Del
-|16: /tmp/pardes-snap/lsprelpath/cwd/shade.zig Save New Newtty Del
-|17: 1 pub const Shade = enum {
-|18: 2 verdigris,
-|19: 3 cinnabar,
-|20: 4 };
-|21: 5
-== style abslook grid=100x34
-|0: 0-74 #949494,#121212, 75-99 d,#121212,
-|1: 0-1 #ffffff,#262626, 2-79 #949494,#121212, 80-99 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-20 #bdbdbd,#080808, 21-27 #cf87e8,#080808,b 28-28 #bdbdbd,#080808, 29-42 #e3c78a,#080808, 43-44 #bdbdbd,#080808, 45-99 d,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-12 #cf87e8,#080808,b 13-38 #bdbdbd,#080808, 39-99 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-16 #cf87e8,#080808,b 17-17 #bdbdbd,#080808, 18-23 #cf87e8,#080808,b 24-29 #bdbdbd,#080808, 30-99 d,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-15 #bdbdbd,#080808, 16-99 d,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808,
-|8: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-7 #bdbdbd,#080808, 8-99 d,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|11: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|16: 0-1 #ffffff,#626262, 2-79 #949494,#121212, 80-99 d,#121212,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-24 #bdbdbd,#080808, 25-28 #cf87e8,#080808,b 29-30 #bdbdbd,#080808, 31-99 d,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-10 #bdbdbd,#080808, 11-19 #080808,#80a0ff, 20-20 #bdbdbd,#080808, 21-99 d,#080808,
-|19: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-19 #bdbdbd,#080808, 20-99 d,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-8 #bdbdbd,#080808, 9-99 d,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|29: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|30: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|31: 0-1 #ffffff,#262626, 2-79 #949494,#121212, 80-99 d,#121212,
-|32: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-76 #bdbdbd,#080808, 77-99 d,#080808,
-|33: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-74 #bdbdbd,#080808, 75-99 d,#080808,
-== snap subrow grid=100x34 cursor=16,6
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|^ /tmp/pardes-snap/lsprelpath/cwd/sub/subdir.zig * Save New Newtty Del
+== snap abslook grid=100x35 cursor=19,19
+|2: /tmp/pardes-snap/lsprelpath/cwd/sub/parent.zig * Save Tty Del Collapse
+|17: /tmp/pardes-snap/lsprelpath/cwd/shade.zig Save Tty Del Collapse
+|18: 1 pub const Shade = enum {
+|19: 2 verdigris,
+|20: 3 cinnabar,
+|21: 4 };
+|22: 5
+== style abslook grid=100x35
+|0: 0-70 #b2c3b8,#1d2824, 71-99 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-99 d,#26362d,
+|2: 0-1 #ffffff,#4c6356, 2-71 #b2c3b8,#1d2824, 72-99 d,#1d2824,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-20 #e5eee5,#0d1410, 21-27 #c9b0e4,#0d1410, 28-28 #e5eee5,#0d1410, 29-42 #b6ce94,#0d1410, 43-44 #e5eee5,#0d1410, 45-99 d,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-12 #c9b0e4,#0d1410, 13-38 #e5eee5,#0d1410, 39-99 d,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-16 #c9b0e4,#0d1410, 17-17 #e5eee5,#0d1410, 18-23 #c9b0e4,#0d1410, 24-29 #e5eee5,#0d1410, 30-99 d,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-15 #e5eee5,#0d1410, 16-99 d,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-99 d,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-7 #e5eee5,#0d1410, 8-99 d,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|17: 0-1 #000000,#adcc91, 2-64 #becfc4,#26362d, 65-99 d,#26362d,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-24 #e5eee5,#0d1410, 25-28 #c9b0e4,#0d1410, 29-30 #e5eee5,#0d1410, 31-99 d,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-10 #e5eee5,#0d1410, 11-19 #f5f7ee,#405d4b, 20-20 #e5eee5,#0d1410, 21-99 d,#0d1410,
+|20: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-19 #e5eee5,#0d1410, 20-99 d,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-8 #e5eee5,#0d1410, 9-99 d,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|31: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|32: 0-1 #ffffff,#4c6356, 2-66 #b2c3b8,#1d2824, 67-99 d,#1d2824,
+|33: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-54 #59675c,#0d1410, 55-76 #e5eee5,#0d1410, 77-99 d,#0d1410,
+|34: 0-0 d,#152019, 1-1 d,#0d1410, 2-54 #59675c,#0d1410, 55-74 #e5eee5,#0d1410, 75-99 d,#0d1410,
+== snap subrow grid=100x35 cursor=16,7
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+|^ /tmp/pardes-snap/lsprelpath/cwd/sub/subdir.zig * Save Tty Del Collapse
| 1 const tint = @import("inner/tint.zig");
| 2
| 3 pub fn hue(t: tint.Tint) u8 {
@@ -108,50 +111,51 @@
|
|
|
-| /tmp/pardes-snap/lsprelpath/cwd/sub/+Search Save New Newtty Del
+| /tmp/pardes-snap/lsprelpath/cwd/sub/+Search Save Tty Del Collapse
| 1 inner/tint.zig:2:5-9 ochre ochre,
| 2 inner/tint.zig:3:5-10 indigo indigo,
-== snap sublook grid=100x34 cursor=15,18
-|1: /tmp/pardes-snap/lsprelpath/cwd/sub/subdir.zig * Save New Newtty Del
-|16: /tmp/pardes-snap/lsprelpath/cwd/sub/inner/tint.zig Save New Newtty Del
-|17: 1 pub const Tint = enum {
-|18: 2 ochre,
-|19: 3 indigo,
-|20: 4 };
-|21: 5
-== style sublook grid=100x34
-|0: 0-74 #949494,#121212, 75-99 d,#121212,
-|1: 0-1 #ffffff,#262626, 2-79 #949494,#121212, 80-99 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-19 #bdbdbd,#080808, 20-26 #cf87e8,#080808,b 27-27 #bdbdbd,#080808, 28-43 #e3c78a,#080808, 44-45 #bdbdbd,#080808, 46-99 d,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-12 #cf87e8,#080808,b 13-35 #bdbdbd,#080808, 36-99 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-16 #cf87e8,#080808,b 17-17 #bdbdbd,#080808, 18-23 #cf87e8,#080808,b 24-29 #bdbdbd,#080808, 30-99 d,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-15 #bdbdbd,#080808, 16-99 d,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808,
-|8: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-7 #bdbdbd,#080808, 8-99 d,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|11: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|16: 0-1 #ffffff,#626262, 2-79 #949494,#121212, 80-99 d,#121212,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-23 #bdbdbd,#080808, 24-27 #cf87e8,#080808,b 28-29 #bdbdbd,#080808, 30-99 d,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-10 #bdbdbd,#080808, 11-15 #080808,#80a0ff, 16-16 #bdbdbd,#080808, 17-99 d,#080808,
-|19: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-17 #bdbdbd,#080808, 18-99 d,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-8 #bdbdbd,#080808, 9-99 d,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|29: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|30: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|31: 0-1 #ffffff,#262626, 2-79 #949494,#121212, 80-99 d,#121212,
-|32: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-40 #bdbdbd,#080808, 41-99 d,#080808,
-|33: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-43 #bdbdbd,#080808, 44-99 d,#080808,
-== snap clicked grid=100x34 cursor=16,19
+== snap sublook grid=100x35 cursor=15,19
+|2: /tmp/pardes-snap/lsprelpath/cwd/sub/subdir.zig * Save Tty Del Collapse
+|17: /tmp/pardes-snap/lsprelpath/cwd/sub/inner/tint.zig Save Tty Del Collapse
+|18: 1 pub const Tint = enum {
+|19: 2 ochre,
+|20: 3 indigo,
+|21: 4 };
+|22: 5
+== style sublook grid=100x35
+|0: 0-70 #b2c3b8,#1d2824, 71-99 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-99 d,#26362d,
+|2: 0-1 #ffffff,#4c6356, 2-71 #b2c3b8,#1d2824, 72-99 d,#1d2824,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-19 #e5eee5,#0d1410, 20-26 #c9b0e4,#0d1410, 27-27 #e5eee5,#0d1410, 28-43 #b6ce94,#0d1410, 44-45 #e5eee5,#0d1410, 46-99 d,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-12 #c9b0e4,#0d1410, 13-35 #e5eee5,#0d1410, 36-99 d,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-16 #c9b0e4,#0d1410, 17-17 #e5eee5,#0d1410, 18-23 #c9b0e4,#0d1410, 24-29 #e5eee5,#0d1410, 30-99 d,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-15 #e5eee5,#0d1410, 16-99 d,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-99 d,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-7 #e5eee5,#0d1410, 8-99 d,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|17: 0-1 #000000,#adcc91, 2-73 #becfc4,#26362d, 74-99 d,#26362d,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-23 #e5eee5,#0d1410, 24-27 #c9b0e4,#0d1410, 28-29 #e5eee5,#0d1410, 30-99 d,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-10 #e5eee5,#0d1410, 11-15 #f5f7ee,#405d4b, 16-16 #e5eee5,#0d1410, 17-99 d,#0d1410,
+|20: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-17 #e5eee5,#0d1410, 18-99 d,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-8 #e5eee5,#0d1410, 9-99 d,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|31: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|32: 0-1 #ffffff,#4c6356, 2-66 #b2c3b8,#1d2824, 67-99 d,#1d2824,
+|33: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-26 #59675c,#0d1410, 27-40 #e5eee5,#0d1410, 41-99 d,#0d1410,
+|34: 0-0 d,#152019, 1-1 d,#0d1410, 2-27 #59675c,#0d1410, 28-43 #e5eee5,#0d1410, 44-99 d,#0d1410,
+== snap clicked grid=100x35 cursor=16,20
diff --git a/test/snapshots/lsprelpath.snap b/test/snapshots/lsprelpath.snap
index 1ff6f549..247390fe 100644
--- a/test/snapshots/lsprelpath.snap
+++ b/test/snapshots/lsprelpath.snap
@@ -30,12 +30,12 @@ file sub/inner/tint.zig pub const Tint = enum {\n ochre,\n indigo,\n};\n
file sub/parent.zig const shade = @import("../shade.zig");\n\npub fn pick(s: shade.Shade) u8 {\n return switch (s) {\n \n };\n}\n
file sub/subdir.zig const tint = @import("inner/tint.zig");\n\npub fn hue(t: tint.Tint) u8 {\n return switch (t) {\n \n };\n}\n
# ---- PARENT: outside the asking file's tree, so the row stays absolute ----
-start 34 100 sub/parent.zig
+start 35 100 sub/parent.zig
wait 8000 fn pick
stable 700 20000
# file line 5 (grid row 6, 1-based click row 7) is the switch's empty body
-press left 8 7
-release left 8 7
+press left 8 8
+release left 8 8
stable 400 5000
key i
key end
@@ -55,11 +55,11 @@ stable 700 15000
snap abslook
snapstyle abslook
# ---- SUBDIRECTORY: under it, so the strip leaves `inner/tint.zig` ----
-start 34 100 sub/subdir.zig
+start 35 100 sub/subdir.zig
wait 8000 fn hue
stable 700 20000
-press left 8 7
-release left 8 7
+press left 8 8
+release left 8 8
stable 400 5000
key i
key end
@@ -83,7 +83,7 @@ snapstyle sublook
# `inner/` and stops on the space of the line-number prefix. A look focuses
# what it opens, so the header's cursor is the assertion: the end of `indigo`
# on line 3 of tint.zig.
-press right 12 34
-release right 12 34
+press right 12 35
+release right 12 35
stable 700 15000
snap clicked
diff --git a/test/snapshots/markup.golden b/test/snapshots/markup.golden
index d03e6b19..7caaf5b1 100644
--- a/test/snapshots/markup.golden
+++ b/test/snapshots/markup.golden
@@ -1,6 +1,7 @@
-== snap typst grid=92x24 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/markup/cwd/paper.typ Save New Newtty Del
+== snap typst grid=92x25 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/markup/cwd/paper.typ Save Tty Del Collapse
| 1 = Typst heading
| 2
| 3 Prose with *bold* and _italic_ words, a `raw` span,
@@ -10,34 +11,36 @@
| 7 fn widget() u8 { return 99; }
| 8 ```
| 9
-== style typst grid=92x24
-|0: 0-74 #949494,#121212, 75-91 d,#121212,
-|1: 0-1 #ffffff,#626262, 2-71 #949494,#121212, 72-91 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-21 #cf87e8,#080808,b 22-91 d,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-17 #bdbdbd,#080808, 18-23 #ffffff,#080808,b 24-28 #bdbdbd,#080808, 29-36 #e3c78a,#080808, 37-46 #bdbdbd,#080808, 47-51 #e3c78a,#080808, 52-57 #bdbdbd,#080808, 58-91 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-15 #cf87e8,#080808,b 16-27 #bdbdbd,#080808, 28-31 #cf87e8,#080808,b 32-36 #bdbdbd,#080808, 37-38 #e3c78a,#080808, 39-91 d,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #e3c78a,#080808, 13-91 d,#080808,
-|8: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-8 #cf87e8,#080808,b 9-23 #bdbdbd,#080808, 24-29 #cf87e8,#080808,b 30-30 #bdbdbd,#080808, 31-32 #e3c78a,#080808, 33-35 #bdbdbd,#080808, 36-91 d,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-9 #e3c78a,#080808, 10-91 d,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|11: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|16: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|19: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-== snap markdown grid=92x24 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/markup/cwd/notes.md Save New Newtty Del
+== style typst grid=92x25
+|0: 0-70 #b2c3b8,#1d2824, 71-91 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-91 d,#26362d,
+|2: 0-1 #000000,#adcc91, 2-60 #becfc4,#26362d, 61-91 d,#26362d,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-21 #c9b0e4,#0d1410, 22-91 d,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-17 #e5eee5,#0d1410, 18-23 #b9e58f,#0d1410, 24-28 #e5eee5,#0d1410, 29-36 #e9bf91,#0d1410, 37-46 #e5eee5,#0d1410, 47-51 #b6ce94,#0d1410, 52-57 #e5eee5,#0d1410, 58-91 d,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-15 #c9b0e4,#0d1410, 16-27 #e5eee5,#0d1410, 28-31 #c9b0e4,#0d1410, 32-36 #e5eee5,#0d1410, 37-38 #e9bf91,#0d1410, 39-91 d,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #b6ce94,#0d1410, 13-91 d,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-8 #c9b0e4,#0d1410, 9-23 #e5eee5,#0d1410, 24-29 #c9b0e4,#0d1410, 30-30 #e5eee5,#0d1410, 31-32 #e9bf91,#0d1410, 33-35 #e5eee5,#0d1410, 36-91 d,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-9 #b6ce94,#0d1410, 10-91 d,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|17: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|20: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+== snap markdown grid=92x25 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/markup/cwd/notes.md Save Tty Del Collapse
| 1 # Markdown heading with *italic*
| 2
| 3 Prose with **bold**, *italic* and an `inline` span.
@@ -46,28 +49,29 @@
| 6 fn gadget() u8 { return 77; }
| 7 ```
| 8
-== style markdown grid=92x24
-|0: 0-74 #949494,#121212, 75-91 d,#121212,
-|1: 0-1 #ffffff,#626262, 2-71 #949494,#121212, 72-91 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-8 #bdbdbd,#080808, 9-30 #cf87e8,#080808,b 31-38 #e3c78a,#080808, 39-91 d,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-17 #bdbdbd,#080808, 18-25 #ffffff,#080808,b 26-27 #bdbdbd,#080808, 28-35 #e3c78a,#080808, 36-43 #bdbdbd,#080808, 44-51 #e3c78a,#080808, 52-57 #bdbdbd,#080808, 58-91 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #e3c78a,#080808, 13-91 d,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-8 #cf87e8,#080808,b 9-23 #bdbdbd,#080808, 24-29 #cf87e8,#080808,b 30-30 #bdbdbd,#080808, 31-32 #e3c78a,#080808, 33-35 #bdbdbd,#080808, 36-91 d,#080808,
-|8: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-9 #e3c78a,#080808, 10-91 d,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|11: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|16: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|19: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-91 d,#080808,
+== style markdown grid=92x25
+|0: 0-70 #b2c3b8,#1d2824, 71-91 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-91 d,#26362d,
+|2: 0-1 #000000,#adcc91, 2-59 #becfc4,#26362d, 60-91 d,#26362d,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-8 #e5eee5,#0d1410, 9-30 #c9b0e4,#0d1410, 31-38 #e9bf91,#0d1410, 39-91 d,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-17 #e5eee5,#0d1410, 18-25 #b9e58f,#0d1410, 26-27 #e5eee5,#0d1410, 28-35 #e9bf91,#0d1410, 36-43 #e5eee5,#0d1410, 44-51 #b6ce94,#0d1410, 52-57 #e5eee5,#0d1410, 58-91 d,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #b6ce94,#0d1410, 13-91 d,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-8 #c9b0e4,#0d1410, 9-23 #e5eee5,#0d1410, 24-29 #c9b0e4,#0d1410, 30-30 #e5eee5,#0d1410, 31-32 #e9bf91,#0d1410, 33-35 #e5eee5,#0d1410, 36-91 d,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-9 #b6ce94,#0d1410, 10-91 d,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|17: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|20: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-91 d,#0d1410,
diff --git a/test/snapshots/markup.snap b/test/snapshots/markup.snap
index 2a28d7d7..dc910c70 100644
--- a/test/snapshots/markup.snap
+++ b/test/snapshots/markup.snap
@@ -4,13 +4,13 @@
# and italics at all, and both languages inject a tagged code block's language
file paper.typ = Typst heading\n\nProse with *bold* and _italic_ words, a `raw` span,\nand #emph[call] plus #let n = 42\n\n```zig\nfn widget() u8 { return 99; }\n```\n
file notes.md # Markdown heading with *italic*\n\nProse with **bold**, *italic* and an `inline` span.\n\n```zig\nfn gadget() u8 { return 77; }\n```\n
-start 24 92 paper.typ
+start 25 92 paper.typ
wait 8000 Typst heading
wait 8000 widget
stable 700 20000
snap typst
snapstyle typst
-start 24 92 notes.md
+start 25 92 notes.md
wait 8000 Markdown heading
wait 8000 gadget
stable 700 20000
diff --git a/test/snapshots/mini.golden b/test/snapshots/mini.golden
index 16e170f6..aac5dee6 100644
--- a/test/snapshots/mini.golden
+++ b/test/snapshots/mini.golden
@@ -1,6 +1,7 @@
-== snap opened grid=90x22 cursor=7,13
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/mini/cwd/commands.txt Save New Newtty Del
+== snap opened grid=90x23 cursor=7,14
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/mini/cwd/commands.txt Save Tty Del Collapse
| 1 @`Mini demo.zig`
|
|
@@ -11,103 +12,107 @@
|
|
|
-| /tmp/pardes-snap/mini/cwd/Mini demo.zig Save New Newtty Del
+| /tmp/pardes-snap/mini/cwd/Mini demo.zig Save Tty Del Collapse
| 1 ⠭⠍⣥⢩⣭⡭⣭⣬⣌⢭⣭⠌⠬⠅⠍⠁
| 2 ⣂⢀⣉⣉⢉⣈⢁⣀⣀⢀⣀⣀⣀⢀⣀⣀⣀⣀⣀
| 3 ⠉⠉⠁⠉⠉⠉⠈⠈⠉⠉⠉⠉⠉⠉
| 4
-== style opened grid=90x22
-|0: 0-74 #949494,#121212, 75-89 d,#121212,
-|1: 0-1 #ffffff,#262626, 2-69 #949494,#121212, 70-89 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-22 #bdbdbd,#080808, 23-89 d,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-|8: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-|11: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-|12: 0-1 #ffffff,#626262, 2-69 #949494,#121212, 70-89 d,#121212,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-8 #bdbdbd,#080808, 9-9 #cf87e8,#080808,b 10-12 #bdbdbd,#080808, 13-15 #cf87e8,#080808,b 16-21 #e3c78a,#080808, 22-22 #bdbdbd,#080808, 23-89 d,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-8 #ffffff,#080808,b 9-11 #cf87e8,#080808,b 12-25 #ffffff,#080808,b 26-89 d,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-17 #bdbdbd,#080808, 18-19 #e3c78a,#080808, 20-20 #bdbdbd,#080808, 21-89 d,#080808,
-|16: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-|19: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-== 9p opened grid=90x22 cursor=7,13,block
-|0: New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-@0: 0-74 #949494,#121212,,tagline 75-89 d,#121212,,tagline
-|1: /tmp/pardes-snap/mini/cwd/commands.txt Save New Newtty Del
-@1: 0-1 #ffffff,#262626,,tagline 2-69 #949494,#121212,,tagline 70-89 d,#121212,,tagline
-|2: 1 @`Mini demo.zig`
-@2: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-22 #bdbdbd,#080808,,body 23-89 d,#080808,,body
-|3:
-@3: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
+== style opened grid=90x23
+|0: 0-70 #b2c3b8,#1d2824, 71-89 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-89 d,#26362d,
+|2: 0-1 #ffffff,#4c6356, 2-61 #b2c3b8,#1d2824, 62-89 d,#1d2824,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-22 #e5eee5,#0d1410, 23-89 d,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+|13: 0-1 #000000,#adcc91, 2-62 #becfc4,#26362d, 63-89 d,#26362d,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-8 #e5eee5,#0d1410, 9-9 #c9b0e4,#0d1410, 10-12 #e5eee5,#0d1410, 13-15 #c9b0e4,#0d1410, 16-21 #b6ce94,#0d1410, 22-22 #e5eee5,#0d1410, 23-89 d,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-8 #b9e58f,#0d1410, 9-11 #c9b0e4,#0d1410, 12-25 #b9e58f,#0d1410, 26-89 d,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-17 #e5eee5,#0d1410, 18-19 #e9bf91,#0d1410, 20-20 #e5eee5,#0d1410, 21-89 d,#0d1410,
+|17: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+|20: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+== 9p opened grid=90x23 cursor=7,14,block
+|0: Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+@0: 0-70 #b2c3b8,#1d2824,,tagline 71-89 d,#1d2824,,tagline
+|1: New Tty Find Grep Joincol
+@1: 0-24 #becfc4,#26362d,,tagline 25-89 d,#26362d,,tagline
+|2: /tmp/pardes-snap/mini/cwd/commands.txt Save Tty Del Collapse
+@2: 0-1 #ffffff,#4c6356,,tagline 2-61 #b2c3b8,#1d2824,,tagline 62-89 d,#1d2824,,tagline
+|3: 1 @`Mini demo.zig`
+@3: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-22 #e5eee5,#0d1410,,body 23-89 d,#0d1410,,body
|4:
-@4: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
+@4: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
|5:
-@5: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
+@5: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
|6:
-@6: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
+@6: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
|7:
-@7: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
+@7: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
|8:
-@8: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
+@8: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
|9:
-@9: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
+@9: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
|10:
-@10: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
+@10: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
|11:
-@11: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
-|12: /tmp/pardes-snap/mini/cwd/Mini demo.zig Save New Newtty Del
-@12: 0-1 #ffffff,#626262,,tagline 2-69 #949494,#121212,,tagline 70-89 d,#121212,,tagline
-|13: 1 ⠭⠍⣥⢩⣭⡭⣭⣬⣌⢭⣭⠌⠬⠅⠍⠁
-+13: 7="⠭" 8="⠍" 9="⣥" 10="⢩" 11="⣭" 12="⡭" 13="⣭" 14="⣬" 15="⣌" 16="⢭" 17="⣭" 18="⠌" 19="⠬" 20="⠅" 21="⠍" 22="⠁"
-@13: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #949494,#121212,,body 7-8 #bdbdbd,#080808,,body 9-9 #cf87e8,#080808,b,body 10-12 #bdbdbd,#080808,,body 13-15 #cf87e8,#080808,b,body 16-21 #e3c78a,#080808,,body 22-22 #bdbdbd,#080808,,body 23-89 d,#080808,,body
-|14: 2 ⣂⢀⣉⣉⢉⣈⢁⣀⣀⢀⣀⣀⣀⢀⣀⣀⣀⣀⣀
-+14: 7="⣂" 8="⢀" 9="⣉" 10="⣉" 11="⢉" 12="⣈" 13="⢁" 14="⣀" 15="⣀" 16="⢀" 17="⣀" 18="⣀" 19="⣀" 20="⢀" 21="⣀" 22="⣀" 23="⣀" 24="⣀" 25="⣀"
-@14: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-8 #ffffff,#080808,b,body 9-11 #cf87e8,#080808,b,body 12-25 #ffffff,#080808,b,body 26-89 d,#080808,,body
-|15: 3 ⠉⠉⠁⠉⠉⠉⠈⠈⠉⠉⠉⠉⠉⠉
-+15: 7="⠉" 8="⠉" 9="⠁" 10="⠉" 11="⠉" 12="⠉" 13="⠈" 14="⠈" 15="⠉" 16="⠉" 17="⠉" 18="⠉" 19="⠉" 20="⠉"
-@15: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-17 #bdbdbd,#080808,,body 18-19 #e3c78a,#080808,,body 20-20 #bdbdbd,#080808,,body 21-89 d,#080808,,body
-|16: 4
-@16: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
-|17:
-@17: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
+@11: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
+|12:
+@12: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
+|13: /tmp/pardes-snap/mini/cwd/Mini demo.zig Save Tty Del Collapse
+@13: 0-1 #000000,#adcc91,,tagline 2-62 #becfc4,#26362d,,tagline 63-89 d,#26362d,,tagline
+|14: 1 ⠭⠍⣥⢩⣭⡭⣭⣬⣌⢭⣭⠌⠬⠅⠍⠁
++14: 7="⠭" 8="⠍" 9="⣥" 10="⢩" 11="⣭" 12="⡭" 13="⣭" 14="⣬" 15="⣌" 16="⢭" 17="⣭" 18="⠌" 19="⠬" 20="⠅" 21="⠍" 22="⠁"
+@14: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #616f64,#0d1410,b,body 7-8 #e5eee5,#0d1410,,body 9-9 #c9b0e4,#0d1410,,body 10-12 #e5eee5,#0d1410,,body 13-15 #c9b0e4,#0d1410,,body 16-21 #b6ce94,#0d1410,,body 22-22 #e5eee5,#0d1410,,body 23-89 d,#0d1410,,body
+|15: 2 ⣂⢀⣉⣉⢉⣈⢁⣀⣀⢀⣀⣀⣀⢀⣀⣀⣀⣀⣀
++15: 7="⣂" 8="⢀" 9="⣉" 10="⣉" 11="⢉" 12="⣈" 13="⢁" 14="⣀" 15="⣀" 16="⢀" 17="⣀" 18="⣀" 19="⣀" 20="⢀" 21="⣀" 22="⣀" 23="⣀" 24="⣀" 25="⣀"
+@15: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-8 #b9e58f,#0d1410,,body 9-11 #c9b0e4,#0d1410,,body 12-25 #b9e58f,#0d1410,,body 26-89 d,#0d1410,,body
+|16: 3 ⠉⠉⠁⠉⠉⠉⠈⠈⠉⠉⠉⠉⠉⠉
++16: 7="⠉" 8="⠉" 9="⠁" 10="⠉" 11="⠉" 12="⠉" 13="⠈" 14="⠈" 15="⠉" 16="⠉" 17="⠉" 18="⠉" 19="⠉" 20="⠉"
+@16: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-17 #e5eee5,#0d1410,,body 18-19 #e9bf91,#0d1410,,body 20-20 #e5eee5,#0d1410,,body 21-89 d,#0d1410,,body
+|17: 4
+@17: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
|18:
-@18: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
+@18: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
|19:
-@19: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
+@19: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
|20:
-@20: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
+@20: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
|21:
-@21: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
-== style colors-off grid=90x22
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-22 #bdbdbd,#080808, 23-89 d,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-25 #bdbdbd,#080808, 26-89 d,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-20 #bdbdbd,#080808, 21-89 d,#080808,
-== 9p colors-off grid=90x22 cursor=7,13,block
-|13: 1 ⠭⠍⣥⢩⣭⡭⣭⣬⣌⢭⣭⠌⠬⠅⠍⠁
-+13: 7="⠭" 8="⠍" 9="⣥" 10="⢩" 11="⣭" 12="⡭" 13="⣭" 14="⣬" 15="⣌" 16="⢭" 17="⣭" 18="⠌" 19="⠬" 20="⠅" 21="⠍" 22="⠁"
-@13: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #949494,#121212,,body 7-22 #bdbdbd,#080808,,body 23-89 d,#080808,,body
-|14: 2 ⣂⢀⣉⣉⢉⣈⢁⣀⣀⢀⣀⣀⣀⢀⣀⣀⣀⣀⣀
-+14: 7="⣂" 8="⢀" 9="⣉" 10="⣉" 11="⢉" 12="⣈" 13="⢁" 14="⣀" 15="⣀" 16="⢀" 17="⣀" 18="⣀" 19="⣀" 20="⢀" 21="⣀" 22="⣀" 23="⣀" 24="⣀" 25="⣀"
-@14: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-25 #bdbdbd,#080808,,body 26-89 d,#080808,,body
-|15: 3 ⠉⠉⠁⠉⠉⠉⠈⠈⠉⠉⠉⠉⠉⠉
-+15: 7="⠉" 8="⠉" 9="⠁" 10="⠉" 11="⠉" 12="⠉" 13="⠈" 14="⠈" 15="⠉" 16="⠉" 17="⠉" 18="⠉" 19="⠉" 20="⠉"
-@15: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-20 #bdbdbd,#080808,,body 21-89 d,#080808,,body
-== style colors-on grid=90x22
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-8 #bdbdbd,#080808, 9-9 #cf87e8,#080808,b 10-12 #bdbdbd,#080808, 13-15 #cf87e8,#080808,b 16-21 #e3c78a,#080808, 22-22 #bdbdbd,#080808, 23-89 d,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-8 #ffffff,#080808,b 9-11 #cf87e8,#080808,b 12-25 #ffffff,#080808,b 26-89 d,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-17 #bdbdbd,#080808, 18-19 #e3c78a,#080808, 20-20 #bdbdbd,#080808, 21-89 d,#080808,
-== snap resized grid=105x26 cursor=7,15
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/mini/cwd/commands.txt Save New Newtty Del
+@21: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
+|22:
+@22: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
+== style colors-off grid=90x23
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-22 #e5eee5,#0d1410, 23-89 d,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-25 #e5eee5,#0d1410, 26-89 d,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-20 #e5eee5,#0d1410, 21-89 d,#0d1410,
+== 9p colors-off grid=90x23 cursor=7,14,block
+|14: 1 ⠭⠍⣥⢩⣭⡭⣭⣬⣌⢭⣭⠌⠬⠅⠍⠁
++14: 7="⠭" 8="⠍" 9="⣥" 10="⢩" 11="⣭" 12="⡭" 13="⣭" 14="⣬" 15="⣌" 16="⢭" 17="⣭" 18="⠌" 19="⠬" 20="⠅" 21="⠍" 22="⠁"
+@14: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #616f64,#0d1410,b,body 7-22 #e5eee5,#0d1410,,body 23-89 d,#0d1410,,body
+|15: 2 ⣂⢀⣉⣉⢉⣈⢁⣀⣀⢀⣀⣀⣀⢀⣀⣀⣀⣀⣀
++15: 7="⣂" 8="⢀" 9="⣉" 10="⣉" 11="⢉" 12="⣈" 13="⢁" 14="⣀" 15="⣀" 16="⢀" 17="⣀" 18="⣀" 19="⣀" 20="⢀" 21="⣀" 22="⣀" 23="⣀" 24="⣀" 25="⣀"
+@15: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-25 #e5eee5,#0d1410,,body 26-89 d,#0d1410,,body
+|16: 3 ⠉⠉⠁⠉⠉⠉⠈⠈⠉⠉⠉⠉⠉⠉
++16: 7="⠉" 8="⠉" 9="⠁" 10="⠉" 11="⠉" 12="⠉" 13="⠈" 14="⠈" 15="⠉" 16="⠉" 17="⠉" 18="⠉" 19="⠉" 20="⠉"
+@16: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-20 #e5eee5,#0d1410,,body 21-89 d,#0d1410,,body
+== style colors-on grid=90x23
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-8 #e5eee5,#0d1410, 9-9 #c9b0e4,#0d1410, 10-12 #e5eee5,#0d1410, 13-15 #c9b0e4,#0d1410, 16-21 #b6ce94,#0d1410, 22-22 #e5eee5,#0d1410, 23-89 d,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-8 #b9e58f,#0d1410, 9-11 #c9b0e4,#0d1410, 12-25 #b9e58f,#0d1410, 26-89 d,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-17 #e5eee5,#0d1410, 18-19 #e9bf91,#0d1410, 20-20 #e5eee5,#0d1410, 21-89 d,#0d1410,
+== snap resized grid=105x27 cursor=7,16
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/mini/cwd/commands.txt Save Tty Del Collapse
| 1 @`Mini demo.zig`
|
|
@@ -120,64 +125,66 @@
|
|
|
-| /tmp/pardes-snap/mini/cwd/Mini demo.zig Save New Newtty Del
+| /tmp/pardes-snap/mini/cwd/Mini demo.zig Save Tty Del Collapse
| 1 ⠭⠍⣥⢩⣭⡭⣭⣬⣌⢭⣭⠌⠬⠅⠍⠁
| 2 ⣂⢀⣉⣉⢉⣈⢁⣀⣀⢀⣀⣀⣀⢀⣀⣀⣀⣀⣀
| 3 ⠉⠉⠁⠉⠉⠉⠈⠈⠉⠉⠉⠉⠉⠉
| 4
-== 9p resized grid=105x26 cursor=7,15,block
-|0: New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-@0: 0-74 #949494,#121212,,tagline 75-104 d,#121212,,tagline
-|1: /tmp/pardes-snap/mini/cwd/commands.txt Save New Newtty Del
-@1: 0-1 #ffffff,#262626,,tagline 2-84 #949494,#121212,,tagline 85-104 d,#121212,,tagline
-|2: 1 @`Mini demo.zig`
-@2: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-22 #bdbdbd,#080808,,body 23-104 d,#080808,,body
-|3:
-@3: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+== 9p resized grid=105x27 cursor=7,16,block
+|0: Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+@0: 0-70 #b2c3b8,#1d2824,,tagline 71-104 d,#1d2824,,tagline
+|1: New Tty Find Grep Joincol
+@1: 0-24 #becfc4,#26362d,,tagline 25-104 d,#26362d,,tagline
+|2: /tmp/pardes-snap/mini/cwd/commands.txt Save Tty Del Collapse
+@2: 0-1 #ffffff,#4c6356,,tagline 2-61 #b2c3b8,#1d2824,,tagline 62-104 d,#1d2824,,tagline
+|3: 1 @`Mini demo.zig`
+@3: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-22 #e5eee5,#0d1410,,body 23-104 d,#0d1410,,body
|4:
-@4: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@4: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|5:
-@5: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@5: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|6:
-@6: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@6: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|7:
-@7: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@7: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|8:
-@8: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@8: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|9:
-@9: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@9: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|10:
-@10: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@10: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|11:
-@11: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@11: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|12:
-@12: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@12: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|13:
-@13: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
-|14: /tmp/pardes-snap/mini/cwd/Mini demo.zig Save New Newtty Del
-@14: 0-1 #ffffff,#626262,,tagline 2-84 #949494,#121212,,tagline 85-104 d,#121212,,tagline
-|15: 1 ⠭⠍⣥⢩⣭⡭⣭⣬⣌⢭⣭⠌⠬⠅⠍⠁
-+15: 7="⠭" 8="⠍" 9="⣥" 10="⢩" 11="⣭" 12="⡭" 13="⣭" 14="⣬" 15="⣌" 16="⢭" 17="⣭" 18="⠌" 19="⠬" 20="⠅" 21="⠍" 22="⠁"
-@15: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #949494,#121212,,body 7-8 #bdbdbd,#080808,,body 9-9 #cf87e8,#080808,b,body 10-12 #bdbdbd,#080808,,body 13-15 #cf87e8,#080808,b,body 16-21 #e3c78a,#080808,,body 22-22 #bdbdbd,#080808,,body 23-104 d,#080808,,body
-|16: 2 ⣂⢀⣉⣉⢉⣈⢁⣀⣀⢀⣀⣀⣀⢀⣀⣀⣀⣀⣀
-+16: 7="⣂" 8="⢀" 9="⣉" 10="⣉" 11="⢉" 12="⣈" 13="⢁" 14="⣀" 15="⣀" 16="⢀" 17="⣀" 18="⣀" 19="⣀" 20="⢀" 21="⣀" 22="⣀" 23="⣀" 24="⣀" 25="⣀"
-@16: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-8 #ffffff,#080808,b,body 9-11 #cf87e8,#080808,b,body 12-25 #ffffff,#080808,b,body 26-104 d,#080808,,body
-|17: 3 ⠉⠉⠁⠉⠉⠉⠈⠈⠉⠉⠉⠉⠉⠉
-+17: 7="⠉" 8="⠉" 9="⠁" 10="⠉" 11="⠉" 12="⠉" 13="⠈" 14="⠈" 15="⠉" 16="⠉" 17="⠉" 18="⠉" 19="⠉" 20="⠉"
-@17: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-17 #bdbdbd,#080808,,body 18-19 #e3c78a,#080808,,body 20-20 #bdbdbd,#080808,,body 21-104 d,#080808,,body
-|18: 4
-@18: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
-|19:
-@19: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@13: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
+|14:
+@14: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
+|15: /tmp/pardes-snap/mini/cwd/Mini demo.zig Save Tty Del Collapse
+@15: 0-1 #000000,#adcc91,,tagline 2-62 #becfc4,#26362d,,tagline 63-104 d,#26362d,,tagline
+|16: 1 ⠭⠍⣥⢩⣭⡭⣭⣬⣌⢭⣭⠌⠬⠅⠍⠁
++16: 7="⠭" 8="⠍" 9="⣥" 10="⢩" 11="⣭" 12="⡭" 13="⣭" 14="⣬" 15="⣌" 16="⢭" 17="⣭" 18="⠌" 19="⠬" 20="⠅" 21="⠍" 22="⠁"
+@16: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #616f64,#0d1410,b,body 7-8 #e5eee5,#0d1410,,body 9-9 #c9b0e4,#0d1410,,body 10-12 #e5eee5,#0d1410,,body 13-15 #c9b0e4,#0d1410,,body 16-21 #b6ce94,#0d1410,,body 22-22 #e5eee5,#0d1410,,body 23-104 d,#0d1410,,body
+|17: 2 ⣂⢀⣉⣉⢉⣈⢁⣀⣀⢀⣀⣀⣀⢀⣀⣀⣀⣀⣀
++17: 7="⣂" 8="⢀" 9="⣉" 10="⣉" 11="⢉" 12="⣈" 13="⢁" 14="⣀" 15="⣀" 16="⢀" 17="⣀" 18="⣀" 19="⣀" 20="⢀" 21="⣀" 22="⣀" 23="⣀" 24="⣀" 25="⣀"
+@17: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-8 #b9e58f,#0d1410,,body 9-11 #c9b0e4,#0d1410,,body 12-25 #b9e58f,#0d1410,,body 26-104 d,#0d1410,,body
+|18: 3 ⠉⠉⠁⠉⠉⠉⠈⠈⠉⠉⠉⠉⠉⠉
++18: 7="⠉" 8="⠉" 9="⠁" 10="⠉" 11="⠉" 12="⠉" 13="⠈" 14="⠈" 15="⠉" 16="⠉" 17="⠉" 18="⠉" 19="⠉" 20="⠉"
+@18: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-17 #e5eee5,#0d1410,,body 18-19 #e9bf91,#0d1410,,body 20-20 #e5eee5,#0d1410,,body 21-104 d,#0d1410,,body
+|19: 4
+@19: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|20:
-@20: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@20: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|21:
-@21: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@21: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|22:
-@22: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@22: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|23:
-@23: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@23: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|24:
-@24: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@24: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|25:
-@25: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@25: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
+|26:
+@26: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
diff --git a/test/snapshots/mini.snap b/test/snapshots/mini.snap
index eacd86b9..4905c68d 100644
--- a/test/snapshots/mini.snap
+++ b/test/snapshots/mini.snap
@@ -1,10 +1,10 @@
file commands.txt @`Mini demo.zig`
file demo.zig const greeting = "café λ 界 é";\n\npub fn choose(ok: bool) u32 {\n if (ok) return 42;\n return 7;\n}\n\n// space and color survive compression\nconst answer = choose(true);\n
-start 22 90 commands.txt
+start 23 90 commands.txt
wait 8000 Mini demo.zig
stable 400 10000
-press middle @Mini 3
-release middle @Mini 3
+press middle @Mini 4
+release middle @Mini 4
wait 8000 /Mini demo.zig
stable 500 10000
snap opened
@@ -17,7 +17,7 @@ snap9p colors-off
key space t c
stable 300 8000
snapstyle colors-on
-resize 26 105
+resize 27 105
stable 400 10000
snap resized
snap9p resized
diff --git a/test/snapshots/modal.golden b/test/snapshots/modal.golden
index 545238f1..ca89416e 100644
--- a/test/snapshots/modal.golden
+++ b/test/snapshots/modal.golden
@@ -1,6 +1,7 @@
-== snap top grid=100x30 cursor=2,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/modal/cwd Save New Newtty Del F /tmp/pardes-snap/modal/cwd Save New Newtty Del F
+== snap top grid=100x31 cursor=2,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/modal/cwd Save Tty Del Togglett /tmp/pardes-snap/modal/cwd Save Tty Del Togglett
| ls ls
| words.txt words.txt
| printf 'one two three\nfour five six\nseven ei
@@ -15,53 +16,54 @@
|
|
|
-| /tmp/pardes-snap/modal/cwd Save New Newtty Del F
+| /tmp/pardes-snap/modal/cwd Save Tty Del Togglett
| ls
| words.txt
-== snap moved grid=100x30 cursor=8,4
-== snap xsel grid=100x30 cursor=48,4
-== style xsel grid=100x30
-|0: 0-74 #949494,#121212, 75-99 d,#121212,
-|1: 0-1 #ffffff,#626262, 2-49 #949494,#121212, 50-51 #ffffff,#262626, 52-99 #949494,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-48 #080808,#80a0ff, 49-49 d,#080808, 50-50 d,#444444, 51-99 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|8: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|9: 0-0 d,#444444, 1-49 d,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|11: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|16: 0-1 #ffffff,#262626, 2-49 #949494,#121212, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|19: 0-0 d,#444444, 1-49 d,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|29: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-== snap xsel2 grid=100x30 cursor=13,5
-== snap yanked grid=100x30 cursor=13,5
-== snap vsel grid=100x30 cursor=14,6
-== style vsel grid=100x30
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-49 #080808,#80a0ff, 50-50 d,#444444, 51-99 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-49 #080808,#80a0ff, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-14 #080808,#80a0ff, 15-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-== snap typed grid=100x30 cursor=7,4
-|4: TYPEDprintf 'one two three\nfour five six\nseven
-== snap undone grid=100x30 cursor=14,6
-|4: printf 'one two three\nfour five six\nseven ei
-== snap redone grid=100x30 cursor=7,4
-|4: TYPEDprintf 'one two three\nfour five six\nseven
-== snap bottom grid=100x30 cursor=2,9
+== snap moved grid=100x31 cursor=8,5
+== snap xsel grid=100x31 cursor=48,5
+== style xsel grid=100x31
+|0: 0-70 #b2c3b8,#1d2824, 71-99 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-49 d,#26362d, 50-74 #b2c3b8,#1d2824, 75-99 d,#1d2824,
+|2: 0-1 #000000,#adcc91, 2-49 #becfc4,#26362d, 50-51 #ffffff,#4c6356, 52-99 #b2c3b8,#1d2824,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-48 #f5f7ee,#405d4b, 49-49 d,#0d1410, 50-50 d,#637f6a, 51-99 d,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|10: 0-0 d,#637f6a, 1-49 d,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|17: 0-1 #ffffff,#4c6356, 2-49 #b2c3b8,#1d2824, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|20: 0-0 d,#637f6a, 1-49 d,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+== snap xsel2 grid=100x31 cursor=13,6
+== snap yanked grid=100x31 cursor=13,6
+== snap vsel grid=100x31 cursor=14,7
+== style vsel grid=100x31
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #f5f7ee,#405d4b, 50-50 d,#637f6a, 51-99 d,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #f5f7ee,#405d4b, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-14 #f5f7ee,#405d4b, 15-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+== snap typed grid=100x31 cursor=7,5
+|5: TYPEDprintf 'one two three\nfour five six\nseven
+== snap undone grid=100x31 cursor=14,7
+|5: printf 'one two three\nfour five six\nseven ei
+== snap redone grid=100x31 cursor=7,5
+|5: TYPEDprintf 'one two three\nfour five six\nseven
+== snap bottom grid=100x31 cursor=2,10
diff --git a/test/snapshots/modal.snap b/test/snapshots/modal.snap
index b6769fdd..9d82f0a3 100644
--- a/test/snapshots/modal.snap
+++ b/test/snapshots/modal.snap
@@ -1,6 +1,6 @@
# helix-modal normal mode: motions, x/v selections, y/d, insert, undo/redo
file words.txt alpha beta
-start 30 100 -n 3
+start 31 100 -n 3
wait 8000 words.txt
stable 700 20000
key c-b
@@ -11,8 +11,8 @@ wait 8000 seven
stable 700 10000
key c-b
stable 600 8000
-press left 5 6
-release left 5 6
+press left 5 7
+release left 5 7
stable 400 5000
key g g
stable 400 5000
diff --git a/test/snapshots/msg.golden b/test/snapshots/msg.golden
index fcfe5f26..9da23117 100644
--- a/test/snapshots/msg.golden
+++ b/test/snapshots/msg.golden
@@ -1,6 +1,7 @@
-== snap opened grid=70x14 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug
-| /tmp/pardes-snap/msg/cwd/a.txt Save New Newtty Del
+== snap opened grid=70x15 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kil
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/msg/cwd/a.txt Save Tty Del Collapse
| 1 line 1
| 2 line 2
| 3 line 3
@@ -8,11 +9,12 @@
| 5 line 5
| 6 line 6
| 7
-== snap saved grid=70x14 cursor=7,2
-|13: --:--:-- saved /tmp/pardes-snap/msg/cwd/a.txt
-== snap repainted grid=70x16 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug
-| /tmp/pardes-snap/msg/cwd/a.txt Save New Newtty Del
+== snap saved grid=70x15 cursor=7,3
+|14: --:--:-- saved /tmp/pardes-snap/msg/cwd/a.txt
+== snap repainted grid=70x17 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kil
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/msg/cwd/a.txt Save Tty Del Collapse
| 1 line 1
| 2 line 2
| 3 line 3
@@ -27,28 +29,28 @@
|
|
| --:--:-- saved /tmp/pardes-snap/msg/cwd/a.txt
-== snap keycleared grid=70x16 cursor=7,3
-|15:
-== snap saved-again grid=70x16 cursor=7,3
-|15: --:--:-- saved /tmp/pardes-snap/msg/cwd/a.txt
-== snap mousecleared grid=70x16 cursor=7,3
-|15:
-== snap reloaded grid=70x16 cursor=7,3
-|2: 1 EXTERNAL
-|3: 2
-|4:
+== snap keycleared grid=70x17 cursor=7,4
+|16:
+== snap saved-again grid=70x17 cursor=7,4
+|16: --:--:-- saved /tmp/pardes-snap/msg/cwd/a.txt
+== snap mousecleared grid=70x17 cursor=7,4
+|16:
+== snap reloaded grid=70x17 cursor=7,4
+|3: 1 EXTERNAL
+|4: 2
|5:
|6:
|7:
|8:
-|15: --:--:-- reloaded /tmp/pardes-snap/msg/cwd/a.txt
-== snap prompt grid=70x16 cursor=7,15
-|15: /EXT
-== snap prompt-wins grid=70x16 cursor=7,15
-|2: 1 AGAIN
-== snap esc grid=70x16 cursor=7,3
-|15:
-== snap msgbuiltin grid=70x16 cursor=29,4
-|1: /tmp/pardes-snap/msg/cwd/a.txt * Save New Newtty Del
-|4: 3 Msg hand-written report
-|15: hand-written report
+|9:
+|16: --:--:-- reloaded /tmp/pardes-snap/msg/cwd/a.txt
+== snap prompt grid=70x17 cursor=7,16
+|16: /EXT
+== snap prompt-wins grid=70x17 cursor=7,16
+|3: 1 AGAIN
+== snap esc grid=70x17 cursor=7,4
+|16:
+== snap msgbuiltin grid=70x17 cursor=29,5
+|2: /tmp/pardes-snap/msg/cwd/a.txt * Save Tty Del Collapse
+|5: 3 Msg hand-written report
+|16: hand-written report
diff --git a/test/snapshots/msg.snap b/test/snapshots/msg.snap
index d1371dab..c8a0a265 100644
--- a/test/snapshots/msg.snap
+++ b/test/snapshots/msg.snap
@@ -14,8 +14,8 @@
# key or mouse event wipes it. An armed PROMPT is what that keystroke is being
# typed INTO, it lives until Enter or Esc, and it WINS.
lines a.txt 6
-start 14 70 a.txt
-wait 8000 New Newcol
+start 15 70 a.txt
+wait 8000 Newcol Joincol
wait 8000 a.txt
stable 700 20000
snap opened
@@ -28,7 +28,7 @@ snap saved
# scratch and the message is still there on the other side of it — the row is
# state, not one frame's flash. (Different rows, or the kernel sends no
# SIGWINCH and nothing repaints.)
-resize 16 70
+resize 17 70
stable 700 15000
snap repainted
# ...but the next KEY takes it away. `j` is a plain cursor motion and changes
diff --git a/test/snapshots/multicursor.golden b/test/snapshots/multicursor.golden
index f27009a1..da2ad1d7 100644
--- a/test/snapshots/multicursor.golden
+++ b/test/snapshots/multicursor.golden
@@ -1,70 +1,68 @@
-== snap three-cursors grid=150x30 cursor=7,4
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/multicursor/cwd/f.txt Save New Newtty Del /tmp/pardes-snap/multicursor/cwd Save New Newtty Del Filter
-| 1 line 1 ls
-| 2 line 2 f.txt
+== snap three-cursors grid=150x31 cursor=7,9
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/multicursor/cwd Save Tty Del Togglettymode Filter Collap /tmp/pardes-snap/multicursor/cwd Save Tty Del Togglettymode Filter Collap
+| ls ls
+| f.txt f.txt
+|
+| /tmp/pardes-snap/multicursor/cwd/f.txt Save Tty Del Collapse
+| 1 line 1
+| 2 line 2
| 3 line 3
| 4 line 4
| 5 line 5
-|╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
-| /tmp/pardes-snap/multicursor/cwd Save New Newtty Del Filter
-| ls
-| f.txt
-|
-|
-|
-| f.txt
-|
-| /tmp/pardes-snap/multicursor/cwd Save New Newtty Del Filter
+| 6 line 6
+| 7 line 7
+| 8 line 8
+| 9 line 9
+| 10 line 10
+| /tmp/pardes-snap/multicursor/cwd Save Tty Del Togglettymode Filter Collap
| ls
| f.txt
-== style three-cursors grid=150x30
-|0: 0-74 #949494,#121212, 75-149 d,#121212,
-|1: 0-1 #ffffff,#626262, 2-60 #949494,#121212, 61-74 d,#121212, 75-76 #ffffff,#262626, 77-135 #949494,#121212, 136-149 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-7 #80a0ff,#080808, 8-12 #bdbdbd,#080808, 13-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-7 #80a0ff,#080808, 8-12 #bdbdbd,#080808, 13-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|4: 0-0 d,#121212, 1-1 d,#080808, 2-6 #949494,#121212, 7-12 #bdbdbd,#080808, 13-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|5: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|6: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|7: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|8: 0-1 #ffffff,#262626, 2-60 #949494,#121212, 61-74 d,#121212, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|11: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-8 #bdbdbd,#080808, 9-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|16: 0-1 #ffffff,#262626, 2-60 #949494,#121212, 61-74 d,#121212, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|19: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|29: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-== snap edited-at-three grid=150x30 cursor=9,4
-|1: /tmp/pardes-snap/multicursor/cwd/f.txt * Save New Newtty Del /tmp/pardes-snap/multicursor/cwd Save New Newtty Del Filter
-|2: 1 >>line 1 ls
-|3: 2 >>line 2 f.txt
-|4: 3 >>line 3
-|8: /tmp/pardes-snap/multicursor/cwd Save New Newtty Del Filter
-|16: /tmp/pardes-snap/multicursor/cwd Save New Newtty Del Filter
-== snap three-selections grid=150x30 cursor=8,4
-== style three-selections grid=150x30
-|1: 0-1 #ffffff,#626262, 2-61 #949494,#121212, 62-74 d,#121212, 75-76 #ffffff,#262626, 77-135 #949494,#121212, 136-149 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-7 #080808,#445483, 8-8 #80a0ff,#080808, 9-14 #bdbdbd,#080808, 15-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-7 #080808,#445483, 8-8 #80a0ff,#080808, 9-14 #bdbdbd,#080808, 15-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|4: 0-0 d,#121212, 1-1 d,#080808, 2-6 #949494,#121212, 7-8 #080808,#80a0ff, 9-14 #bdbdbd,#080808, 15-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|8: 0-1 #ffffff,#262626, 2-61 #949494,#121212, 62-74 d,#121212, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|16: 0-1 #ffffff,#262626, 2-61 #949494,#121212, 62-74 d,#121212, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-== snap keep-primary grid=150x30 cursor=8,4
-== style keep-primary grid=150x30
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-14 #bdbdbd,#080808, 15-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-14 #bdbdbd,#080808, 15-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
+== style three-cursors grid=150x31
+|0: 0-70 #b2c3b8,#1d2824, 71-149 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-74 d,#26362d, 75-99 #b2c3b8,#1d2824, 100-149 d,#1d2824,
+|2: 0-1 #ffffff,#4c6356, 2-74 #b2c3b8,#1d2824, 75-76 #ffffff,#4c6356, 77-149 #b2c3b8,#1d2824,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|5: 0-0 d,#637f6a, 1-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|6: 0-1 #000000,#adcc91, 2-61 #becfc4,#26362d, 62-74 d,#26362d, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-7 #405d4b,#f5f7ee, 8-12 #e5eee5,#0d1410, 13-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-7 #405d4b,#f5f7ee, 8-12 #e5eee5,#0d1410, 13-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-12 #e5eee5,#0d1410, 13-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|14: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|15: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|16: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|17: 0-1 #ffffff,#4c6356, 2-74 #b2c3b8,#1d2824, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|20: 0-0 d,#637f6a, 1-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+== snap edited-at-three grid=150x31 cursor=9,9
+|6: /tmp/pardes-snap/multicursor/cwd/f.txt * Save Tty Del Collapse
+|7: 1 >>line 1
+|8: 2 >>line 2
+|9: 3 >>line 3
+== snap three-selections grid=150x31 cursor=8,9
+== style three-selections grid=150x31
+|6: 0-1 #000000,#adcc91, 2-63 #becfc4,#26362d, 64-74 d,#26362d, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-7 #f5f7ee,#26382d, 8-8 #405d4b,#f5f7ee, 9-14 #e5eee5,#0d1410, 15-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-7 #f5f7ee,#26382d, 8-8 #405d4b,#f5f7ee, 9-14 #e5eee5,#0d1410, 15-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-8 #f5f7ee,#405d4b, 9-14 #e5eee5,#0d1410, 15-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+== snap keep-primary grid=150x31 cursor=8,9
+== style keep-primary grid=150x31
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-14 #e5eee5,#0d1410, 15-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-14 #e5eee5,#0d1410, 15-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
diff --git a/test/snapshots/multicursor.snap b/test/snapshots/multicursor.snap
index 2bfccb93..ebd97ec5 100644
--- a/test/snapshots/multicursor.snap
+++ b/test/snapshots/multicursor.snap
@@ -3,19 +3,19 @@
# see: that every range is actually on screen, that the primary reads
# differently from the others, and that ONE keystroke edits at all of them.
lines f.txt 12
-start 30 150 -n 3
+start 31 150 -n 3
wait 8000 f.txt
stable 700 20000
# open f.txt in the left pane (type its name, right-click to Look)
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key i
text f.txt
key esc
settle 100
-press right 6 8
-release right 6 8
+press right 6 9
+release right 6 9
wait 10000 line 3
stable 700 15000
# top of the file, then C C: three cursors, one per line, primary on line 3
diff --git a/test/snapshots/nested-optout.golden b/test/snapshots/nested-optout.golden
index fbb7ef0e..5d3fb8a7 100644
--- a/test/snapshots/nested-optout.golden
+++ b/test/snapshots/nested-optout.golden
@@ -1,19 +1,24 @@
-== snap optout-file grid=100x30 cursor=9,4
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|$ /tmp/pardes-snap/nested-optout/cwd Save New Newtty Del Filter
-| New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/nested-optout/cwd/nested.txt Save New Newtty Del
+== snap optout-file grid=100x31 cursor=9,6
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+|$ /tmp/pardes-snap/nested-optout/cwd Save Tty Del Togglettymode Filter Collapse
+| Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| New Tty Find Grep Joincol
+| /tmp/pardes-snap/nested-optout/cwd/nested.txt Save Tty Del Collapse
| 1 optout-marker
| 2 second-optout-line
| 3
-== snap inner-shell grid=100x30 cursor=6,4
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|$ /tmp/pardes-snap/nested-optout/cwd Save New Newtty Del Filter
-| New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| $ /tmp/pardes-snap/nested-optout/cwd/innerdir Save New Newtty Del Filter
+== snap inner-shell grid=100x31 cursor=6,6
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+|$ /tmp/pardes-snap/nested-optout/cwd Save Tty Del Togglettymode Filter Collapse
+| Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| New Tty Find Grep Joincol
+| $ /tmp/pardes-snap/nested-optout/cwd/innerdir Save Tty Del Togglettymode Filter Collapse
| $
-== snap inner-launch grid=100x30 cursor=11,6
-|4: New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|5: /tmp/pardes-snap/nested-optout/cwd/innerdir/deeper.txt Save New Newtty Del
-|6: 1 deepest-marker
-|7: 2
+== snap inner-launch grid=100x31 cursor=11,9
+|6: Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|7: New Tty Find Grep Joincol
+|8: /tmp/pardes-snap/nested-optout/cwd/innerdir/deeper.txt Save Tty Del Collapse
+|9: 1 deepest-marker
+|10: 2
diff --git a/test/snapshots/nested-optout.snap b/test/snapshots/nested-optout.snap
index 973b8817..45cedab9 100644
--- a/test/snapshots/nested-optout.snap
+++ b/test/snapshots/nested-optout.snap
@@ -1,7 +1,7 @@
file nested.txt optout-marker\nsecond-optout-line\n
dirmk innerdir
file innerdir/deeper.txt deepest-marker\n
-start 30 100
+start 31 100
wait 8000 $
stable 700 20000
text $(readlink /proc/$PPID/exe) --nested nested.txt
@@ -9,7 +9,7 @@ key enter
wait 20000 optout-marker
stable 700 20000
snap optout-file
-start 30 100
+start 31 100
wait 8000 $
stable 700 20000
text (cd innerdir && $(readlink /proc/$PPID/exe) --nested)
diff --git a/test/snapshots/nested.golden b/test/snapshots/nested.golden
index 6d0d0bf9..68d0a69b 100644
--- a/test/snapshots/nested.golden
+++ b/test/snapshots/nested.golden
@@ -1,35 +1,28 @@
-== snap file-arg grid=100x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/nested/cwd/nested.txt Save New Newtty Del
+== snap file-arg grid=100x31 cursor=7,6
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+|$ /tmp/pardes-snap/nested/cwd Save Tty Del Togglettymode Filter Collapse
+| $ $(readlink /proc/$PPID/exe) nested.txt
+| $
+| /tmp/pardes-snap/nested/cwd/nested.txt Save Tty Del Collapse
| 1 hello-from-nested
| 2 second-nested-line
| 3
-|
-|
-|
-|
-|
-|
-|
-|
-|
-|
-|$ /tmp/pardes-snap/nested/cwd Save New Newtty Del Filter
-| $ $(readlink /proc/$PPID/exe) nested.txt
-| $
-== snap no-arg grid=100x30 cursor=4,6
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|$ /tmp/pardes-snap/nested/cwd Save New Newtty Del Filter
+== snap no-arg grid=100x31 cursor=4,7
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+|$ /tmp/pardes-snap/nested/cwd Save Tty Del Togglettymode Filter Collapse
| $ $(readlink /proc/$PPID/exe)
| pardes: this shell is already inside pardes, and a pardes inside a pardes
| is spicy. Name a file or a directory and the outer session opens it, or
| pass --nested if you really want a second one in here.
| $
-== snap dir-arg grid=100x30 cursor=4,7
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|$ /tmp/pardes-snap/nested/cwd Save New Newtty Del Filter
+== snap dir-arg grid=100x31 cursor=4,8
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+|$ /tmp/pardes-snap/nested/cwd Save Tty Del Togglettymode Filter Collapse
| $ $(readlink /proc/$PPID/exe) nestdir
| $
-| /tmp/pardes-snap/nested/cwd/nestdir Save New Newtty Del Filter
+| /tmp/pardes-snap/nested/cwd/nestdir Save Tty Del Togglettymode Filter Collapse
| ls
| inside-nested.txt
diff --git a/test/snapshots/nested.snap b/test/snapshots/nested.snap
index 790b9b0c..c26b7cea 100644
--- a/test/snapshots/nested.snap
+++ b/test/snapshots/nested.snap
@@ -1,7 +1,7 @@
dirmk nestdir
file nestdir/inside-nested.txt marker
file nested.txt hello-from-nested\nsecond-nested-line\n
-start 30 100
+start 31 100
wait 8000 $
stable 700 20000
text $(readlink /proc/$PPID/exe) nested.txt
@@ -9,7 +9,7 @@ key enter
wait 15000 hello-from-nested
stable 700 20000
snap file-arg
-start 30 100
+start 31 100
wait 8000 $
stable 700 20000
text $(readlink /proc/$PPID/exe)
@@ -17,7 +17,7 @@ key enter
wait 15000 already inside pardes
stable 700 20000
snap no-arg
-start 30 100
+start 31 100
wait 8000 $
stable 700 20000
text $(readlink /proc/$PPID/exe) nestdir
diff --git a/test/snapshots/ninep.golden b/test/snapshots/ninep.golden
index c0e90e3f..94ad4bcf 100644
--- a/test/snapshots/ninep.golden
+++ b/test/snapshots/ninep.golden
@@ -1,6 +1,7 @@
-== snap opened grid=90x14 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/ninep/cwd/demo.zig Save New Newtty Del
+== snap opened grid=90x15 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/ninep/cwd/demo.zig Save Tty Del Collapse
| 1 const greeting = "café λ 界 é";
| 2
| 3 pub fn choose(ok: bool) u32 {
@@ -8,182 +9,190 @@
| 5 return 7;
| 6 }
| 7
-== style opened grid=90x14
-|0: 0-74 #949494,#121212, 75-89 d,#121212,
-|1: 0-1 #ffffff,#626262, 2-69 #949494,#121212, 70-89 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-23 #bdbdbd,#080808, 24-32 #e3c78a,#080808, 33-33 d,d, 34-36 #e3c78a,#080808, 37-37 #bdbdbd,#080808, 38-89 d,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-12 #cf87e8,#080808,b 13-35 #bdbdbd,#080808, 36-89 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-12 #cf87e8,#080808,b 13-18 #bdbdbd,#080808, 19-24 #cf87e8,#080808,b 25-25 #bdbdbd,#080808, 26-27 #e3c78a,#080808, 28-28 #bdbdbd,#080808, 29-89 d,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-16 #cf87e8,#080808,b 17-17 #bdbdbd,#080808, 18-18 #e3c78a,#080808, 19-19 #bdbdbd,#080808, 20-89 d,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-7 #bdbdbd,#080808, 8-89 d,#080808,
-|8: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-|11: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-== 9p opened grid=90x14 cursor=7,2,block
-|0: New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-@0: 0-74 #949494,#121212,,tagline 75-89 d,#121212,,tagline
-|1: /tmp/pardes-snap/ninep/cwd/demo.zig Save New Newtty Del
-@1: 0-1 #ffffff,#626262,,tagline 2-69 #949494,#121212,,tagline 70-89 d,#121212,,tagline
-|2: 1 const greeting = "café λ 界 é";
-+2: 28="é" 30="λ" 32="界" 33="" 35="é"
-@2: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #949494,#121212,,body 7-23 #bdbdbd,#080808,,body 24-36 #e3c78a,#080808,,body 37-37 #bdbdbd,#080808,,body 38-89 d,#080808,,body
-|3: 2
-@3: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
-|4: 3 pub fn choose(ok: bool) u32 {
-@4: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-10 #bdbdbd,#080808,,body 11-12 #cf87e8,#080808,b,body 13-35 #bdbdbd,#080808,,body 36-89 d,#080808,,body
-|5: 4 if (ok) return 42;
-@5: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-10 #bdbdbd,#080808,,body 11-12 #cf87e8,#080808,b,body 13-18 #bdbdbd,#080808,,body 19-24 #cf87e8,#080808,b,body 25-25 #bdbdbd,#080808,,body 26-27 #e3c78a,#080808,,body 28-28 #bdbdbd,#080808,,body 29-89 d,#080808,,body
-|6: 5 return 7;
-@6: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-10 #bdbdbd,#080808,,body 11-16 #cf87e8,#080808,b,body 17-17 #bdbdbd,#080808,,body 18-18 #e3c78a,#080808,,body 19-19 #bdbdbd,#080808,,body 20-89 d,#080808,,body
-|7: 6 }
-@7: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-7 #bdbdbd,#080808,,body 8-89 d,#080808,,body
-|8: 7
-@8: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
-|9:
-@9: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
+== style opened grid=90x15
+|0: 0-70 #b2c3b8,#1d2824, 71-89 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-89 d,#26362d,
+|2: 0-1 #000000,#adcc91, 2-58 #becfc4,#26362d, 59-89 d,#26362d,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-23 #e5eee5,#0d1410, 24-32 #b6ce94,#0d1410, 33-33 d,d, 34-36 #b6ce94,#0d1410, 37-37 #e5eee5,#0d1410, 38-89 d,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-12 #c9b0e4,#0d1410, 13-35 #e5eee5,#0d1410, 36-89 d,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-12 #c9b0e4,#0d1410, 13-18 #e5eee5,#0d1410, 19-24 #c9b0e4,#0d1410, 25-25 #e5eee5,#0d1410, 26-27 #e9bf91,#0d1410, 28-28 #e5eee5,#0d1410, 29-89 d,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-16 #c9b0e4,#0d1410, 17-17 #e5eee5,#0d1410, 18-18 #e9bf91,#0d1410, 19-19 #e5eee5,#0d1410, 20-89 d,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-7 #e5eee5,#0d1410, 8-89 d,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+== 9p opened grid=90x15 cursor=7,3,block
+|0: Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+@0: 0-70 #b2c3b8,#1d2824,,tagline 71-89 d,#1d2824,,tagline
+|1: New Tty Find Grep Joincol
+@1: 0-24 #becfc4,#26362d,,tagline 25-89 d,#26362d,,tagline
+|2: /tmp/pardes-snap/ninep/cwd/demo.zig Save Tty Del Collapse
+@2: 0-1 #000000,#adcc91,,tagline 2-58 #becfc4,#26362d,,tagline 59-89 d,#26362d,,tagline
+|3: 1 const greeting = "café λ 界 é";
++3: 28="é" 30="λ" 32="界" 33="" 35="é"
+@3: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #616f64,#0d1410,b,body 7-23 #e5eee5,#0d1410,,body 24-36 #b6ce94,#0d1410,,body 37-37 #e5eee5,#0d1410,,body 38-89 d,#0d1410,,body
+|4: 2
+@4: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
+|5: 3 pub fn choose(ok: bool) u32 {
+@5: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-10 #e5eee5,#0d1410,,body 11-12 #c9b0e4,#0d1410,,body 13-35 #e5eee5,#0d1410,,body 36-89 d,#0d1410,,body
+|6: 4 if (ok) return 42;
+@6: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-10 #e5eee5,#0d1410,,body 11-12 #c9b0e4,#0d1410,,body 13-18 #e5eee5,#0d1410,,body 19-24 #c9b0e4,#0d1410,,body 25-25 #e5eee5,#0d1410,,body 26-27 #e9bf91,#0d1410,,body 28-28 #e5eee5,#0d1410,,body 29-89 d,#0d1410,,body
+|7: 5 return 7;
+@7: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-10 #e5eee5,#0d1410,,body 11-16 #c9b0e4,#0d1410,,body 17-17 #e5eee5,#0d1410,,body 18-18 #e9bf91,#0d1410,,body 19-19 #e5eee5,#0d1410,,body 20-89 d,#0d1410,,body
+|8: 6 }
+@8: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-7 #e5eee5,#0d1410,,body 8-89 d,#0d1410,,body
+|9: 7
+@9: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
|10:
-@10: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
+@10: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
|11:
-@11: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
+@11: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
|12:
-@12: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
+@12: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
|13:
-@13: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
-== style colors-off grid=90x14
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-32 #bdbdbd,#080808, 33-33 d,d, 34-37 #bdbdbd,#080808, 38-89 d,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-35 #bdbdbd,#080808, 36-89 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-28 #bdbdbd,#080808, 29-89 d,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-19 #bdbdbd,#080808, 20-89 d,#080808,
-== 9p colors-off grid=90x14 cursor=7,2,block
-|2: 1 const greeting = "café λ 界 é";
-+2: 28="é" 30="λ" 32="界" 33="" 35="é"
-@2: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #949494,#121212,,body 7-37 #bdbdbd,#080808,,body 38-89 d,#080808,,body
-|4: 3 pub fn choose(ok: bool) u32 {
-@4: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-35 #bdbdbd,#080808,,body 36-89 d,#080808,,body
-|5: 4 if (ok) return 42;
-@5: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-28 #bdbdbd,#080808,,body 29-89 d,#080808,,body
-|6: 5 return 7;
-@6: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-19 #bdbdbd,#080808,,body 20-89 d,#080808,,body
-== snap edited-with-colors-off grid=90x14 cursor=7,3
-|1: /tmp/pardes-snap/ninep/cwd/demo.zig * Save New Newtty Del
-|2: 1 // café λ 界
-|3: 2 const greeting = "café λ 界 é";
-|4: 3
-|5: 4 pub fn choose(ok: bool) u32 {
-|6: 5 if (ok) return 42;
-|7: 6 return 7;
-|8: 7 }
-|9: 8
-== 9p edited-with-colors-off grid=90x14 cursor=7,3,block
-|1: /tmp/pardes-snap/ninep/cwd/demo.zig * Save New Newtty Del
-@1: 0-1 #ffffff,#626262,,tagline 2-69 #949494,#121212,,tagline 70-89 d,#121212,,tagline
-|2: 1 // café λ 界
-+2: 13="é" 15="λ" 17="界" 18=""
-@2: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-18 #bdbdbd,#080808,,body 19-89 d,#080808,,body
-|3: 2 const greeting = "café λ 界 é";
-+3: 28="é" 30="λ" 32="界" 33="" 35="é"
-@3: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #949494,#121212,,body 7-37 #bdbdbd,#080808,,body 38-89 d,#080808,,body
-|4: 3
-@4: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
-|5: 4 pub fn choose(ok: bool) u32 {
-@5: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-35 #bdbdbd,#080808,,body 36-89 d,#080808,,body
-|6: 5 if (ok) return 42;
-@6: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-28 #bdbdbd,#080808,,body 29-89 d,#080808,,body
-|7: 6 return 7;
-@7: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-19 #bdbdbd,#080808,,body 20-89 d,#080808,,body
-|8: 7 }
-@8: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-7 #bdbdbd,#080808,,body 8-89 d,#080808,,body
-|9: 8
-@9: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-89 d,#080808,,body
-== style colors-on grid=90x14
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-17 #ffffff,#080808,b 18-18 d,d, 19-89 d,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-23 #bdbdbd,#080808, 24-32 #e3c78a,#080808, 33-33 d,d, 34-36 #e3c78a,#080808, 37-37 #bdbdbd,#080808, 38-89 d,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-89 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-12 #cf87e8,#080808,b 13-35 #bdbdbd,#080808, 36-89 d,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-12 #cf87e8,#080808,b 13-18 #bdbdbd,#080808, 19-24 #cf87e8,#080808,b 25-25 #bdbdbd,#080808, 26-27 #e3c78a,#080808, 28-28 #bdbdbd,#080808, 29-89 d,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-16 #cf87e8,#080808,b 17-17 #bdbdbd,#080808, 18-18 #e3c78a,#080808, 19-19 #bdbdbd,#080808, 20-89 d,#080808,
-|8: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-7 #bdbdbd,#080808, 8-89 d,#080808,
-== 9p colors-on grid=90x14 cursor=7,3,block
-|2: 1 // café λ 界
-+2: 13="é" 15="λ" 17="界" 18=""
-@2: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-18 #ffffff,#080808,b,body 19-89 d,#080808,,body
-|3: 2 const greeting = "café λ 界 é";
-+3: 28="é" 30="λ" 32="界" 33="" 35="é"
-@3: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #949494,#121212,,body 7-23 #bdbdbd,#080808,,body 24-36 #e3c78a,#080808,,body 37-37 #bdbdbd,#080808,,body 38-89 d,#080808,,body
-|5: 4 pub fn choose(ok: bool) u32 {
-@5: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-10 #bdbdbd,#080808,,body 11-12 #cf87e8,#080808,b,body 13-35 #bdbdbd,#080808,,body 36-89 d,#080808,,body
-|6: 5 if (ok) return 42;
-@6: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-10 #bdbdbd,#080808,,body 11-12 #cf87e8,#080808,b,body 13-18 #bdbdbd,#080808,,body 19-24 #cf87e8,#080808,b,body 25-25 #bdbdbd,#080808,,body 26-27 #e3c78a,#080808,,body 28-28 #bdbdbd,#080808,,body 29-89 d,#080808,,body
-|7: 6 return 7;
-@7: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-10 #bdbdbd,#080808,,body 11-16 #cf87e8,#080808,b,body 17-17 #bdbdbd,#080808,,body 18-18 #e3c78a,#080808,,body 19-19 #bdbdbd,#080808,,body 20-89 d,#080808,,body
-== style resized grid=105x19
-|0: 0-74 #949494,#121212, 75-104 d,#121212,
-|1: 0-1 #ffffff,#626262, 2-84 #949494,#121212, 85-104 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-17 #ffffff,#080808,b 18-18 d,d, 19-104 d,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-23 #bdbdbd,#080808, 24-32 #e3c78a,#080808, 33-33 d,d, 34-36 #e3c78a,#080808, 37-37 #bdbdbd,#080808, 38-104 d,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-104 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-12 #cf87e8,#080808,b 13-35 #bdbdbd,#080808, 36-104 d,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-12 #cf87e8,#080808,b 13-18 #bdbdbd,#080808, 19-24 #cf87e8,#080808,b 25-25 #bdbdbd,#080808, 26-27 #e3c78a,#080808, 28-28 #bdbdbd,#080808, 29-104 d,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-16 #cf87e8,#080808,b 17-17 #bdbdbd,#080808, 18-18 #e3c78a,#080808, 19-19 #bdbdbd,#080808, 20-104 d,#080808,
-|8: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-7 #bdbdbd,#080808, 8-104 d,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-104 d,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-104 d,#080808,
-|11: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-104 d,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-104 d,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-104 d,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-104 d,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-104 d,#080808,
-|16: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-104 d,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-104 d,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-104 d,#080808,
-== 9p resized grid=105x19 cursor=7,3,block
-|0: New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-@0: 0-74 #949494,#121212,,tagline 75-104 d,#121212,,tagline
-|1: /tmp/pardes-snap/ninep/cwd/demo.zig * Save New Newtty Del
-@1: 0-1 #ffffff,#626262,,tagline 2-84 #949494,#121212,,tagline 85-104 d,#121212,,tagline
-|2: 1 // café λ 界
-+2: 13="é" 15="λ" 17="界" 18=""
-@2: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-18 #ffffff,#080808,b,body 19-104 d,#080808,,body
-|3: 2 const greeting = "café λ 界 é";
+@13: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
+|14:
+@14: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
+== style colors-off grid=90x15
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-32 #e5eee5,#0d1410, 33-33 d,d, 34-37 #e5eee5,#0d1410, 38-89 d,#0d1410,
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-35 #e5eee5,#0d1410, 36-89 d,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-28 #e5eee5,#0d1410, 29-89 d,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-19 #e5eee5,#0d1410, 20-89 d,#0d1410,
+== 9p colors-off grid=90x15 cursor=7,3,block
+|3: 1 const greeting = "café λ 界 é";
+3: 28="é" 30="λ" 32="界" 33="" 35="é"
-@3: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #949494,#121212,,body 7-23 #bdbdbd,#080808,,body 24-36 #e3c78a,#080808,,body 37-37 #bdbdbd,#080808,,body 38-104 d,#080808,,body
-|4: 3
-@4: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
-|5: 4 pub fn choose(ok: bool) u32 {
-@5: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-10 #bdbdbd,#080808,,body 11-12 #cf87e8,#080808,b,body 13-35 #bdbdbd,#080808,,body 36-104 d,#080808,,body
-|6: 5 if (ok) return 42;
-@6: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-10 #bdbdbd,#080808,,body 11-12 #cf87e8,#080808,b,body 13-18 #bdbdbd,#080808,,body 19-24 #cf87e8,#080808,b,body 25-25 #bdbdbd,#080808,,body 26-27 #e3c78a,#080808,,body 28-28 #bdbdbd,#080808,,body 29-104 d,#080808,,body
-|7: 6 return 7;
-@7: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-10 #bdbdbd,#080808,,body 11-16 #cf87e8,#080808,b,body 17-17 #bdbdbd,#080808,,body 18-18 #e3c78a,#080808,,body 19-19 #bdbdbd,#080808,,body 20-104 d,#080808,,body
-|8: 7 }
-@8: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-7 #bdbdbd,#080808,,body 8-104 d,#080808,,body
-|9: 8
-@9: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
-|10:
-@10: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@3: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #616f64,#0d1410,b,body 7-37 #e5eee5,#0d1410,,body 38-89 d,#0d1410,,body
+|5: 3 pub fn choose(ok: bool) u32 {
+@5: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-35 #e5eee5,#0d1410,,body 36-89 d,#0d1410,,body
+|6: 4 if (ok) return 42;
+@6: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-28 #e5eee5,#0d1410,,body 29-89 d,#0d1410,,body
+|7: 5 return 7;
+@7: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-19 #e5eee5,#0d1410,,body 20-89 d,#0d1410,,body
+== snap edited-with-colors-off grid=90x15 cursor=7,4
+|2: /tmp/pardes-snap/ninep/cwd/demo.zig * Save Tty Del Collapse
+|3: 1 // café λ 界
+|4: 2 const greeting = "café λ 界 é";
+|5: 3
+|6: 4 pub fn choose(ok: bool) u32 {
+|7: 5 if (ok) return 42;
+|8: 6 return 7;
+|9: 7 }
+|10: 8
+== 9p edited-with-colors-off grid=90x15 cursor=7,4,block
+|2: /tmp/pardes-snap/ninep/cwd/demo.zig * Save Tty Del Collapse
+@2: 0-1 #000000,#adcc91,,tagline 2-60 #becfc4,#26362d,,tagline 61-89 d,#26362d,,tagline
+|3: 1 // café λ 界
++3: 13="é" 15="λ" 17="界" 18=""
+@3: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-18 #e5eee5,#0d1410,,body 19-89 d,#0d1410,,body
+|4: 2 const greeting = "café λ 界 é";
++4: 28="é" 30="λ" 32="界" 33="" 35="é"
+@4: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #616f64,#0d1410,b,body 7-37 #e5eee5,#0d1410,,body 38-89 d,#0d1410,,body
+|5: 3
+@5: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
+|6: 4 pub fn choose(ok: bool) u32 {
+@6: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-35 #e5eee5,#0d1410,,body 36-89 d,#0d1410,,body
+|7: 5 if (ok) return 42;
+@7: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-28 #e5eee5,#0d1410,,body 29-89 d,#0d1410,,body
+|8: 6 return 7;
+@8: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-19 #e5eee5,#0d1410,,body 20-89 d,#0d1410,,body
+|9: 7 }
+@9: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-7 #e5eee5,#0d1410,,body 8-89 d,#0d1410,,body
+|10: 8
+@10: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-89 d,#0d1410,,body
+== style colors-on grid=90x15
+|2: 0-1 #000000,#adcc91, 2-60 #becfc4,#26362d, 61-89 d,#26362d,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-17 #b9e58f,#0d1410, 18-18 d,d, 19-89 d,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-23 #e5eee5,#0d1410, 24-32 #b6ce94,#0d1410, 33-33 d,d, 34-36 #b6ce94,#0d1410, 37-37 #e5eee5,#0d1410, 38-89 d,#0d1410,
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-89 d,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-12 #c9b0e4,#0d1410, 13-35 #e5eee5,#0d1410, 36-89 d,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-12 #c9b0e4,#0d1410, 13-18 #e5eee5,#0d1410, 19-24 #c9b0e4,#0d1410, 25-25 #e5eee5,#0d1410, 26-27 #e9bf91,#0d1410, 28-28 #e5eee5,#0d1410, 29-89 d,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-16 #c9b0e4,#0d1410, 17-17 #e5eee5,#0d1410, 18-18 #e9bf91,#0d1410, 19-19 #e5eee5,#0d1410, 20-89 d,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-7 #e5eee5,#0d1410, 8-89 d,#0d1410,
+== 9p colors-on grid=90x15 cursor=7,4,block
+|3: 1 // café λ 界
++3: 13="é" 15="λ" 17="界" 18=""
+@3: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-18 #b9e58f,#0d1410,,body 19-89 d,#0d1410,,body
+|4: 2 const greeting = "café λ 界 é";
++4: 28="é" 30="λ" 32="界" 33="" 35="é"
+@4: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #616f64,#0d1410,b,body 7-23 #e5eee5,#0d1410,,body 24-36 #b6ce94,#0d1410,,body 37-37 #e5eee5,#0d1410,,body 38-89 d,#0d1410,,body
+|6: 4 pub fn choose(ok: bool) u32 {
+@6: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-10 #e5eee5,#0d1410,,body 11-12 #c9b0e4,#0d1410,,body 13-35 #e5eee5,#0d1410,,body 36-89 d,#0d1410,,body
+|7: 5 if (ok) return 42;
+@7: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-10 #e5eee5,#0d1410,,body 11-12 #c9b0e4,#0d1410,,body 13-18 #e5eee5,#0d1410,,body 19-24 #c9b0e4,#0d1410,,body 25-25 #e5eee5,#0d1410,,body 26-27 #e9bf91,#0d1410,,body 28-28 #e5eee5,#0d1410,,body 29-89 d,#0d1410,,body
+|8: 6 return 7;
+@8: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-10 #e5eee5,#0d1410,,body 11-16 #c9b0e4,#0d1410,,body 17-17 #e5eee5,#0d1410,,body 18-18 #e9bf91,#0d1410,,body 19-19 #e5eee5,#0d1410,,body 20-89 d,#0d1410,,body
+== style resized grid=105x20
+|0: 0-70 #b2c3b8,#1d2824, 71-104 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-104 d,#26362d,
+|2: 0-1 #000000,#adcc91, 2-60 #becfc4,#26362d, 61-104 d,#26362d,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-17 #b9e58f,#0d1410, 18-18 d,d, 19-104 d,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-23 #e5eee5,#0d1410, 24-32 #b6ce94,#0d1410, 33-33 d,d, 34-36 #b6ce94,#0d1410, 37-37 #e5eee5,#0d1410, 38-104 d,#0d1410,
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-104 d,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-12 #c9b0e4,#0d1410, 13-35 #e5eee5,#0d1410, 36-104 d,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-12 #c9b0e4,#0d1410, 13-18 #e5eee5,#0d1410, 19-24 #c9b0e4,#0d1410, 25-25 #e5eee5,#0d1410, 26-27 #e9bf91,#0d1410, 28-28 #e5eee5,#0d1410, 29-104 d,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-16 #c9b0e4,#0d1410, 17-17 #e5eee5,#0d1410, 18-18 #e9bf91,#0d1410, 19-19 #e5eee5,#0d1410, 20-104 d,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-7 #e5eee5,#0d1410, 8-104 d,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-104 d,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-104 d,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-104 d,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-104 d,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-104 d,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-104 d,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-104 d,#0d1410,
+|17: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-104 d,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-104 d,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-104 d,#0d1410,
+== 9p resized grid=105x20 cursor=7,4,block
+|0: Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+@0: 0-70 #b2c3b8,#1d2824,,tagline 71-104 d,#1d2824,,tagline
+|1: New Tty Find Grep Joincol
+@1: 0-24 #becfc4,#26362d,,tagline 25-104 d,#26362d,,tagline
+|2: /tmp/pardes-snap/ninep/cwd/demo.zig * Save Tty Del Collapse
+@2: 0-1 #000000,#adcc91,,tagline 2-60 #becfc4,#26362d,,tagline 61-104 d,#26362d,,tagline
+|3: 1 // café λ 界
++3: 13="é" 15="λ" 17="界" 18=""
+@3: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-18 #b9e58f,#0d1410,,body 19-104 d,#0d1410,,body
+|4: 2 const greeting = "café λ 界 é";
++4: 28="é" 30="λ" 32="界" 33="" 35="é"
+@4: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #616f64,#0d1410,b,body 7-23 #e5eee5,#0d1410,,body 24-36 #b6ce94,#0d1410,,body 37-37 #e5eee5,#0d1410,,body 38-104 d,#0d1410,,body
+|5: 3
+@5: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
+|6: 4 pub fn choose(ok: bool) u32 {
+@6: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-10 #e5eee5,#0d1410,,body 11-12 #c9b0e4,#0d1410,,body 13-35 #e5eee5,#0d1410,,body 36-104 d,#0d1410,,body
+|7: 5 if (ok) return 42;
+@7: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-10 #e5eee5,#0d1410,,body 11-12 #c9b0e4,#0d1410,,body 13-18 #e5eee5,#0d1410,,body 19-24 #c9b0e4,#0d1410,,body 25-25 #e5eee5,#0d1410,,body 26-27 #e9bf91,#0d1410,,body 28-28 #e5eee5,#0d1410,,body 29-104 d,#0d1410,,body
+|8: 6 return 7;
+@8: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-10 #e5eee5,#0d1410,,body 11-16 #c9b0e4,#0d1410,,body 17-17 #e5eee5,#0d1410,,body 18-18 #e9bf91,#0d1410,,body 19-19 #e5eee5,#0d1410,,body 20-104 d,#0d1410,,body
+|9: 7 }
+@9: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-7 #e5eee5,#0d1410,,body 8-104 d,#0d1410,,body
+|10: 8
+@10: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|11:
-@11: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@11: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|12:
-@12: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@12: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|13:
-@13: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@13: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|14:
-@14: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@14: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|15:
-@15: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@15: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|16:
-@16: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@16: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|17:
-@17: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
+@17: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
|18:
-@18: 0-0 d,#444444,,body 1-1 d,#080808,,body 2-6 #626262,#080808,,body 7-104 d,#080808,,body
-== snap resized grid=105x19 cursor=7,3
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/ninep/cwd/demo.zig * Save New Newtty Del
+@18: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
+|19:
+@19: 0-0 d,#637f6a,,body 1-1 d,#0d1410,,body 2-6 #59675c,#0d1410,,body 7-104 d,#0d1410,,body
+== snap resized grid=105x20 cursor=7,4
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/ninep/cwd/demo.zig * Save Tty Del Collapse
| 1 // café λ 界
| 2 const greeting = "café λ 界 é";
| 3
@@ -192,4 +201,4 @@
| 6 return 7;
| 7 }
| 8
-== 9p unchanged grid=105x19 cursor=7,3,block
+== 9p unchanged grid=105x20 cursor=7,4,block
diff --git a/test/snapshots/ninep.snap b/test/snapshots/ninep.snap
index 5c9da02a..9299058f 100644
--- a/test/snapshots/ninep.snap
+++ b/test/snapshots/ninep.snap
@@ -1,5 +1,5 @@
file demo.zig const greeting = "café λ 界 é";\n\npub fn choose(ok: bool) u32 {\n if (ok) return 42;\n return 7;\n}\n
-start 14 90 demo.zig
+start 15 90 demo.zig
wait 8000 choose
stable 400 10000
snap opened
@@ -20,7 +20,7 @@ key space t c
stable 300 8000
snapstyle colors-on
snap9p colors-on
-resize 19 105
+resize 20 105
stable 400 10000
snapstyle resized
snap9p resized
diff --git a/test/snapshots/pipe.golden b/test/snapshots/pipe.golden
index 8772f81e..e6d558a6 100644
--- a/test/snapshots/pipe.golden
+++ b/test/snapshots/pipe.golden
@@ -1,6 +1,7 @@
-== snap prompt grid=180x12 cursor=14,11
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/pipe/cwd/pipe.txt Save New Newtty Del
+== snap prompt grid=180x13 cursor=14,12
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/pipe/cwd/pipe.txt Save Tty Del Collapse
| 1 alpha beta
| 2 gamma delta
|
@@ -11,9 +12,9 @@
|
|
| |tr a-z A-Z
-== snap filtered grid=180x12 cursor=17,2
-|1: /tmp/pardes-snap/pipe/cwd/pipe.txt * Save New Newtty Del
-|2: 1 ALPHA BETA
-|11:
-== snap undone grid=180x12 cursor=17,2
-|2: 1 alpha beta
+== snap filtered grid=180x13 cursor=17,3
+|2: /tmp/pardes-snap/pipe/cwd/pipe.txt * Save Tty Del Collapse
+|3: 1 ALPHA BETA
+|12:
+== snap undone grid=180x13 cursor=17,3
+|3: 1 alpha beta
diff --git a/test/snapshots/pipe.snap b/test/snapshots/pipe.snap
index 421f9177..0df76864 100644
--- a/test/snapshots/pipe.snap
+++ b/test/snapshots/pipe.snap
@@ -1,6 +1,6 @@
# `|`: visible tag prompt, native async shell filter, and one-step undo.
file pipe.txt alpha beta\ngamma delta
-start 12 180 pipe.txt
+start 13 180 pipe.txt
wait 8000 alpha beta
stable 700 20000
key x |
diff --git a/test/snapshots/psearch.golden b/test/snapshots/psearch.golden
index 8dfcd2b3..d1a28996 100644
--- a/test/snapshots/psearch.golden
+++ b/test/snapshots/psearch.golden
@@ -1,60 +1,62 @@
-== snap output grid=140x30 cursor=4,8
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/psearch/cwd Save New Newtty Del Filter
+== snap output grid=140x31 cursor=4,9
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/psearch/cwd Save Tty Del Togglettymode Filter Collapse
| 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
-== snap typing grid=140x30 cursor=8,29
-|29: /MARK
-== snap results grid=140x30 cursor=7,3
-|26: /tmp/pardes-snap/psearch/cwd/+Search Save New Newtty Del
-|27: 1 @p0:2:3-6 x MARK a
-|28: 2 @p0:4:3-6 x MARK b
-|29: 3 @p0:6:3-6 x MARK c
-== style results grid=140x30
-|0: 0-74 #949494,#121212, 75-139 d,#121212,
-|1: 0-1 #ffffff,#626262, 2-119 #949494,#121212, 120-139 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-139 #bdbdbd,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-3 #bdbdbd,#080808, 4-7 #080808,#80a0ff, 8-139 #bdbdbd,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-139 #bdbdbd,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-139 #bdbdbd,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-139 #bdbdbd,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-139 #bdbdbd,#080808,
-|8: 0-0 d,#444444, 1-139 d,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-139 #bdbdbd,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-139 #bdbdbd,#080808,
-|11: 0-0 d,#444444, 1-1 d,#080808, 2-139 #bdbdbd,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-139 #bdbdbd,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-139 #bdbdbd,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-139 #bdbdbd,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-139 #bdbdbd,#080808,
-|16: 0-0 d,#444444, 1-1 d,#080808, 2-139 #bdbdbd,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-139 #bdbdbd,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-139 #bdbdbd,#080808,
-|19: 0-0 d,#444444, 1-1 d,#080808, 2-139 #bdbdbd,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-139 #bdbdbd,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-139 #bdbdbd,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-139 #bdbdbd,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-139 #bdbdbd,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-139 #bdbdbd,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-139 #bdbdbd,#080808,
-|26: 0-1 #ffffff,#262626, 2-119 #949494,#121212, 120-139 d,#121212,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-24 #bdbdbd,#080808, 25-139 d,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-24 #bdbdbd,#080808, 25-139 d,#080808,
-|29: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-24 #bdbdbd,#080808, 25-139 d,#080808,
-== snap second grid=140x30 cursor=7,5
-== snap back grid=140x30 cursor=7,3
-== snap nomatch grid=140x30 cursor=7,28
-|24: /tmp/pardes-snap/psearch/cwd/+Search Save New Newtty Del
-|25: 1
-== snap ttyinert grid=140x30 cursor=4,8
-|1: $ /tmp/pardes-snap/psearch/cwd Save New Newtty Del Filter
-|2: $ printf 'x MA''RK a\nzz\nx MA''RK b\nzz\nx MA''RK c\n'
-|8: $
-== snap rightsearch grid=140x30 cursor=7,5
-|1: /tmp/pardes-snap/psearch/cwd Save New Newtty Del Filter
-|2: printf 'x MA''RK a\nzz\nx MA''RK b\nzz\nx MA''RK c\n'
-|8:
+== snap typing grid=140x31 cursor=8,30
+|30: /MARK
+== snap results grid=140x31 cursor=7,4
+|27: /tmp/pardes-snap/psearch/cwd/+Search Save Tty Del Collapse
+|28: 1 @p0:2:3-6 x MARK a
+|29: 2 @p0:4:3-6 x MARK b
+|30: 3 @p0:6:3-6 x MARK c
+== style results grid=140x31
+|0: 0-70 #b2c3b8,#1d2824, 71-139 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-139 d,#26362d,
+|2: 0-1 #000000,#adcc91, 2-72 #becfc4,#26362d, 73-139 d,#26362d,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-139 #e5eee5,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-3 #e5eee5,#0d1410, 4-7 #f5f7ee,#405d4b, 8-139 #e5eee5,#0d1410,
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-139 #e5eee5,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-139 #e5eee5,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-139 #e5eee5,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-139 #e5eee5,#0d1410,
+|9: 0-0 d,#637f6a, 1-139 d,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-139 #e5eee5,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-139 #e5eee5,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-139 #e5eee5,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-139 #e5eee5,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-139 #e5eee5,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-139 #e5eee5,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-139 #e5eee5,#0d1410,
+|17: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-139 #e5eee5,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-139 #e5eee5,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-139 #e5eee5,#0d1410,
+|20: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-139 #e5eee5,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-139 #e5eee5,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-139 #e5eee5,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-139 #e5eee5,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-139 #e5eee5,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-139 #e5eee5,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-139 #e5eee5,#0d1410,
+|27: 0-1 #ffffff,#4c6356, 2-59 #b2c3b8,#1d2824, 60-139 d,#1d2824,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-15 #59675c,#0d1410, 16-18 #e5eee5,#0d1410, 19-22 #f7e4a5,#57472a, 23-24 #e5eee5,#0d1410, 25-139 d,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-15 #59675c,#0d1410, 16-18 #e5eee5,#0d1410, 19-22 #f7e4a5,#57472a, 23-24 #e5eee5,#0d1410, 25-139 d,#0d1410,
+|30: 0-0 d,#152019, 1-1 d,#0d1410, 2-15 #59675c,#0d1410, 16-18 #e5eee5,#0d1410, 19-22 #f7e4a5,#57472a, 23-24 #e5eee5,#0d1410, 25-139 d,#0d1410,
+== snap second grid=140x31 cursor=7,6
+== snap back grid=140x31 cursor=7,4
+== snap nomatch grid=140x31 cursor=7,29
+|25: /tmp/pardes-snap/psearch/cwd/+Search Save Tty Del Collapse
+|26: 1
+== snap ttyinert grid=140x31 cursor=4,9
+|2: $ /tmp/pardes-snap/psearch/cwd Save Tty Del Togglettymode Filter Collapse
+|3: $ printf 'x MA''RK a\nzz\nx MA''RK b\nzz\nx MA''RK c\n'
+|9: $
+== snap rightsearch grid=140x31 cursor=7,6
+|2: /tmp/pardes-snap/psearch/cwd Save Tty Del Togglettymode Filter Collapse
+|3: printf 'x MA''RK a\nzz\nx MA''RK b\nzz\nx MA''RK c\n'
+|9:
diff --git a/test/snapshots/psearch.snap b/test/snapshots/psearch.snap
index beceb806..a46e2b9d 100644
--- a/test/snapshots/psearch.snap
+++ b/test/snapshots/psearch.snap
@@ -12,8 +12,8 @@
# It splits BELOW the shell it came from: every snap below stays ONE column,
# the shell's tag and the +Search tag both starting at x=0, thirty rows split
# between them, and nothing shifts sideways.
-start 30 140
-wait 8000 New Newcol
+start 31 140
+wait 8000 Newcol Joincol
stable 700 20000
# print something to search (a bare boot starts in tty mode; the marker is
# split so the echoed command line, which normal mode hides anyway, can never
@@ -69,20 +69,20 @@ snap nomatch
# The left click first is the price of the step above: it left the cursor in
# the results buffer, and c-b is read by the ACTIVE pane — there is no tty
# behind a +Search to toggle.
-press left 5 4
-release left 5 4
+press left 5 5
+release left 5 5
stable 400 5000
key c-b
stable 600 8000
-press right 5 4
-release right 5 4
+press right 5 5
+release right 5 5
stable 700 10000
snap ttyinert
# back in normal mode the same click searches for MARK
key c-b
stable 600 8000
-press right 5 4
-release right 5 4
+press right 5 5
+release right 5 5
wait 10000 @p0:2:3
stable 700 15000
snap rightsearch
diff --git a/test/snapshots/reflow.golden b/test/snapshots/reflow.golden
index fd96e68f..3c2f5ff4 100644
--- a/test/snapshots/reflow.golden
+++ b/test/snapshots/reflow.golden
@@ -1,6 +1,7 @@
-== snap widened grid=200x24 cursor=4,19
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|$ /tmp/pardes-snap/reflow/cwd Save New Newtty Del Filter
+== snap widened grid=200x25 cursor=4,20
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+|$ /tmp/pardes-snap/reflow/cwd Save Tty Del Togglettymode Filter Collapse
| $ printf 'y%.0s' $(seq 1 3000); echo do''ne
| yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
| yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
diff --git a/test/snapshots/reflow.snap b/test/snapshots/reflow.snap
index 931fe9d4..7aac1e8c 100644
--- a/test/snapshots/reflow.snap
+++ b/test/snapshots/reflow.snap
@@ -4,7 +4,7 @@
# integrity check panicked the whole app ("ViewportPinInsufficientRows").
# build.zig now pins the ghostty dependency at ReleaseSafe so those
# development-only checks are off — the app's own safety checks are unchanged.
-start 24 40
+start 25 40
wait 8000 $
text printf 'y%.0s' $(seq 1 3000); echo do''ne
key enter
@@ -15,6 +15,6 @@ wheel up 10 10
wheel up 10 10
wheel up 10 10
stable 500 8000
-resize 24 200
+resize 25 200
stable 700 15000
snap widened
diff --git a/test/snapshots/respawn.golden b/test/snapshots/respawn.golden
index f97a0233..9aa6b46b 100644
--- a/test/snapshots/respawn.golden
+++ b/test/snapshots/respawn.golden
@@ -1,9 +1,10 @@
-== snap respawn grid=100x30 cursor=4,8
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/respawn/cwd Save New Newtty Del /tmp/pardes-snap/respawn/cwd Save New Newtty Del
+== snap respawn grid=100x31 cursor=4,9
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/respawn/cwd Save Tty Del Toggle /tmp/pardes-snap/respawn/cwd Save Tty Del Toggle
| ls ls
|
-|$ /tmp/pardes-snap/respawn/cwd Save New Newtty Del
+|$ /tmp/pardes-snap/respawn/cwd Save Tty Del Toggle
| $ ls
| $ echo RESP''AWNOK
| RESPAWNOK
diff --git a/test/snapshots/respawn.snap b/test/snapshots/respawn.snap
index 8fcd751c..66393da9 100644
--- a/test/snapshots/respawn.snap
+++ b/test/snapshots/respawn.snap
@@ -1,13 +1,13 @@
# a deleted shell pane's pty lingers in its slot (there is no close effect);
# a later spawn reusing the pane id must reap it instead of tripping the
# drainEffects spawn assert — this exact sequence crashed pre-fix
-start 30 100 -n 3
-wait 8000 New Newcol
+start 31 100 -n 3
+wait 8000 Newcol Joincol
stable 700 20000
# middle-click Del on the lower-left pane's tag: the pane id is freed while
# its shell process stays alive in the slot
-press middle @Del 17
-release middle @Del 17
+press middle @Del 18
+release middle @Del 18
stable 700 10000
# Alt-n reuses the freed id -> spawn effect lands on the occupied slot
key a-n
diff --git a/test/snapshots/restore.golden b/test/snapshots/restore.golden
index c1494983..d2a60c4a 100644
--- a/test/snapshots/restore.golden
+++ b/test/snapshots/restore.golden
@@ -1,13 +1,14 @@
-== snap dumped grid=100x30 cursor=4,5
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill Restore /tmp/pardes-snap
-|$ /tmp/pardes-snap/restore/cwd Save New Newtty Del Filter
+== snap dumped grid=100x31 cursor=4,6
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill Restore /tmp/pardes-snap/res
+|New Tty Find Grep Joincol
+|$ /tmp/pardes-snap/restore/cwd Save Tty Del Togglettymode Filter Collapse
| $ ls
| $ echo KEEP''ME
| KEEPME
| $
-== snap restored grid=100x30 cursor=4,5
-|0: New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|1: /tmp/pardes-snap/restore/cwd Save New Newtty Del Filter
-|2: ls
-|3: echo KEEP''ME
-|5:
+== snap restored grid=100x31 cursor=4,6
+|0: Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|2: /tmp/pardes-snap/restore/cwd Save Tty Del Togglettymode Filter Collapse
+|3: ls
+|4: echo KEEP''ME
+|6:
diff --git a/test/snapshots/restore.snap b/test/snapshots/restore.snap
index c29eeb5e..73f5c8ec 100644
--- a/test/snapshots/restore.snap
+++ b/test/snapshots/restore.snap
@@ -2,8 +2,8 @@
# under ~/.local/share/pardes in live runs) and the topbar grows Restore <path>;
# middle-click Restore loads that dump back into the live session: output on
# screen at Dump time survives (pty history), later output does not
-start 30 100 -n 1
-wait 8000 New Newcol
+start 31 100 -n 1
+wait 8000 Newcol Joincol
stable 700 20000
key c-b
stable 600 8000
diff --git a/test/snapshots/rsearch.golden b/test/snapshots/rsearch.golden
index b076ad0d..f0bc0594 100644
--- a/test/snapshots/rsearch.golden
+++ b/test/snapshots/rsearch.golden
@@ -1,31 +1,32 @@
-== snap opened grid=210x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/rsearch/cwd/code.txt Save New Newtty Del /tmp/pardes-snap/rsearch/cwd Save New Newtty Del Filter
+== snap opened grid=210x31 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/rsearch/cwd/code.txt Save Tty Del Collapse /tmp/pardes-snap/rsearch/cwd Save Tty Del Togglettymode Filter Collapse
| 1 run count_x now ls
| 2 open sub/dep.txt:3 here code.txt sub
| 3 count_x again
| 4 pick two words
|
| code.txt
-== snap search grid=210x30 cursor=13,4
-|27: /tmp/pardes-snap/rsearch/cwd/+Search Save New Newtty Del
-|28: 1 code.txt:1:5-11 run count_x now
-|29: 2 code.txt:3:1-7 count_x again
-== snap select grid=210x30 cursor=14,5
-|25: /tmp/pardes-snap/rsearch/cwd/+Search Save New Newtty Del
-|26: 1 code.txt:4:1-8 pick two words
-== snap path-open grid=210x30 cursor=7,16
-|13: /tmp/pardes-snap/rsearch/cwd/sub/dep.txt Save New Newtty Del
-|14: 1 d1
-|15: 2 d2
-|16: 3 DEPTARGET
-|17: 4 d4
-|18: 5 d5
-|19: 6 d6
-== snap step1 grid=210x30 cursor=13,4
-== snap step2 grid=210x30 cursor=17,2
-== snap step3 grid=210x30 cursor=17,2
-== snap selclick grid=210x30 cursor=14,5
-== snap outside grid=210x30 cursor=20,5
-|11: /tmp/pardes-snap/rsearch/cwd/+Search Save New Newtty Del
-|12: 1 code.txt:4:10-14 pick two words
+== snap search grid=210x31 cursor=13,5
+|28: /tmp/pardes-snap/rsearch/cwd/+Search Save Tty Del Collapse
+|29: 1 code.txt:1:5-11 run count_x now
+|30: 2 code.txt:3:1-7 count_x again
+== snap select grid=210x31 cursor=14,6
+|26: /tmp/pardes-snap/rsearch/cwd/+Search Save Tty Del Collapse
+|27: 1 code.txt:4:1-8 pick two words
+== snap path-open grid=210x31 cursor=7,17
+|14: /tmp/pardes-snap/rsearch/cwd/sub/dep.txt Save Tty Del Collapse
+|15: 1 d1
+|16: 2 d2
+|17: 3 DEPTARGET
+|18: 4 d4
+|19: 5 d5
+|20: 6 d6
+== snap step1 grid=210x31 cursor=13,5
+== snap step2 grid=210x31 cursor=17,3
+== snap step3 grid=210x31 cursor=17,3
+== snap selclick grid=210x31 cursor=14,6
+== snap outside grid=210x31 cursor=20,6
+|12: /tmp/pardes-snap/rsearch/cwd/+Search Save Tty Del Collapse
+|13: 1 code.txt:4:10-14 pick two words
diff --git a/test/snapshots/rsearch.snap b/test/snapshots/rsearch.snap
index 9c9ee8b6..c413c559 100644
--- a/test/snapshots/rsearch.snap
+++ b/test/snapshots/rsearch.snap
@@ -7,80 +7,80 @@
dirmk sub
file sub/dep.txt d1\nd2\nDEPTARGET\nd4\nd5\nd6
file code.txt run count_x now\nopen sub/dep.txt:3 here\ncount_x again\npick two words
-start 30 210 -n 1
+start 31 210 -n 1
wait 8000 code.txt
stable 700 20000
# open code.txt: type the name in a shell, right-click it (ordinary look)
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key i
text code.txt
key esc
settle 100
stable 400 5000
-press right 6 8
-release right 6 8
+press right 6 9
+release right 6 9
wait 10000 count_x
stable 700 15000
snap opened
# right-CLICK the identifier `count_x` (line 1, the 'n' at col 15). It names no
# file, so the click searches for it: the results list both lines containing it.
-press right 15 3
-release right 15 3
+press right 15 4
+release right 15 4
wait 10000 code.txt:1:5-11 run count_x
stable 700 15000
snap search
# right-SELECT `pick two` (line 4, sweep cols 8..15): a multi-word span passes
# through verbatim (the space is kept), unlike a click's single-word expansion.
-press right 8 6
-drag right 15 6
-release right 15 6
+press right 8 7
+drag right 15 7
+release right 15 7
wait 10000 code.txt:4:1-8 pick two
stable 700 15000
snap select
# right-CLICK the path `sub/dep.txt:3` (line 2, col 18): isFileChar keeps / . :
# so the click expands the whole token and it RESOLVES — a look, not a search —
# opening dep.txt scrolled to line 3 (DEPTARGET). The "don't break paths" case.
-press right 18 4
-release right 18 4
+press right 18 5
+release right 18 5
wait 10000 DEPTARGET
stable 700 15000
snap path-open
# A click does not merely LIST the hits, it goes to one: this re-search of
# `count_x` (line 1, col 15) also STEPS onto hit 1, so the cursor lands in the
# match — line 1 col 5, not the column that was clicked.
-press right 15 3
-release right 15 3
+press right 15 4
+release right 15 4
stable 700 15000
snap step1
# ...and the same word clicked in its OTHER place (line 3, col 10) opens NO
# second +Search: the list is already armed on this pattern, so the click is
# `n`. Cursor moves to hit 2, line 3.
-press right 10 5
-release right 10 5
+press right 10 6
+release right 10 6
stable 700 15000
snap step2
# past the last hit the ring wraps: back to hit 1, line 1.
-press right 10 5
-release right 10 5
+press right 10 6
+release right 10 6
stable 700 15000
snap step3
# A LEFT sweep over `pick two` (line 4, cols 8..15) and then a right CLICK
# INSIDE it: the click takes the whole selection — the search is for the
# two-word span (`4:1-8`), which the file-ish word expansion could never
# produce from the single word under the click.
-press left 8 6
-drag left 15 6
-release left 15 6
+press left 8 7
+drag left 15 7
+release left 15 7
stable 400 5000
-press right 11 6
-release right 11 6
+press right 11 7
+release right 11 7
stable 700 15000
snap selclick
# ...and a right click OUTSIDE the selection is the ordinary word click again:
# `words` (line 4, col 19), not the span left lying in the pane.
-press right 19 6
-release right 19 6
+press right 19 7
+release right 19 7
stable 700 15000
snap outside
diff --git a/test/snapshots/savepane.golden b/test/snapshots/savepane.golden
index ddea4d55..070146d3 100644
--- a/test/snapshots/savepane.golden
+++ b/test/snapshots/savepane.golden
@@ -1,15 +1,16 @@
-== snap scratch grid=100x30 cursor=20,5
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/savepane/cwd Save New Newtty Del Filter
+== snap scratch grid=100x31 cursor=20,6
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/savepane/cwd Save Tty Del Togglettymode Filter Collapse
| ls
|
-| /tmp/pardes-snap/savepane/cwd/+New * Save New Newtty Del
+| /tmp/pardes-snap/savepane/cwd/+New * Save Tty Del Collapse
| 1 scratch bytes
-== snap prompt grid=100x30 cursor=38,29
-|29: Save /tmp/pardes-snap/savepane/cwd/
-== snap saved grid=100x30 cursor=20,5
-|4: /tmp/pardes-snap/savepane/cwd/saved.txt Save New Newtty Del
-|29: --:--:-- saved /tmp/pardes-snap/savepane/cwd/saved.txt
+== snap prompt grid=100x31 cursor=38,30
+|30: Save /tmp/pardes-snap/savepane/cwd/
+== snap saved grid=100x31 cursor=20,6
+|5: /tmp/pardes-snap/savepane/cwd/saved.txt Save Tty Del Collapse
+|30: --:--:-- saved /tmp/pardes-snap/savepane/cwd/saved.txt
== file bytes
scratch bytes
== end file
diff --git a/test/snapshots/savepane.snap b/test/snapshots/savepane.snap
index f5a3b9e2..58df13ef 100644
--- a/test/snapshots/savepane.snap
+++ b/test/snapshots/savepane.snap
@@ -7,8 +7,8 @@
# scratch asks for a path in its inherited dir and makes it a file"); none of
# them can see it drawn, land on the tag rather than the message row, or show
# what the pane becomes afterwards. That is what this script is for.
-start 30 100 -n 1
-wait 8000 New Newcol
+start 31 100 -n 1
+wait 8000 Newcol Joincol
stable 700 20000
# a scratch of our own, with something in it to save
key space f n
diff --git a/test/snapshots/scroll.golden b/test/snapshots/scroll.golden
index eb35bcba..46576f75 100644
--- a/test/snapshots/scroll.golden
+++ b/test/snapshots/scroll.golden
@@ -1,6 +1,7 @@
-== snap bottom grid=100x30 cursor=4,15
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/scroll/cwd Save New Newtty Del /tmp/pardes-snap/scroll/cwd Save New Newtty Del
+== snap bottom grid=100x31 cursor=4,16
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/scroll/cwd Save Tty Del Togglet /tmp/pardes-snap/scroll/cwd Save Tty Del Togglet
| 188 ls
| 189 s.txt
| 190
@@ -15,43 +16,57 @@
| 199
| 200
|
-| /tmp/pardes-snap/scroll/cwd Save New Newtty Del
+| /tmp/pardes-snap/scroll/cwd Save Tty Del Togglet
| ls
| s.txt
-== snap wheel3 grid=100x30 cursor=4,15
-|2: 185 ls
-|3: 186 s.txt
-|4: 187
-|5: 188
-|6: 189
-|7: 190
-|8: 191
-|9: 192
-|10: 193
-|11: 194
-|12: 195
-|13: 196
-|14: 197
-|15: 198
-== snap gutter-up grid=100x30 cursor=4,15
-|2: 178 ls
-|3: 179 s.txt
-|4: 180
-|5: 181
-|6: 182
-|7: 183
-|8: 184
-|9: 185
-|10: 186
-|11: 187
-|12: 188
-|13: 189
-|14: 190
-|15: 191
-== snap gutter-down grid=100x30 cursor=4,15
-|2: 180 ls
-|3: 181 s.txt
-|4: 182
+== snap wheel3 grid=100x31 cursor=4,16
+|3: 185 ls
+|4: 186 s.txt
+|5: 187
+|6: 188
+|7: 189
+|8: 190
+|9: 191
+|10: 192
+|11: 193
+|12: 194
+|13: 195
+|14: 196
+|15: 197
+|16: 198
+== snap gutter-up grid=100x31 cursor=4,16
+|3: 178 ls
+|4: 179 s.txt
+|5: 180
+|6: 181
+|7: 182
+|8: 183
+|9: 184
+|10: 185
+|11: 186
+|12: 187
+|13: 188
+|14: 189
+|15: 190
+|16: 191
+== snap gutter-down grid=100x31 cursor=4,16
+|3: 180 ls
+|4: 181 s.txt
+|5: 182
+|6: 183
+|7: 184
+|8: 185
+|9: 186
+|10: 187
+|11: 188
+|12: 189
+|13: 190
+|14: 191
+|15: 192
+|16: 193
+== snap wheel-down grid=100x31 cursor=4,16
+|3: 181 ls
+|4: 182 s.txt
|5: 183
|6: 184
|7: 185
@@ -63,49 +78,36 @@
|13: 191
|14: 192
|15: 193
-== snap wheel-down grid=100x30 cursor=4,15
-|2: 181 ls
-|3: 182 s.txt
-|4: 183
-|5: 184
-|6: 185
-|7: 186
-|8: 187
-|9: 188
-|10: 189
-|11: 190
-|12: 191
-|13: 192
-|14: 193
-|15: 194
-== style wheel-down grid=100x30
-|0: 0-74 #949494,#121212, 75-99 d,#121212,
-|1: 0-1 #ffffff,#626262, 2-49 #949494,#121212, 50-51 #ffffff,#262626, 52-99 #949494,#121212,
-|2: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|3: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|4: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-99 d,#080808,
-|5: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|6: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|7: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|8: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|9: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|10: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|11: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|12: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|13: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|15: 0-0 d,#121212, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|16: 0-1 #ffffff,#262626, 2-49 #949494,#121212, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|19: 0-0 d,#444444, 1-49 d,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|29: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
+|16: 194
+== style wheel-down grid=100x31
+|0: 0-70 #b2c3b8,#1d2824, 71-99 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-49 d,#26362d, 50-74 #b2c3b8,#1d2824, 75-99 d,#1d2824,
+|2: 0-1 #000000,#adcc91, 2-49 #becfc4,#26362d, 50-51 #ffffff,#4c6356, 52-99 #b2c3b8,#1d2824,
+|3: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|4: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|5: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-99 d,#0d1410,
+|6: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|7: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|8: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|9: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|10: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|11: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|12: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|13: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|14: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|16: 0-0 d,#152019, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|17: 0-1 #ffffff,#4c6356, 2-49 #b2c3b8,#1d2824, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|20: 0-0 d,#637f6a, 1-49 d,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
diff --git a/test/snapshots/scroll.snap b/test/snapshots/scroll.snap
index dd025474..d8d3e665 100644
--- a/test/snapshots/scroll.snap
+++ b/test/snapshots/scroll.snap
@@ -1,6 +1,6 @@
# scrolling: wheel + scrollbar gutter clicks over real scrollback
file s.txt x
-start 30 100 -n 3
+start 31 100 -n 3
wait 8000 s.txt
stable 700 20000
key c-b
@@ -17,12 +17,12 @@ wheel up 10 8
wheel up 10 8
stable 500 8000
snap wheel3
-press left 1 10
-release left 1 10
+press left 1 11
+release left 1 11
stable 500 8000
snap gutter-up
-press right 1 5
-release right 1 5
+press right 1 6
+release right 1 6
stable 500 8000
snap gutter-down
wheel down 10 8
diff --git a/test/snapshots/scrolloff.golden b/test/snapshots/scrolloff.golden
index 3651c8b7..6054e8bc 100644
--- a/test/snapshots/scrolloff.golden
+++ b/test/snapshots/scrolloff.golden
@@ -1,6 +1,7 @@
-== snap top grid=210x11 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/scrolloff/cwd/g.txt Save New Newtty Del /tmp/pardes-snap/scrolloff/cwd Save New Newtty Del Filter
+== snap top grid=210x12 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/scrolloff/cwd/g.txt Save Tty Del Collapse /tmp/pardes-snap/scrolloff/cwd Save Tty Del Togglettymode Filter Collapse
| 1 line 1 ls
| 2 line 2 g.txt
| 3 line 3
@@ -10,54 +11,54 @@
| 7 line 7
| 8 line 8
| 9 line 9
-== snap edge grid=210x11 cursor=7,7
-== snap scrolled1 grid=210x11 cursor=7,7
-|2: 2 line 2 ls
-|3: 3 line 3 g.txt
-|4: 4 line 4
-|5: 5 line 5
-|6: 6 line 6
-|7: 7 line 7
-|8: 8 line 8
-|9: 9 line 9
-|10: 10 line 10
-== snap jdown grid=210x11 cursor=7,7
-|2: 6 line 6 ls
-|3: 7 line 7 g.txt
-|4: 8 line 8
-|5: 9 line 9
-|6: 10 line 10
-|7: 11 line 11
-|8: 12 line 12
-|9: 13 line 13
-|10: 14 line 14
-== snap end grid=210x11 cursor=7,9
-|2: 33 line 33 ls
-|3: 34 line 34 g.txt
-|4: 35 line 35
-|5: 36 line 36
-|6: 37 line 37
-|7: 38 line 38
-|8: 39 line 39
-|9: 40 line 40
-|10: 41
-== snap kup grid=210x11 cursor=7,5
-|2: 29 line 29 ls
-|3: 30 line 30 g.txt
-|4: 31 line 31
-|5: 32 line 32
-|6: 33 line 33
-|7: 34 line 34
-|8: 35 line 35
-|9: 36 line 36
-|10: 37 line 37
-== snap top2 grid=210x11 cursor=7,2
-|2: 1 line 1 ls
-|3: 2 line 2 g.txt
-|4: 3 line 3
+== snap edge grid=210x12 cursor=7,8
+== snap scrolled1 grid=210x12 cursor=7,8
+|3: 2 line 2 ls
+|4: 3 line 3 g.txt
|5: 4 line 4
|6: 5 line 5
|7: 6 line 6
|8: 7 line 7
|9: 8 line 8
|10: 9 line 9
+|11: 10 line 10
+== snap jdown grid=210x12 cursor=7,8
+|3: 6 line 6 ls
+|4: 7 line 7 g.txt
+|5: 8 line 8
+|6: 9 line 9
+|7: 10 line 10
+|8: 11 line 11
+|9: 12 line 12
+|10: 13 line 13
+|11: 14 line 14
+== snap end grid=210x12 cursor=7,10
+|3: 33 line 33 ls
+|4: 34 line 34 g.txt
+|5: 35 line 35
+|6: 36 line 36
+|7: 37 line 37
+|8: 38 line 38
+|9: 39 line 39
+|10: 40 line 40
+|11: 41
+== snap kup grid=210x12 cursor=7,6
+|3: 29 line 29 ls
+|4: 30 line 30 g.txt
+|5: 31 line 31
+|6: 32 line 32
+|7: 33 line 33
+|8: 34 line 34
+|9: 35 line 35
+|10: 36 line 36
+|11: 37 line 37
+== snap top2 grid=210x12 cursor=7,3
+|3: 1 line 1 ls
+|4: 2 line 2 g.txt
+|5: 3 line 3
+|6: 4 line 4
+|7: 5 line 5
+|8: 6 line 6
+|9: 7 line 7
+|10: 8 line 8
+|11: 9 line 9
diff --git a/test/snapshots/scrolloff.snap b/test/snapshots/scrolloff.snap
index 94ea36f6..caed9d47 100644
--- a/test/snapshots/scrolloff.snap
+++ b/test/snapshots/scrolloff.snap
@@ -1,16 +1,16 @@
# scrolloff: keyboard motion keeps 3 context rows above/below the cursor,
# clamped at file boundaries (cursor may reach the top/bottom body row there)
lines g.txt 40
-start 11 210 -n 1
+start 12 210 -n 1
wait 8000 g.txt
stable 700 20000
# right-click the g.txt name in the greeting ls -> file pane, 9 body rows
-press right 4 4
-release right 4 4
+press right 4 5
+release right 4 5
wait 10000 line 3
stable 700 15000
-press left 10 3
-release left 10 3
+press left 10 4
+release left 10 4
stable 400 5000
# (b) gg: cursor CAN sit on the top body row, no forced scroll
key g g
diff --git a/test/snapshots/selarg.golden b/test/snapshots/selarg.golden
index bd0b1c1d..b0a14b86 100644
--- a/test/snapshots/selarg.golden
+++ b/test/snapshots/selarg.golden
@@ -1,6 +1,7 @@
-== snap kept grid=100x30 cursor=6,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/selarg/cwd Save New Newtty Del /tmp/pardes-snap/selarg/cwd Save New Newtty Del
+== snap kept grid=100x31 cursor=6,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/selarg/cwd Save Tty Del Togglet /tmp/pardes-snap/selarg/cwd Save Tty Del Togglet
| ZZARG ZZVEE ./c.sh
|
|
@@ -15,12 +16,12 @@
|
|
|
-| /tmp/pardes-snap/selarg/cwd Save New Newtty Del
+| /tmp/pardes-snap/selarg/cwd Save Tty Del Togglet
| ls
| s.txt
-== snap crosspane grid=100x30 cursor=6,2
-|3: ./c.sh ZZARG
-|4: CHORDARG:ZZARG
-== snap vselarg grid=100x30 cursor=12,2
-|5: ./c.sh ZZVEE
-|6: CHORDARG:ZZVEE
+== snap crosspane grid=100x31 cursor=6,3
+|4: ./c.sh ZZARG
+|5: CHORDARG:ZZARG
+== snap vselarg grid=100x31 cursor=12,3
+|6: ./c.sh ZZVEE
+|7: CHORDARG:ZZVEE
diff --git a/test/snapshots/selarg.snap b/test/snapshots/selarg.snap
index c7b09c33..1df7ee12 100644
--- a/test/snapshots/selarg.snap
+++ b/test/snapshots/selarg.snap
@@ -3,7 +3,7 @@
# selection of its own — the chord's left tap finds A's kept left selection,
# and later A's explicit v selection, and rides it as the argument.
file s.txt x
-start 30 100 -n 3
+start 31 100 -n 3
wait 8000 s.txt
stable 700 20000
# pane A (left, active at boot): print the two argument words
@@ -16,8 +16,8 @@ stable 700 15000
key c-b
stable 600 8000
# pane B (top right): create the arg-printing script and show its path
-press left 60 5
-release left 60 5
+press left 60 6
+release left 60 6
stable 400 5000
key c-b
stable 600 8000
@@ -28,31 +28,31 @@ stable 700 15000
key c-b
stable 600 8000
# keep a left selection over ZZARG in pane A (this also focuses A)
-press left 3 3
-drag left 7 3
-release left 7 3
+press left 3 4
+drag left 7 4
+release left 7 4
stable 400 5000
snap kept
# chord in pane B: middle on ./c.sh + left tap (B has NO selection: the
# argument comes from pane A's kept left selection) + middle release runs
-press middle 55 3
-press left 55 3
-release middle 55 3
-release left 55 3
+press middle 55 4
+press left 55 4
+release middle 55 4
+release left 55 4
wait 10000 CHORDARG:ZZARG
stable 700 10000
snap crosspane
# now an explicit modal selection: plain-click ZZVEE in A (drops A's kept
# left selection), select it with v e, chord in B again
-press left 9 3
-release left 9 3
+press left 9 4
+release left 9 4
stable 400 5000
text ve
stable 400 5000
-press middle 55 3
-press left 55 3
-release middle 55 3
-release left 55 3
+press middle 55 4
+press left 55 4
+release middle 55 4
+release left 55 4
wait 10000 CHORDARG:ZZVEE
stable 700 10000
snap vselarg
diff --git a/test/snapshots/selregex.golden b/test/snapshots/selregex.golden
index ac15f693..4f380f9b 100644
--- a/test/snapshots/selregex.golden
+++ b/test/snapshots/selregex.golden
@@ -1,6 +1,7 @@
-== snap prompt-armed grid=160x24 cursor=11,23
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/selregex/cwd/m.zig Save New Newtty Del
+== snap prompt-armed grid=160x25 cursor=11,24
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/selregex/cwd/m.zig Save Tty Del Collapse
| 1 const one = 1;
| 2 const two = 2;
| 3 const three = 3;
@@ -23,58 +24,59 @@
|
|
| Select /
-== snap preview grid=160x24 cursor=16,23
-|23: Select /const
-== style preview grid=160x24
-|0: 0-74 #949494,#121212, 75-159 d,#121212,
-|1: 0-1 #ffffff,#626262, 2-139 #949494,#121212, 140-159 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #080808,#80a0ff, 11-11 #80a0ff,#080808, 12-18 #bdbdbd,#080808, 19-19 #e3c78a,#080808, 20-20 #bdbdbd,#080808, 21-159 d,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #080808,#445483, 11-11 #80a0ff,#080808, 12-18 #bdbdbd,#080808, 19-19 #e3c78a,#080808, 20-20 #bdbdbd,#080808, 21-159 d,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #080808,#445483, 11-11 #80a0ff,#080808, 12-20 #bdbdbd,#080808, 21-21 #e3c78a,#080808, 22-22 #bdbdbd,#080808, 23-159 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-159 d,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-159 d,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-159 d,#080808,
-|8: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-159 d,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-159 d,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-159 d,#080808,
-|11: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-159 d,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-159 d,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-159 d,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-159 d,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-159 d,#080808,
-|16: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-159 d,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-159 d,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-159 d,#080808,
-|19: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-159 d,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-159 d,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-159 d,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-159 d,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-15 #bdbdbd,#080808, 16-159 d,#080808,
-== snap three-selected grid=160x24 cursor=11,2
-|23:
-== style three-selected grid=160x24
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-11 #080808,#80a0ff, 12-18 #bdbdbd,#080808, 19-19 #e3c78a,#080808, 20-20 #bdbdbd,#080808, 21-159 d,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-159 d,#080808,
-== snap narrowed grid=160x24 cursor=12,23
-|23: Select /t
-== style narrowed grid=160x24
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-11 #80a0ff,#080808, 12-18 #bdbdbd,#080808, 19-19 #e3c78a,#080808, 20-20 #bdbdbd,#080808, 21-159 d,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-11 #80a0ff,#080808, 12-18 #bdbdbd,#080808, 19-19 #e3c78a,#080808, 20-20 #bdbdbd,#080808, 21-159 d,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-11 #80a0ff,#080808, 12-20 #bdbdbd,#080808, 21-21 #e3c78a,#080808, 22-22 #bdbdbd,#080808, 23-159 d,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-11 #bdbdbd,#080808, 12-159 d,#080808,
-== snap esc-restores grid=160x24 cursor=11,2
-|23:
-== style esc-restores grid=160x24
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-11 #080808,#80a0ff, 12-18 #bdbdbd,#080808, 19-19 #e3c78a,#080808, 20-20 #bdbdbd,#080808, 21-159 d,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #080808,#445483, 11-11 #80a0ff,#080808, 12-18 #bdbdbd,#080808, 19-19 #e3c78a,#080808, 20-20 #bdbdbd,#080808, 21-159 d,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #080808,#445483, 11-11 #80a0ff,#080808, 12-20 #bdbdbd,#080808, 21-21 #e3c78a,#080808, 22-22 #bdbdbd,#080808, 23-159 d,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-159 d,#080808,
-== snap commented grid=160x24 cursor=14,2
-|1: /tmp/pardes-snap/selregex/cwd/m.zig * Save New Newtty Del
-|2: 1 // const one = 1;
-|3: 2 // const two = 2;
-|4: 3 // const three = 3;
-== snap uncommented grid=160x24 cursor=11,2
-|2: 1 const one = 1;
-|3: 2 const two = 2;
-|4: 3 const three = 3;
+== snap preview grid=160x25 cursor=16,24
+|24: Select /const
+== style preview grid=160x25
+|0: 0-70 #b2c3b8,#1d2824, 71-159 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-159 d,#26362d,
+|2: 0-1 #000000,#adcc91, 2-58 #becfc4,#26362d, 59-159 d,#26362d,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #f5f7ee,#405d4b, 11-11 #405d4b,#f5f7ee, 12-18 #e5eee5,#0d1410, 19-19 #e9bf91,#0d1410, 20-20 #e5eee5,#0d1410, 21-159 d,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #f5f7ee,#26382d, 11-11 #405d4b,#f5f7ee, 12-18 #e5eee5,#0d1410, 19-19 #e9bf91,#0d1410, 20-20 #e5eee5,#0d1410, 21-159 d,#0d1410,
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #f5f7ee,#26382d, 11-11 #405d4b,#f5f7ee, 12-20 #e5eee5,#0d1410, 21-21 #e9bf91,#0d1410, 22-22 #e5eee5,#0d1410, 23-159 d,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-159 d,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-159 d,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-159 d,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-159 d,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-159 d,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-159 d,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-159 d,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-159 d,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-159 d,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-159 d,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-159 d,#0d1410,
+|17: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-159 d,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-159 d,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-159 d,#0d1410,
+|20: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-159 d,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-159 d,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-159 d,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-159 d,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-15 #e5eee5,#0d1410, 16-159 d,#0d1410,
+== snap three-selected grid=160x25 cursor=11,3
+|24:
+== style three-selected grid=160x25
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-11 #f5f7ee,#405d4b, 12-18 #e5eee5,#0d1410, 19-19 #e9bf91,#0d1410, 20-20 #e5eee5,#0d1410, 21-159 d,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-159 d,#0d1410,
+== snap narrowed grid=160x25 cursor=12,24
+|24: Select /t
+== style narrowed grid=160x25
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-11 #405d4b,#f5f7ee, 12-18 #e5eee5,#0d1410, 19-19 #e9bf91,#0d1410, 20-20 #e5eee5,#0d1410, 21-159 d,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-11 #405d4b,#f5f7ee, 12-18 #e5eee5,#0d1410, 19-19 #e9bf91,#0d1410, 20-20 #e5eee5,#0d1410, 21-159 d,#0d1410,
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-11 #405d4b,#f5f7ee, 12-20 #e5eee5,#0d1410, 21-21 #e9bf91,#0d1410, 22-22 #e5eee5,#0d1410, 23-159 d,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-11 #e5eee5,#0d1410, 12-159 d,#0d1410,
+== snap esc-restores grid=160x25 cursor=11,3
+|24:
+== style esc-restores grid=160x25
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-11 #f5f7ee,#405d4b, 12-18 #e5eee5,#0d1410, 19-19 #e9bf91,#0d1410, 20-20 #e5eee5,#0d1410, 21-159 d,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #f5f7ee,#26382d, 11-11 #405d4b,#f5f7ee, 12-18 #e5eee5,#0d1410, 19-19 #e9bf91,#0d1410, 20-20 #e5eee5,#0d1410, 21-159 d,#0d1410,
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #f5f7ee,#26382d, 11-11 #405d4b,#f5f7ee, 12-20 #e5eee5,#0d1410, 21-21 #e9bf91,#0d1410, 22-22 #e5eee5,#0d1410, 23-159 d,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-159 d,#0d1410,
+== snap commented grid=160x25 cursor=14,3
+|2: /tmp/pardes-snap/selregex/cwd/m.zig * Save Tty Del Collapse
+|3: 1 // const one = 1;
+|4: 2 // const two = 2;
+|5: 3 // const three = 3;
+== snap uncommented grid=160x25 cursor=11,3
+|3: 1 const one = 1;
+|4: 2 const two = 2;
+|5: 3 const three = 3;
diff --git a/test/snapshots/selregex.snap b/test/snapshots/selregex.snap
index 193ab314..b4a042f8 100644
--- a/test/snapshots/selregex.snap
+++ b/test/snapshots/selregex.snap
@@ -7,7 +7,7 @@
file m.zig const one = 1;\nconst two = 2;\nconst three = 3;\n
# wide on purpose: the whole point of this script is a tag long enough to hold
# the marker AND the pattern, and a narrow pane simply truncates it away
-start 24 160 m.zig
+start 25 160 m.zig
wait 8000 m.zig
stable 700 20000
key g g
diff --git a/test/snapshots/shellset.golden b/test/snapshots/shellset.golden
index 37866d46..33cbfb29 100644
--- a/test/snapshots/shellset.golden
+++ b/test/snapshots/shellset.golden
@@ -1,9 +1,11 @@
-== snap boot grid=90x20 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/shellset/cwd/cmd.txt Save New Newtty Del
+== snap boot grid=90x21 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/shellset/cwd/cmd.txt Save Tty Del Collapse
| 1 Shell zznosuchshell
-== snap builtin-ran grid=90x20 cursor=25,2
-== snap fallback-shell grid=90x20 cursor=49,4
-|1: /tmp/pardes-snap/shellset/cwd/cmd.txt Save /tmp/pardes-snap/shellset/cwd Save New Newt
-|2: 1 Shell zznosuchshell ls
-|3: cmd.txt zmarkfile.txt
+== snap builtin-ran grid=90x21 cursor=25,3
+== snap fallback-shell grid=90x21 cursor=49,5
+|1: New Tty Find Grep Joincol New Tty Find Grep Joincol
+|2: /tmp/pardes-snap/shellset/cwd/cmd.txt Save /tmp/pardes-snap/shellset/cwd Save Tty Del
+|3: 1 Shell zznosuchshell ls
+|4: cmd.txt zmarkfile.txt
diff --git a/test/snapshots/shellset.snap b/test/snapshots/shellset.snap
index e50d29bc..d2bacf38 100644
--- a/test/snapshots/shellset.snap
+++ b/test/snapshots/shellset.snap
@@ -16,7 +16,7 @@
# ordinary config file the harness writes — see snapshot.zig.)
file cmd.txt Shell zznosuchshell
file zmarkfile.txt x
-start 20 90 cmd.txt
+start 21 90 cmd.txt
wait 8000 Shell zznosuchshell
stable 700 20000
snap boot
diff --git a/test/snapshots/shrinktag.golden b/test/snapshots/shrinktag.golden
index e186d330..41098ef1 100644
--- a/test/snapshots/shrinktag.golden
+++ b/test/snapshots/shrinktag.golden
@@ -1,6 +1,7 @@
-== snap before grid=100x30 cursor=2,8
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/shrinktag/cwd Save New Newtty D /tmp/pardes-snap/shrinktag/cwd Save New Newtty D
+== snap before grid=100x31 cursor=2,9
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/shrinktag/cwd Save Tty Del Togg /tmp/pardes-snap/shrinktag/cwd Save Tty Del Togg
| ls ls
| w.txt w.txt
|
@@ -15,29 +16,29 @@
|
|
|
-| /tmp/pardes-snap/shrinktag/cwd Save New Newtty D
+| /tmp/pardes-snap/shrinktag/cwd Save Tty Del Togg
| ls
| w.txt
-== snap shrunk grid=100x30 cursor=2,8
-|2: /tmp/pardes-snap/shrinktag/cwd Save New Newtty D ls
-|3: ls w.txt
-|4: w.txt
-|7:
-|16:
+== snap shrunk grid=100x31 cursor=2,9
+|3: /tmp/pardes-snap/shrinktag/cwd Save Tty Del Togg ls
+|4: ls w.txt
+|5: w.txt
+|8:
|17:
|18:
-== snap move-preview grid=100x30 cursor=2,8
-|7: ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌▌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
-== snap restored grid=100x30 cursor=2,8
-|2: ls ls
-|3: w.txt w.txt
-|4:
-|7: echo one; echo two
-|16: /tmp/pardes-snap/shrinktag/cwd Save New Newtty D
-|17: ls
-|18: w.txt
-== snap bottom-shrunk grid=100x30 cursor=2,8
-|16:
+|19:
+== snap move-preview grid=100x31 cursor=2,9
+|8: ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌▌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
+== snap restored grid=100x31 cursor=2,9
+|3: ls ls
+|4: w.txt w.txt
+|5:
+|8: echo one; echo two
+|17: /tmp/pardes-snap/shrinktag/cwd Save Tty Del Togg
+|18: ls
+|19: w.txt
+== snap bottom-shrunk grid=100x31 cursor=2,9
|17:
|18:
-|29: /tmp/pardes-snap/shrinktag/cwd Save New Newtty D
+|19:
+|30: /tmp/pardes-snap/shrinktag/cwd Save Tty Del Togg
diff --git a/test/snapshots/shrinktag.snap b/test/snapshots/shrinktag.snap
index 94d36282..f17c402f 100644
--- a/test/snapshots/shrinktag.snap
+++ b/test/snapshots/shrinktag.snap
@@ -2,12 +2,12 @@
# (0 body rows), the gutter box still grabs a move, and dragging back down
# restores the body intact (the hidden pane's pty/vt is never resized)
file w.txt x
-start 30 100 -n 3
+start 31 100 -n 3
wait 8000 w.txt
stable 700 20000
# content in pane 0 so the restored body is provably intact
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key i
text echo one; echo two
@@ -17,33 +17,33 @@ settle 100
stable 400 5000
snap before
# drag pane 0's bottom handle (its last row) up to its tag row: tag-only pane
-press left 20 16
-drag left 20 2
-release left 20 2
+press left 20 17
+drag left 20 3
+release left 20 3
motion 40 25
stable 500 8000
snap shrunk
# the shrunk pane's single row is now the pair's resize handle, but the gutter
# box must still win: grab it, preview a move into the right column, abort by
# releasing over the pane itself
-press left 1 2
-drag left 70 8
+press left 1 3
+drag left 70 9
stable 400 5000
snap move-preview
-drag left 20 2
-release left 20 2
+drag left 20 3
+release left 20 3
stable 400 5000
# re-enlarge: the tag row doubles as the drag handle, pull it back down
-press left 20 2
-drag left 20 16
-release left 20 16
+press left 20 3
+drag left 20 17
+release left 20 17
motion 40 25
stable 500 8000
snap restored
# the bottom pane can shrink to ITS tag too: drag past the bottom, clamp holds
-press left 20 16
-drag left 20 30
-release left 20 30
+press left 20 17
+drag left 20 31
+release left 20 31
motion 40 25
stable 500 8000
snap bottom-shrunk
diff --git a/test/snapshots/splitparent.golden b/test/snapshots/splitparent.golden
index cc3a785b..7382103d 100644
--- a/test/snapshots/splitparent.golden
+++ b/test/snapshots/splitparent.golden
@@ -1,23 +1,26 @@
-== snap shrunk grid=100x30 cursor=4,3
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/splitparent/cwd Save New Newtty /tmp/pardes-snap/splitparent/cwd Save New Newtty
-| /tmp/pardes-snap/splitparent/cwd Save New Newtty ls
+== snap shrunk grid=100x31 cursor=4,4
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/splitparent/cwd Save Tty Del To /tmp/pardes-snap/splitparent/cwd Save Tty Del To
+| /tmp/pardes-snap/splitparent/cwd Save Tty Del To ls
| ls
-== snap swap-parent grid=100x30 cursor=4,7
-|5: /tmp/pardes-snap/splitparent/cwd Save New Newtty
-|6: ls
-== snap tallest grid=100x5 cursor=54,4
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/splitparent/cwd Save New Newtty /tmp/pardes-snap/splitparent/cwd Save New Newtty
-| /tmp/pardes-snap/splitparent/cwd Save New Newtty
-| /tmp/pardes-snap/splitparent/cwd Save New Newtty /tmp/pardes-snap/splitparent/cwd Save New Newtty
-== snap regrown grid=100x30 cursor=54,18
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/splitparent/cwd Save New Newtty /tmp/pardes-snap/splitparent/cwd Save New Newtty
-| /tmp/pardes-snap/splitparent/cwd Save New Newtty ls
+== snap swap-parent grid=100x31 cursor=4,8
+|6: /tmp/pardes-snap/splitparent/cwd Save Tty Del To
+|7: ls
+== snap tallest grid=100x6 cursor=54,5
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/splitparent/cwd Save Tty Del To /tmp/pardes-snap/splitparent/cwd Save Tty Del To
+| /tmp/pardes-snap/splitparent/cwd Save Tty Del To
+| /tmp/pardes-snap/splitparent/cwd Save Tty Del To /tmp/pardes-snap/splitparent/cwd Save Tty Del To
+== snap regrown grid=100x31 cursor=54,19
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/splitparent/cwd Save Tty Del To /tmp/pardes-snap/splitparent/cwd Save Tty Del To
+| /tmp/pardes-snap/splitparent/cwd Save Tty Del To ls
| ls
|
-| /tmp/pardes-snap/splitparent/cwd Save New Newtty
+| /tmp/pardes-snap/splitparent/cwd Save Tty Del To
| ls
|
|
@@ -28,5 +31,5 @@
|
|
|
-| /tmp/pardes-snap/splitparent/cwd Save New Newtty
+| /tmp/pardes-snap/splitparent/cwd Save Tty Del To
| ls
diff --git a/test/snapshots/splitparent.snap b/test/snapshots/splitparent.snap
index 77a1fba1..1fd4e935 100644
--- a/test/snapshots/splitparent.snap
+++ b/test/snapshots/splitparent.snap
@@ -1,12 +1,12 @@
# a new pane never opens under a too-short parent: Alt-n from a tag-only pane
# splits the tall sibling in its column instead; when NO pane could leave the
# newcomer 2 body rows, the tallest one anywhere is split
-start 30 100 -n 3
+start 31 100 -n 3
stable 700 20000
# shrink pane 0 (top-left) to just its tagline
-press left 20 16
-drag left 20 2
-release left 20 2
+press left 20 17
+drag left 20 3
+release left 20 3
motion 40 25
stable 500 8000
snap shrunk
@@ -17,11 +17,11 @@ stable 700 15000
snap swap-parent
# squeeze the grid until no pane is 5 rows tall, then Alt-n again: the
# tallest pane (right column) is split even though the active one is left
-resize 5 100
+resize 6 100
stable 700 15000
key a-n
stable 700 15000
snap tallest
-resize 30 100
+resize 31 100
stable 700 15000
snap regrown
diff --git a/test/snapshots/stepgrain.golden b/test/snapshots/stepgrain.golden
index 1baf8ff1..202a4f9a 100644
--- a/test/snapshots/stepgrain.golden
+++ b/test/snapshots/stepgrain.golden
@@ -1,6 +1,7 @@
-== snap results grid=150x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/stepgrain/cwd/a.txt Save New Newtty Del
+== snap results grid=150x31 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/stepgrain/cwd/a.txt Save Tty Del Collapse
| 1 hello ZQMARK one
| 2 see also sub/b.txt for ZQMARK two
|
@@ -25,63 +26,64 @@
|
|
|
-| /tmp/pardes-snap/stepgrain/cwd/+Search Save New Newtty Del
+| /tmp/pardes-snap/stepgrain/cwd/+Search Save Tty Del Collapse
| 1 a.txt:1:7-12 hello ZQMARK one
| 2 a.txt:2:24-29 see also sub/b.txt for ZQMARK two
| 3 sub/b.txt:1:1-6 ZQMARK inside sub
-== snap step-row1 grid=150x30 cursor=7,27
-== style step-row1 grid=150x30
-|0: 0-74 #949494,#121212, 75-149 d,#121212,
-|1: 0-1 #ffffff,#262626, 2-129 #949494,#121212, 130-149 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-22 #bdbdbd,#080808, 23-149 d,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-39 #bdbdbd,#080808, 40-149 d,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|8: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|11: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|16: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|19: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-149 d,#080808,
-|26: 0-1 #ffffff,#626262, 2-129 #949494,#121212, 130-149 d,#121212,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-18 #080808,#80a0ff, 19-35 #bdbdbd,#080808, 36-149 d,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-53 #bdbdbd,#080808, 54-149 d,#080808,
-|29: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-39 #bdbdbd,#080808, 40-149 d,#080808,
-== snap step-row2 grid=150x30 cursor=7,28
-== style step-row2 grid=150x30
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-35 #bdbdbd,#080808, 36-149 d,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-19 #080808,#80a0ff, 20-53 #bdbdbd,#080808, 54-149 d,#080808,
-== snap step-row3 grid=150x30 cursor=7,28
-|27: 2 a.txt:2:24-29 see also sub/b.txt for ZQMARK two
-|28: 3 sub/b.txt:1:1-6 ZQMARK inside sub
-|29: 4
-== snap step-wrap grid=150x30 cursor=7,27
-|27: 1 a.txt:1:7-12 hello ZQMARK one
+== snap step-row1 grid=150x31 cursor=7,28
+== style step-row1 grid=150x31
+|0: 0-70 #b2c3b8,#1d2824, 71-149 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-149 d,#26362d,
+|2: 0-1 #ffffff,#4c6356, 2-59 #b2c3b8,#1d2824, 60-149 d,#1d2824,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-22 #e5eee5,#0d1410, 23-149 d,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-39 #e5eee5,#0d1410, 40-149 d,#0d1410,
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|17: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|20: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-149 d,#0d1410,
+|27: 0-1 #000000,#adcc91, 2-61 #becfc4,#26362d, 62-149 d,#26362d,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-18 #f5f7ee,#405d4b, 19-25 #e5eee5,#0d1410, 26-31 #f7e4a5,#57472a, 32-35 #e5eee5,#0d1410, 36-149 d,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-19 #59675c,#0d1410, 20-43 #e5eee5,#0d1410, 44-49 #f7e4a5,#57472a, 50-53 #e5eee5,#0d1410, 54-149 d,#0d1410,
+|30: 0-0 d,#152019, 1-1 d,#0d1410, 2-21 #59675c,#0d1410, 22-22 #e5eee5,#0d1410, 23-28 #f7e4a5,#57472a, 29-39 #e5eee5,#0d1410, 40-149 d,#0d1410,
+== snap step-row2 grid=150x31 cursor=7,29
+== style step-row2 grid=150x31
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-18 #59675c,#0d1410, 19-25 #e5eee5,#0d1410, 26-31 #f7e4a5,#57472a, 32-35 #e5eee5,#0d1410, 36-149 d,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-19 #f5f7ee,#405d4b, 20-43 #e5eee5,#0d1410, 44-49 #f7e4a5,#57472a, 50-53 #e5eee5,#0d1410, 54-149 d,#0d1410,
+== snap step-row3 grid=150x31 cursor=7,29
|28: 2 a.txt:2:24-29 see also sub/b.txt for ZQMARK two
|29: 3 sub/b.txt:1:1-6 ZQMARK inside sub
-== snap blank-in-path grid=150x30 cursor=7,25
-|24: /tmp/pardes-snap/stepgrain/cwd/+Search Save New Newtty Del
-|25: 1 two words.txt
-== style blank-in-path grid=150x30
-|24: 0-1 #ffffff,#626262, 2-129 #949494,#121212, 130-149 d,#121212,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-19 #080808,#80a0ff, 20-149 d,#080808,
-|26: 0-1 #ffffff,#262626, 2-129 #949494,#121212, 130-149 d,#121212,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-18 #080808,#80a0ff, 19-35 #bdbdbd,#080808, 36-149 d,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-53 #bdbdbd,#080808, 54-149 d,#080808,
-== snap blank-opened grid=150x30 cursor=7,14
-|13: /tmp/pardes-snap/stepgrain/cwd/two words.txt Save New Newtty Del
-|14: 1
+|30: 4
+== snap step-wrap grid=150x31 cursor=7,28
+|28: 1 a.txt:1:7-12 hello ZQMARK one
+|29: 2 a.txt:2:24-29 see also sub/b.txt for ZQMARK two
+|30: 3 sub/b.txt:1:1-6 ZQMARK inside sub
+== snap blank-in-path grid=150x31 cursor=7,26
+|25: /tmp/pardes-snap/stepgrain/cwd/+Search Save Tty Del Collapse
+|26: 1 two words.txt
+== style blank-in-path grid=150x31
+|25: 0-1 #000000,#adcc91, 2-61 #becfc4,#26362d, 62-149 d,#26362d,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-19 #f5f7ee,#405d4b, 20-149 d,#0d1410,
+|27: 0-1 #ffffff,#4c6356, 2-61 #b2c3b8,#1d2824, 62-149 d,#1d2824,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-18 #f5f7ee,#405d4b, 19-25 #e5eee5,#0d1410, 26-31 #f7e4a5,#57472a, 32-35 #e5eee5,#0d1410, 36-149 d,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-19 #59675c,#0d1410, 20-43 #e5eee5,#0d1410, 44-49 #f7e4a5,#57472a, 50-53 #e5eee5,#0d1410, 54-149 d,#0d1410,
+== snap blank-opened grid=150x31 cursor=7,15
+|14: /tmp/pardes-snap/stepgrain/cwd/two words.txt Save Tty Del Collapse
+|15: 1
diff --git a/test/snapshots/stepgrain.snap b/test/snapshots/stepgrain.snap
index a12d7bbd..3c4d3e4c 100644
--- a/test/snapshots/stepgrain.snap
+++ b/test/snapshots/stepgrain.snap
@@ -21,7 +21,7 @@ dirmk sub
file a.txt hello ZQMARK one\nsee also sub/b.txt for ZQMARK two
file sub/b.txt ZQMARK inside sub
run touch 'two words.txt'
-start 30 150 a.txt
+start 31 150 a.txt
wait 8000 hello ZQMARK
stable 700 20000
# Grep from the leader: three hits, sorted by path, the empty file contributing
@@ -55,8 +55,8 @@ stable 400 5000
snap step-wrap
# Back into the file, so the Find below is asked from a pane that is not a
# results buffer (fillResults never refills the buffer it was asked from).
-press left 8 3
-release left 8 3
+press left 8 4
+release left 8 4
stable 400 5000
# A path with a blank in it: the row is one span from its first cell, because
# the walk asks about the LONGEST run of the row first and the filesystem is
diff --git a/test/snapshots/syntax.golden b/test/snapshots/syntax.golden
index 31b212f9..3199f03a 100644
--- a/test/snapshots/syntax.golden
+++ b/test/snapshots/syntax.golden
@@ -1,109 +1,109 @@
-== snap zig-open grid=150x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/syntax/cwd/demo.zig Save New Newtty Del /tmp/pardes-snap/syntax/cwd Save New Newtty Del Filter
-| 1 const std = @import("std"); // greet ls
-| 2 pub fn main() void { demo.zig
+== snap zig-open grid=150x31 cursor=7,7
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/syntax/cwd Save Tty Del Togglettymode Filter Collapse /tmp/pardes-snap/syntax/cwd Save Tty Del Togglettymode Filter Collapse
+| ls ls
+| demo.zig demo.zig
+|
+| /tmp/pardes-snap/syntax/cwd/demo.zig Save Tty Del Collapse
+| 1 const std = @import("std"); // greet
+| 2 pub fn main() void {
| 3 var x: u32 = 42;
| 4 _ = x;
| 5 }
-|╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
-| /tmp/pardes-snap/syntax/cwd Save New Newtty Del Filter
-| ls
-| demo.zig
|
|
|
-| demo.zig
|
-| /tmp/pardes-snap/syntax/cwd Save New Newtty Del Filter
+|
+| /tmp/pardes-snap/syntax/cwd Save Tty Del Togglettymode Filter Collapse
| ls
| demo.zig
-== style zig-open grid=150x30
-|0: 0-74 #949494,#121212, 75-149 d,#121212,
-|1: 0-1 #ffffff,#626262, 2-57 #949494,#121212, 58-74 d,#121212, 75-76 #ffffff,#262626, 77-130 #949494,#121212, 131-149 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-18 #bdbdbd,#080808, 19-25 #cf87e8,#080808,b 26-26 #bdbdbd,#080808, 27-31 #e3c78a,#080808, 32-34 #bdbdbd,#080808, 35-42 #ffffff,#080808,b 43-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-12 #cf87e8,#080808,b 13-26 #bdbdbd,#080808, 27-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-23 #bdbdbd,#080808, 24-25 #e3c78a,#080808, 26-26 #bdbdbd,#080808, 27-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-16 #bdbdbd,#080808, 17-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-7 #bdbdbd,#080808, 8-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|8: 0-1 #ffffff,#262626, 2-57 #949494,#121212, 58-74 d,#121212, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|11: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-11 #bdbdbd,#080808, 12-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|16: 0-1 #ffffff,#262626, 2-57 #949494,#121212, 58-74 d,#121212, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|19: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|29: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-== style colors-off grid=150x30
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-42 #bdbdbd,#080808, 43-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-78 #bdbdbd,#080808, 79-149 d,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-26 #bdbdbd,#080808, 27-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-84 #bdbdbd,#080808, 85-149 d,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-26 #bdbdbd,#080808, 27-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-16 #bdbdbd,#080808, 17-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-7 #bdbdbd,#080808, 8-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|8: 0-1 #ffffff,#262626, 2-57 #949494,#121212, 58-74 d,#121212, 75-75 d,#444444, 76-149 d,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-3 #bdbdbd,#080808, 4-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-9 #bdbdbd,#080808, 10-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|11: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|12: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|13: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-11 #bdbdbd,#080808, 12-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|15: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|16: 0-1 #ffffff,#262626, 2-57 #949494,#121212, 58-74 d,#121212, 75-75 d,#444444, 76-149 d,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-3 #bdbdbd,#080808, 4-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-9 #bdbdbd,#080808, 10-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|19: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|20: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|21: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|22: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|23: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|24: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|25: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|26: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|27: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|28: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|29: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-== style colors-on grid=150x30
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-18 #bdbdbd,#080808, 19-25 #cf87e8,#080808,b 26-26 #bdbdbd,#080808, 27-31 #e3c78a,#080808, 32-34 #bdbdbd,#080808, 35-42 #ffffff,#080808,b 43-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-10 #bdbdbd,#080808, 11-12 #cf87e8,#080808,b 13-26 #bdbdbd,#080808, 27-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-23 #bdbdbd,#080808, 24-25 #e3c78a,#080808, 26-26 #bdbdbd,#080808, 27-74 d,#080808, 75-75 d,#444444, 76-149 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-16 #bdbdbd,#080808, 17-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-7 #bdbdbd,#080808, 8-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|8: 0-1 #ffffff,#262626, 2-57 #949494,#121212, 58-74 d,#121212, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|11: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-11 #bdbdbd,#080808, 12-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|16: 0-1 #ffffff,#262626, 2-57 #949494,#121212, 58-74 d,#121212, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|19: 0-0 d,#444444, 1-74 d,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
-|29: 0-0 d,#444444, 1-1 d,#080808, 2-74 #bdbdbd,#080808, 75-75 d,#444444, 76-76 d,#080808, 77-149 #bdbdbd,#080808,
+== style zig-open grid=150x31
+|0: 0-70 #b2c3b8,#1d2824, 71-149 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-74 d,#26362d, 75-99 #b2c3b8,#1d2824, 100-149 d,#1d2824,
+|2: 0-1 #ffffff,#4c6356, 2-71 #b2c3b8,#1d2824, 72-74 d,#1d2824, 75-76 #ffffff,#4c6356, 77-146 #b2c3b8,#1d2824, 147-149 d,#1d2824,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|5: 0-0 d,#637f6a, 1-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|6: 0-1 #000000,#adcc91, 2-59 #becfc4,#26362d, 60-74 d,#26362d, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-18 #e5eee5,#0d1410, 19-25 #c9b0e4,#0d1410, 26-26 #e5eee5,#0d1410, 27-31 #b6ce94,#0d1410, 32-34 #e5eee5,#0d1410, 35-42 #b9e58f,#0d1410, 43-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-12 #c9b0e4,#0d1410, 13-26 #e5eee5,#0d1410, 27-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-23 #e5eee5,#0d1410, 24-25 #e9bf91,#0d1410, 26-26 #e5eee5,#0d1410, 27-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-16 #e5eee5,#0d1410, 17-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-7 #e5eee5,#0d1410, 8-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|17: 0-1 #ffffff,#4c6356, 2-71 #b2c3b8,#1d2824, 72-74 d,#1d2824, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|20: 0-0 d,#637f6a, 1-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+== style colors-off grid=150x31
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-3 #e5eee5,#0d1410, 4-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-78 #e5eee5,#0d1410, 79-149 d,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-9 #e5eee5,#0d1410, 10-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-84 #e5eee5,#0d1410, 85-149 d,#0d1410,
+|6: 0-1 #000000,#adcc91, 2-59 #becfc4,#26362d, 60-74 d,#26362d, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-42 #e5eee5,#0d1410, 43-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-26 #e5eee5,#0d1410, 27-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-26 #e5eee5,#0d1410, 27-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-16 #e5eee5,#0d1410, 17-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-7 #e5eee5,#0d1410, 8-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|17: 0-1 #ffffff,#4c6356, 2-71 #b2c3b8,#1d2824, 72-74 d,#1d2824, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-3 #e5eee5,#0d1410, 4-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-9 #e5eee5,#0d1410, 10-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|20: 0-0 d,#637f6a, 1-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|21: 0-0 d,#637f6a, 1-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|22: 0-0 d,#637f6a, 1-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|23: 0-0 d,#637f6a, 1-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|24: 0-0 d,#637f6a, 1-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|25: 0-0 d,#637f6a, 1-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|26: 0-0 d,#637f6a, 1-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|27: 0-0 d,#637f6a, 1-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|28: 0-0 d,#637f6a, 1-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|29: 0-0 d,#637f6a, 1-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+|30: 0-0 d,#637f6a, 1-74 d,#0d1410, 75-75 d,#637f6a, 76-149 d,#0d1410,
+== style colors-on grid=150x31
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|6: 0-1 #000000,#adcc91, 2-59 #becfc4,#26362d, 60-74 d,#26362d, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-18 #e5eee5,#0d1410, 19-25 #c9b0e4,#0d1410, 26-26 #e5eee5,#0d1410, 27-31 #b6ce94,#0d1410, 32-34 #e5eee5,#0d1410, 35-42 #b9e58f,#0d1410, 43-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-10 #e5eee5,#0d1410, 11-12 #c9b0e4,#0d1410, 13-26 #e5eee5,#0d1410, 27-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-23 #e5eee5,#0d1410, 24-25 #e9bf91,#0d1410, 26-26 #e5eee5,#0d1410, 27-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-16 #e5eee5,#0d1410, 17-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-7 #e5eee5,#0d1410, 8-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|17: 0-1 #ffffff,#4c6356, 2-71 #b2c3b8,#1d2824, 72-74 d,#1d2824, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|20: 0-0 d,#637f6a, 1-74 d,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-74 #e5eee5,#0d1410, 75-75 d,#637f6a, 76-76 d,#0d1410, 77-149 #e5eee5,#0d1410,
diff --git a/test/snapshots/syntax.snap b/test/snapshots/syntax.snap
index d660fdd9..aae49c1b 100644
--- a/test/snapshots/syntax.snap
+++ b/test/snapshots/syntax.snap
@@ -1,18 +1,18 @@
# tree-sitter: open a .zig file, keyword/string/number/comment colors on;
# Colors off (SPC t c) clears them; edit re-highlights
file demo.zig const std = @import("std"); // greet\npub fn main() void {\n var x: u32 = 42;\n _ = x;\n}
-start 30 150 -n 3
+start 31 150 -n 3
wait 8000 demo.zig
stable 700 20000
-press left 5 8
-release left 5 8
+press left 5 9
+release left 5 9
stable 400 5000
key i
text demo.zig
key esc
settle 100
-press right 6 8
-release right 6 8
+press right 6 9
+release right 6 9
wait 10000 @import
stable 700 15000
snap zig-open
diff --git a/test/snapshots/tag.golden b/test/snapshots/tag.golden
index cea7fdb1..abc83b8f 100644
--- a/test/snapshots/tag.golden
+++ b/test/snapshots/tag.golden
@@ -1,6 +1,7 @@
-== snap tag-focus grid=150x30 cursor=27,1
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/tag/cwd Save New Newtty Del Filter /tmp/pardes-snap/tag/cwd Save New Newtty Del Filter
+== snap tag-focus grid=150x31 cursor=26,2
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/tag/cwd Save Tty Del Togglettymode Filter Collapse /tmp/pardes-snap/tag/cwd Save Tty Del Togglettymode Filter Collapse
| ls ls
| t.txt t.txt
|
@@ -15,19 +16,15 @@
|
|
|
-| /tmp/pardes-snap/tag/cwd Save New Newtty Del Filter
+| /tmp/pardes-snap/tag/cwd Save Tty Del Togglettymode Filter Collapse
| ls
| t.txt
-== snap tag-typed grid=150x30 cursor=33,1
-|1: /tmp/pardes-snap/tag/cwd t.txt Save New Newtty Del Filter /tmp/pardes-snap/tag/cwd Save New Newtty Del Filter
-== snap tag-del grid=150x30 cursor=29,1
-|1: /tmp/pardes-snap/tag/cwd t Save New Newtty Del Filter /tmp/pardes-snap/tag/cwd Save New Newtty Del Filter
-== snap tag-exit grid=150x30 cursor=4,4
-|1: /tmp/pardes-snap/tag/cwd t.txt Save New Newtty Del Filter /tmp/pardes-snap/tag/cwd Save New Newtty Del Filter
-== snap tag-look grid=150x30 cursor=7,2
-|1: /tmp/pardes-snap/tag/cwd/t.txt Save New Newtty Del /tmp/pardes-snap/tag/cwd Save New Newtty Del Filter
-|2: 1 ZZLOOKED ls
-|3: t.txt
-|8: /tmp/pardes-snap/tag/cwd t.txt Save New Newtty Del Filter
-|9: ls
-|10: t.txt
+== snap tag-typed grid=150x31 cursor=32,2
+|2: /tmp/pardes-snap/tag/cwd t.txt Save Tty Del Togglettymode Filter Collapse /tmp/pardes-snap/tag/cwd Save Tty Del Togglettymode Filter Collapse
+== snap tag-del grid=150x31 cursor=28,2
+|2: /tmp/pardes-snap/tag/cwd t Save Tty Del Togglettymode Filter Collapse /tmp/pardes-snap/tag/cwd Save Tty Del Togglettymode Filter Collapse
+== snap tag-exit grid=150x31 cursor=4,5
+|2: /tmp/pardes-snap/tag/cwd t.txt Save Tty Del Togglettymode Filter Collapse /tmp/pardes-snap/tag/cwd Save Tty Del Togglettymode Filter Collapse
+== snap tag-look grid=150x31 cursor=7,7
+|6: /tmp/pardes-snap/tag/cwd/t.txt Save Tty Del Collapse
+|7: 1 ZZLOOKED
diff --git a/test/snapshots/tag.snap b/test/snapshots/tag.snap
index f37b2ac7..a545ff9f 100644
--- a/test/snapshots/tag.snap
+++ b/test/snapshots/tag.snap
@@ -3,22 +3,17 @@
# looks the word at the cursor (Tab executes it). Multi-word execution from
# the tag stays the mouse's job (middle-drag), like anywhere else.
file t.txt ZZLOOKED
-start 30 150 -n 3
+start 31 150 -n 3
wait 8000 t.txt
stable 700 20000
-# click into the tag tail of pane 0: straight into insert. `@Save-2` is two
-# columns left of the first builtin - inside the gap that right-aligns them,
-# ordinary spaces in the tag, so this is the tail like any other part of it.
-# Anchored on the builtins rather than on a column or on the path, because the
-# builtins are the side that MOVES: one more builtin word slides them left and
-# a frozen column 28 (or a `@cwd+4`, which is the same fixed column, since the
-# path is left-anchored) would land on `Save` instead of in the gap.
+# Click the one editable separator before Save, directly after the cwd.
+# The former generated alignment gap no longer exists.
# The layout box shows
# the pane's BODY mode, not the tag's, so the evidence for "this click went to
# insert" is the next step — the typed text lands as text instead of running as
# normal-mode commands.
-press left @Save-2 2
-release left @Save-2 2
+press left @Save-1 3
+release left @Save-1 3
stable 400 5000
snap tag-focus
send \x20t.txt
@@ -40,11 +35,9 @@ settle 100
stable 400 5000
snap tag-exit
# re-enter the tag and look the typed word: Enter opens t.txt as a file pane.
-# Clicked ON the word itself rather than past the end of the tag and walked
-# back into it — the builtins are right-aligned (config.tag_right_pad), so the
-# tag no longer ends where the typing does and a click past it lands in the gap.
-press left @t.txt 2
-release left @t.txt 2
+# Click the inserted word itself; filename, separator and commands are compact.
+press left @t.txt 3
+release left @t.txt 3
stable 400 5000
key enter
wait 10000 ZZLOOKED
diff --git a/test/snapshots/tagalign.golden b/test/snapshots/tagalign.golden
index a37ecefc..eaed8e2e 100644
--- a/test/snapshots/tagalign.golden
+++ b/test/snapshots/tagalign.golden
@@ -1,6 +1,7 @@
-== snap aligned grid=100x30 cursor=4,19
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/tagalign/cwd/deep/nested-project-directory/document.txt Save New Newtty Del
+== snap aligned grid=100x31 cursor=4,20
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/tagalign/cwd/deep/nested-project-directory/document.txt Save Tty Del Collapse
| 1 alpha
| 2 beta
| 3 gamma
@@ -15,12 +16,13 @@
|
|
|
-| /tmp/pardes-snap/tagalign/cwd Save New Newtty Del Filter
+| /tmp/pardes-snap/tagalign/cwd Save Tty Del Togglettymode Filter Collapse
| ls
| deep
-== snap fits grid=87x30 cursor=4,19
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/tagalign/cwd/deep/nested-project-directory/document.txt Save New New
+== snap fits grid=87x31 cursor=4,20
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/tagalign/cwd/deep/nested-project-directory/document.txt Save Tty Del
| 1 alpha
| 2 beta
| 3 gamma
@@ -35,12 +37,13 @@
|
|
|
-| /tmp/pardes-snap/tagalign/cwd Save New Newtty Del Filter
+| /tmp/pardes-snap/tagalign/cwd Save Tty Del Togglettymode Filter Collapse
| ls
| deep
-== snap overby1 grid=86x30 cursor=4,19
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/tagalign/cwd/deep/nested-project-directory/document.txt Save New Ne
+== snap overby1 grid=86x31 cursor=4,20
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/tagalign/cwd/deep/nested-project-directory/document.txt Save Tty De
| 1 alpha
| 2 beta
| 3 gamma
@@ -55,12 +58,13 @@
|
|
|
-| /tmp/pardes-snap/tagalign/cwd Save New Newtty Del Filter
+| /tmp/pardes-snap/tagalign/cwd Save Tty Del Togglettymode Filter Collapse
| ls
| deep
-== snap clicked grid=100x30 cursor=11,1
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/tagalign/cwd/deep/nested-project-directory/document.txt Save New Newtty Del
+== snap clicked grid=100x31 cursor=11,2
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/tagalign/cwd/deep/nested-project-directory/document.txt Save Tty Del Collapse
| 1 alpha
| 2 beta
| 3 gamma
@@ -75,14 +79,35 @@
|
|
|
-| /tmp/pardes-snap/tagalign/cwd Save New Newtty Del Filter
+| /tmp/pardes-snap/tagalign/cwd Save Tty Del Togglettymode Filter Collapse
| ls
| deep
-== snap alone grid=100x30 cursor=4,4
-|1: /tmp/pardes-snap/tagalign/cwd Save New Newtty Del Filter
-|2: ls
-|3: deep
-|4:
-|16:
+== snap revealed grid=70x31 cursor=69,2
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kil
+|New Tty Find Grep Joincol
+| wd/deep/nested-project-directory/document.txt Save Tty Del Collapse
+| 1 alpha
+| 2 beta
+| 3 gamma
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+|
+| /tmp/pardes-snap/tagalign/cwd Save Tty Del Togglettymode Filter Coll
+| ls
+| deep
+== snap alone grid=70x31 cursor=4,5
+|2: /tmp/pardes-snap/tagalign/cwd Save Tty Del Togglettymode Filter Coll
+|3: ls
+|4: deep
+|5:
|17:
|18:
+|19:
diff --git a/test/snapshots/tagalign.snap b/test/snapshots/tagalign.snap
index 0d2cad12..9df22f57 100644
--- a/test/snapshots/tagalign.snap
+++ b/test/snapshots/tagalign.snap
@@ -1,53 +1,33 @@
-# The command words of every pane in a LAYOUT COLUMN end at the same screen
-# column. tag_right_pad sets that end, but a path too long to fit inside the
-# pad used to collapse its own gap alone, so one row's New/Del sat hard against
-# its path while the row below it kept its own out at the pad — two ragged
-# columns of words you read (and click) down.
-#
-# Here the file's path is 43 columns longer than the shell's cwd, and long
-# enough (85 of the pane's 98 columns) that its own gap is zero. The shell
-# below it moves out to the file's end instead of the pad's, so both rows spell
-# New and Del in the same two places.
+# Compact commands stay beside their own prefix regardless of sibling length.
dirmk deep
dirmk deep/nested-project-directory
file deep/nested-project-directory/document.txt alpha\nbeta\ngamma
-start 30 100 deep/nested-project-directory/document.txt
-wait 8000 New Newcol
+start 31 100 deep/nested-project-directory/document.txt
+wait 8000 Newcol Joincol
wait 8000 document.txt
stable 700 20000
-# Alt-n: a shell BELOW the file, in the same column
key a-n
stable 700 15000
snap aligned
-# A pane whose tag does not FIT is counted AT its right edge rather than
-# dropped from the vote. Dropping it would be a threshold: here the file's tag
-# is 85 columns, so one column of resize either side of that would move BOTH
-# rows of words by the whole pad, and dragging a window edge across the width
-# would snap them back and forth under the pointer. 87 -> 86 moves them one
-# column, and the file's own tag is the only thing that loses a character.
-resize 30 87
+# Clipping never changes underlying tag text or shorter siblings' positions.
+resize 31 87
stable 400 5000
snap fits
-resize 30 86
+resize 31 86
stable 400 5000
snap overby1
-resize 30 100
+resize 31 100
stable 700 15000
-# A left click on a tagline SEEDS its tail: the gap stops being computed and
-# becomes ordinary characters you own. It must not stop the pane VOTING —
-# this clicks the FILE's path, and the file is the widest tag in the column,
-# the one holding the end out. The shell's row below must not move a column
-# (it did once: every other tagline in the column snapped left on the click,
-# and a middle-click that used to hit Del landed on whitespace).
-press left 12 2
-release left 12 2
+press left 12 3
+release left 12 3
stable 400 5000
snap clicked
-# ...and proving that with the words themselves. Where Del SITS is asserted by
-# the two snaps above; this step clicks it. It closes the file, so the shell is alone in the column
-# and falls back to tag_right_pad short of its own edge — the shared end is
-# the LIVE widest, not a high-water mark.
-press middle @Del 2
-release middle @Del 2
+# End reveals the complete command suffix; a scrolled Del still executes.
+resize 31 70
+key end
+stable 400 5000
+snap revealed
+press middle @Del 3
+release middle @Del 3
stable 700 15000
snap alone
diff --git a/test/snapshots/tagalign2col.golden b/test/snapshots/tagalign2col.golden
index bb01c1e6..cef20c73 100644
--- a/test/snapshots/tagalign2col.golden
+++ b/test/snapshots/tagalign2col.golden
@@ -1,19 +1,20 @@
-== snap onecol grid=160x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/tagalign2col/cwd/deep/proj/document.txt Save New Newtty Del /tmp/pardes-snap/tagalign2col/cwd Save New Newtty Del Filter
+== snap onecol grid=160x31 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/tagalign2col/cwd/deep/proj/document.txt Save Tty Del Collapse /tmp/pardes-snap/tagalign2col/cwd Save Tty Del Togglettymode Filter Collapse
| 1 alpha ls
| 2 beta deep
| 3 gamma
-== snap aligned grid=160x30 cursor=4,19
-|16: /tmp/pardes-snap/tagalign2col/cwd Save New Newtty Del Filter
-|17: ls
-|18: deep
-== snap widened grid=160x30 cursor=4,19
-|1: /tmp/pardes-snap/tagalign2col/cwd/deep/proj/document.txt Save New Newtty Del ╎ /tmp/pardes-snap/tagalign2col/cwd Save New Newtty Del Filt
-|2: 1 alpha ╎ ls
-|3: 2 beta ╎ deep
-|4: 3 gamma ╎
-|5: ╎
+== snap aligned grid=160x31 cursor=4,20
+|17: /tmp/pardes-snap/tagalign2col/cwd Save Tty Del Togglettymode Filter Collapse
+|18: ls
+|19: deep
+== snap widened grid=160x31 cursor=4,20
+|1: New Tty Find Grep Joincol ╎New Tty Find Grep Joincol
+|2: /tmp/pardes-snap/tagalign2col/cwd/deep/proj/document.txt Save Tty Del Collapse ╎ /tmp/pardes-snap/tagalign2col/cwd Save Tty Del Togglettymo
+|3: 1 alpha ╎ ls
+|4: 2 beta ╎ deep
+|5: 3 gamma ╎
|6: ╎
|7: ╎
|8: ╎
@@ -24,10 +25,10 @@
|13: ╎
|14: ╎
|15: ╎
-|16: /tmp/pardes-snap/tagalign2col/cwd Save New Newtty Del Filter ╎
-|17: ls ╎
-|18: deep ╎
-|19: ╎
+|16: ╎
+|17: /tmp/pardes-snap/tagalign2col/cwd Save Tty Del Togglettymode Filter Collapse ╎
+|18: ls ╎
+|19: deep ╎
|20: ╎
|21: ╎
|22: ╎
@@ -38,3 +39,4 @@
|27: ╎
|28: ╎
|29: ╎
+|30: ╎
diff --git a/test/snapshots/tagalign2col.snap b/test/snapshots/tagalign2col.snap
index 56048c8b..0849ffae 100644
--- a/test/snapshots/tagalign2col.snap
+++ b/test/snapshots/tagalign2col.snap
@@ -1,47 +1,25 @@
-# The shared tail-end is scoped to a LAYOUT COLUMN. tagalign.snap proves the
-# sharing but only ever has one column, so nothing there would notice a vote
-# that leaked sideways: every pane in the window would still line up, and the
-# feature would look like it worked right up until you opened a second column.
-#
-# Here the long path is in the LEFT column (that is which side it lands on:
-# Alt-c puts the NEW column on the right, so the boot file keeps the left)
-# and the right column is a plain shell. Both columns are 80 wide, so both
-# would end their words at tag_right_pad — 58 columns in — if nothing pushed.
+# Each compact command run follows its own prefix, never a neighboring path.
dirmk deep
dirmk deep/proj
file deep/proj/document.txt alpha\nbeta\ngamma
-start 30 160 deep/proj/document.txt
-wait 8000 New Newcol
+start 31 160 deep/proj/document.txt
+wait 8000 Newcol Joincol
wait 8000 document.txt
stable 700 20000
-# Alt-n then Alt-c: a shell in a column of its own on the right (`New`/`Newcol`
-# open an empty +New scratch now, not a shell). Two columns, one pane each. The
-# file's own tag is 69 columns and so pushes past its column's pad; the shell on
-# the right sits AT its pad, 58 in. Read the two ends off this snap — they are
-# what the next one must not disturb.
+# A shell in a separate right-hand column.
key a-n
key a-c
stable 700 15000
key space w h
stable 400 5000
snap onecol
-# Alt-n: a second pane in the LEFT column. It is 48 columns of tag and would
-# right-align at 58 on its own; the file above it drags it out to 69 instead.
-# THE ASSERTION: the right column's `New Del Filter` has not moved a cell — same
-# absolute column as in `onecol`, still at its own pad — while the left
-# column's two rows now agree with each other at 69.
+# A left sibling does not move either existing tag's command text.
key a-n
stable 700 15000
snap aligned
-# ...and the ends are computed per column, not once for the window. Drag the
-# vertical border 20 columns right: the left column grows to 100 (tw-pad 78 is
-# now past the file's 69, so its pad binds again and both left rows move OUT to
-# 78) and the right column shrinks to 60 (tw-pad 38 is now short of the shell's
-# own 48, so its words fall back hard against the path at 48). Two different
-# rules firing in the same frame, one per column — a single window-wide end
-# could not produce this grid at all.
-press left 80 10
-drag left 100 10
-release left 100 10
+# Resizing moves the right column as a whole and clips without hidden spaces.
+press left 80 11
+drag left 100 11
+release left 100 11
stable 700 15000
snap widened
diff --git a/test/snapshots/tagbottom.golden b/test/snapshots/tagbottom.golden
index 8aa4ce5c..f455c425 100644
--- a/test/snapshots/tagbottom.golden
+++ b/test/snapshots/tagbottom.golden
@@ -1,6 +1,7 @@
-== snap boot grid=100x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/tagbottom/cwd/top.txt Save New Newtty Del
+== snap boot grid=100x31 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/tagbottom/cwd/top.txt Save Tty Del Collapse
| 1 aaa
| 2 bbb
| 3 ccc
@@ -27,37 +28,7 @@
| 24 xxx
| 25 yyy
| 26 zzz
-== snap on grid=100x30 cursor=7,1
-|1: 1 aaa
-|2: 2 bbb
-|3: 3 ccc
-|4: 4 ddd
-|5: 5 eee
-|6: 6 fff
-|7: 7 ggg
-|8: 8 hhh
-|9: 9 iii
-|10: 10 jjj
-|11: 11 kkk
-|12: 12 lll
-|13: 13 mmm
-|14: 14 nnn
-|15: 15 ooo
-|16: 16 ppp
-|17: 17 qqq
-|18: 18 rrr
-|19: 19 sss
-|20: 20 ttt
-|21: 21 uuu
-|22: 22 vvv
-|23: 23 www
-|24: 24 xxx
-|25: 25 yyy
-|26: 26 zzz
-|27:
-|29: /tmp/pardes-snap/tagbottom/cwd/top.txt Save New Newtty Del
-== snap off grid=100x30 cursor=7,2
-|1: /tmp/pardes-snap/tagbottom/cwd/top.txt Save New Newtty Del
+== snap on grid=100x31 cursor=7,2
|2: 1 aaa
|3: 2 bbb
|4: 3 ccc
@@ -84,41 +55,70 @@
|25: 24 xxx
|26: 25 yyy
|27: 26 zzz
-|29:
-== snap tag-typed grid=100x30 cursor=60,29
-|1: 1 aaa
-|2: 2 bbb
-|3: 3 ccc
-|4: 4 ddd
-|5: 5 eee
-|6: 6 fff
-|7: 7 ggg
-|8: 8 hhh
-|9: 9 iii
-|10: 10 jjj
-|11: 11 kkk
-|12: 12 lll
-|13: 13 mmm
-|14: 14 nnn
-|15: 15 ooo
-|16: 16 ppp
-|17: 17 qqq
-|18: 18 rrr
-|19: 19 sss
-|20: 20 ttt
-|21: 21 uuu
-|22: 22 vvv
-|23: 23 www
-|24: 24 xxx
-|25: 25 yyy
-|26: 26 zzz
-|27:
-|29: /tmp/pardes-snap/tagbottom/cwd/top.txt bottom.txt Save New Newtty Del
-== snap look-bottom-tag grid=100x30 cursor=7,16
-|15: /tmp/pardes-snap/tagbottom/cwd/top.txt bottom.txt Save New Newtty Del
-|16: 1 ZZONE
-|17: 2 ZZTWO
-|18:
+|28:
+|30: /tmp/pardes-snap/tagbottom/cwd/top.txt Save Tty Del Collapse
+== snap off grid=100x31 cursor=7,3
+|2: /tmp/pardes-snap/tagbottom/cwd/top.txt Save Tty Del Collapse
+|3: 1 aaa
+|4: 2 bbb
+|5: 3 ccc
+|6: 4 ddd
+|7: 5 eee
+|8: 6 fff
+|9: 7 ggg
+|10: 8 hhh
+|11: 9 iii
+|12: 10 jjj
+|13: 11 kkk
+|14: 12 lll
+|15: 13 mmm
+|16: 14 nnn
+|17: 15 ooo
+|18: 16 ppp
+|19: 17 qqq
+|20: 18 rrr
+|21: 19 sss
+|22: 20 ttt
+|23: 21 uuu
+|24: 22 vvv
+|25: 23 www
+|26: 24 xxx
+|27: 25 yyy
+|28: 26 zzz
+|30:
+== snap tag-typed grid=100x31 cursor=60,30
+|2: 1 aaa
+|3: 2 bbb
+|4: 3 ccc
+|5: 4 ddd
+|6: 5 eee
+|7: 6 fff
+|8: 7 ggg
+|9: 8 hhh
+|10: 9 iii
+|11: 10 jjj
+|12: 11 kkk
+|13: 12 lll
+|14: 13 mmm
+|15: 14 nnn
+|16: 15 ooo
+|17: 16 ppp
+|18: 17 qqq
+|19: 18 rrr
+|20: 19 sss
+|21: 20 ttt
+|22: 21 uuu
+|23: 22 vvv
+|24: 23 www
+|25: 24 xxx
+|26: 25 yyy
+|27: 26 zzz
+|28:
+|30: /tmp/pardes-snap/tagbottom/cwd/top.txt Save Tty bottom.txt Del Collapse
+== snap look-bottom-tag grid=100x31 cursor=7,17
+|16: /tmp/pardes-snap/tagbottom/cwd/top.txt Save Tty bottom.txt Del Collapse
+|17: 1 ZZONE
+|18: 2 ZZTWO
|19:
|20:
|21:
@@ -127,44 +127,45 @@
|24:
|25:
|26:
-|29: /tmp/pardes-snap/tagbottom/cwd/bottom.txt Save New Newtty Del
-== snap body-cursor grid=100x30 cursor=9,5
-== snap seam-noop grid=100x30 cursor=9,5
-== snap seam-dragged grid=100x30 cursor=9,5
-|10: /tmp/pardes-snap/tagbottom/cwd/top.txt bottom.txt Save New Newtty Del
-|11: 1 ZZONE
-|12: 2 ZZTWO
-|13:
+|27:
+|30: /tmp/pardes-snap/tagbottom/cwd/bottom.txt Save Tty Del Collapse
+== snap body-cursor grid=100x31 cursor=9,6
+== snap seam-noop grid=100x31 cursor=9,6
+== snap seam-dragged grid=100x31 cursor=9,6
+|11: /tmp/pardes-snap/tagbottom/cwd/top.txt Save Tty bottom.txt Del Collapse
+|12: 1 ZZONE
+|13: 2 ZZTWO
|14:
|15:
|16:
|17:
-== snap gutter-click grid=100x30 cursor=9,4
-|1: 2 bbb
-|2: 3 ccc
-|3: 4 ddd
-|4: 5 eee
-|5: 6 fff
-|6: 7 ggg
-|7: 8 hhh
-|8: 9 iii
-|9: 10 jjj
-== snap search-prompt grid=100x30 cursor=6,28
-|28: /ZZ
-== snap leader grid=100x30 cursor=9,13
-|28: SPC
-== snap cut-down grid=100x30 cursor=7,4
-|1: 1 aaa
+|18:
+== snap gutter-click grid=100x31 cursor=9,5
|2: 2 bbb
|3: 3 ccc
-|4: 4 jj
-|5: 5 kkk
-|6: 6 lll
-|7: 7 mmm
-|8: 8 nnn
-|9: 9 ooo
-|10: /tmp/pardes-snap/tagbottom/cwd/top.txt * bottom.txt Save New Newtty Del
-|28:
+|4: 4 ddd
+|5: 5 eee
+|6: 6 fff
+|7: 7 ggg
+|8: 8 hhh
+|9: 9 iii
+|10: 10 jjj
+== snap search-prompt grid=100x31 cursor=6,29
+|29: /ZZ
+== snap leader grid=100x31 cursor=9,14
+|29: SPC
+== snap cut-down grid=100x31 cursor=7,5
+|2: 1 aaa
+|3: 2 bbb
+|4: 3 ccc
+|5: 4 jj
+|6: 5 kkk
+|7: 6 lll
+|8: 7 mmm
+|9: 8 nnn
+|10: 9 ooo
+|11: /tmp/pardes-snap/tagbottom/cwd/top.txt * Save Tty bottom.txt Del Collapse
+|29:
== file cut-buffer
aaa
bbb
@@ -187,30 +188,7 @@ xxx
yyy
zzz
== end file
-== snap del-bottom-tag grid=100x30 cursor=7,4
-|10: 10 ppp
-|11: 11 qqq
-|12: 12 rrr
-|13: 13 sss
-|14: 14 ttt
-|15: 15 uuu
-|16: 16 vvv
-|17: 17 www
-|18: 18 xxx
-|19: 19 yyy
-|20: 20 zzz
-|29: /tmp/pardes-snap/tagbottom/cwd/top.txt bottom.txt Save New Newtty Del
-== snap off-again grid=100x30 cursor=7,5
-|1: /tmp/pardes-snap/tagbottom/cwd/top.txt bottom.txt Save New Newtty Del
-|2: 1 aaa
-|3: 2 bbb
-|4: 3 ccc
-|5: 4 jj
-|6: 5 kkk
-|7: 6 lll
-|8: 7 mmm
-|9: 8 nnn
-|10: 9 ooo
+== snap del-bottom-tag grid=100x31 cursor=7,5
|11: 10 ppp
|12: 11 qqq
|13: 12 rrr
@@ -222,4 +200,27 @@ zzz
|19: 18 xxx
|20: 19 yyy
|21: 20 zzz
-|29:
+|30: /tmp/pardes-snap/tagbottom/cwd/top.txt Save Tty bottom.txt Del Collapse
+== snap off-again grid=100x31 cursor=7,6
+|2: /tmp/pardes-snap/tagbottom/cwd/top.txt Save Tty bottom.txt Del Collapse
+|3: 1 aaa
+|4: 2 bbb
+|5: 3 ccc
+|6: 4 jj
+|7: 5 kkk
+|8: 6 lll
+|9: 7 mmm
+|10: 8 nnn
+|11: 9 ooo
+|12: 10 ppp
+|13: 11 qqq
+|14: 12 rrr
+|15: 13 sss
+|16: 14 ttt
+|17: 15 uuu
+|18: 16 vvv
+|19: 17 www
+|20: 18 xxx
+|21: 19 yyy
+|22: 20 zzz
+|30:
diff --git a/test/snapshots/tagbottom.snap b/test/snapshots/tagbottom.snap
index 57b6e749..a6a7a882 100644
--- a/test/snapshots/tagbottom.snap
+++ b/test/snapshots/tagbottom.snap
@@ -17,8 +17,8 @@
# exactly: `off` is byte-for-byte `boot`, cursor included.
file top.txt aaa\nbbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\nmmm\nnnn\nooo\nppp\nqqq\nrrr\nsss\nttt\nuuu\nvvv\nwww\nxxx\nyyy\nzzz
file bottom.txt ZZONE\nZZTWO
-start 30 100 top.txt
-wait 8000 New Newcol
+start 31 100 top.txt
+wait 8000 Newcol Joincol
wait 8000 top.txt
stable 700 20000
snap boot
@@ -38,8 +38,8 @@ stable 700 15000
# cursor is down on the tagline with it. Col 50 is past the end of the path,
# which is read-only — a click inside it parks the cursor there and the typing
# goes nowhere.
-press left 50 30
-release left 50 30
+press left 50 31
+release left 50 31
stable 400 5000
send \x20bottom.txt
stable 600 8000
@@ -48,31 +48,31 @@ snap tag-typed
# ...and LOOK the word just typed, from that same bottom tagline: bottom.txt
# opens as a second pane below. It only can if the press was mapped to the tag
# — mapped as a body row it lands on blank line 29 and looks nothing at all.
-press right 55 30
-release right 55 30
+press right 55 31
+release right 55 31
wait 10000 ZZONE
stable 700 15000
snap look-bottom-tag
# a body click in the UPPER pane: the cursor lands on the row under the
# pointer, counted from the pane's first row rather than from a tag that is no
# longer there. Row 6 is grid row 5, the fifth body row, file line 5.
-press left 10 6
-release left 10 6
+press left 10 7
+release left 10 7
stable 400 8000
snap body-cursor
# The h-resize seam. With top taglines it is the upper pane's LAST row; here
# that row is the upper pane's TAG, so the handle is the lower pane's FIRST row
# (grid 16, click row 17). A no-drag click on it must leave both sizes alone.
-press left 40 17
-release left 40 17
+press left 40 18
+release left 40 18
motion 40 25
stable 500 8000
snap seam-noop
# ...and the real drag, five rows up: the upper pane keeps 10 rows, the lower
# grows to 19. Both taglines follow their own pane's bottom.
-press left 40 17
-drag left 40 12
-release left 40 12
+press left 40 18
+drag left 40 13
+release left 40 13
motion 40 25
stable 500 8000
snap seam-dragged
@@ -91,8 +91,8 @@ stable 400 8000
# counts from is the BODY's first, not r.y + BOX_H. Row 4 is grid row 3, the
# third body row: two rows up, to line 2. Counted from the wrong end it would
# be one row up, to line 3.
-press left 1 4
-release left 1 4
+press left 1 5
+release left 1 5
stable 400 8000
snap gutter-click
# `/` in the lower pane's body arms the search input. The prompt is CUT off the
@@ -100,8 +100,8 @@ snap gutter-click
# two are adjacent: the tail keeps its builtins on row 29 while `/ZZ` and the
# cursor sit on row 28, the last body row. The tagline under it stays whole —
# the prompt must not have eaten the row it was cut from.
-press left 10 14
-release left 10 14
+press left 10 15
+release left 10 15
stable 400 5000
key /
send ZZ
@@ -124,15 +124,15 @@ stable 400 5000
# of Sel space: the highlight jumps ABOVE the anchor and a 1-2 Cut deletes lines
# nobody swept. Anchored on grid row 3 (file line 4) and dragged onto the upper
# pane's tag row, the sweep must cover lines 4..10 downward, not 2..4 upward.
-press left 8 4
-drag left 8 11
+press left 8 5
+drag left 8 12
stable 400 5000
# ...and the proof is the BUFFER, not the highlight: 1-2 Cut the sweep, save,
# and read the file back. aaa/bbb/ccc survive and kkk..zzz survive; unclamped
# this file lost bbb/ccc/ddd instead and kept eee onward.
-press middle 8 11
-release middle 8 11
-release left 8 11
+press middle 8 12
+release middle 8 12
+release left 8 12
stable 400 5000
snap cut-down
key space f s
@@ -141,8 +141,8 @@ snapfile cut-buffer /tmp/pardes-snap/tagbottom/cwd/top.txt
# EXECUTE `Del` on the lower pane's bottom tagline: the pane goes away and the
# upper one takes the whole column back. The middle button's half of the same
# tag mapping the look used above.
-press middle @Del 30
-release middle @Del 30
+press middle @Del 31
+release middle @Del 31
stable 700 15000
snap del-bottom-tag
# and off again, one pane, its tagline back on row 1 with the body under it
diff --git a/test/snapshots/tagbottomimage.golden b/test/snapshots/tagbottomimage.golden
index 01a48012..523dd27c 100644
--- a/test/snapshots/tagbottomimage.golden
+++ b/test/snapshots/tagbottomimage.golden
@@ -1,88 +1,103 @@
-== snap img-top grid=150x30 cursor=11,7
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| img petscii:off palette:commodore ascii:on /tmp/pardes-snap/tagbottomimage/cwd/pic.ppm New Newtty Del
-| 9d4🬫▚{▙v]O*🬥🬣n🬍🬕5S6#4🬵C[🬆🬻
-| {🬲🬍s🬕/*%!🬖🬹╱?🬷C🬔3q🬗]Q┼🬆🬹
-| }=^!t🬺R'My┼▐jP▞🬡y}▄V🬆~
-| 6(9?🬝🬳J1🬢k?g🬶🬙SY%t🬆▄█
-| ╲Ep^w🬪2zJbxF&🬷🬦a🬝~
-| 🬥K`🬙🬲$'#3x(▜🬌a▛🬹
-| zj🬡{U🬨(j🬗🬔E[▛🬹█
-| 🬺🬊*V*]g^🬳p▀🬹
-| [;🬬/M🬊🬲🬻🬆🬻
-| │🬕r🬜┼e🬆🬻
-| [🬝g4🬆🬹
-| 🬐🬹🬆🬹
-| 🬎🬻█
-| /tmp/pardes-snap/tagbottomimage/cwd Save New Newtty Del Filter
+== snap img-top grid=150x31 cursor=11,8
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/tagbottomimage/cwd Save Tty Del Togglettymode Filter Collapse
| ls
| pic.ppm
|
-|
-|
-| pic.ppm
-== snap img-bottom grid=150x30 cursor=11,7
-|1: 9d4🬫▚{▙v]O*🬥🬣n🬍🬕5S6#4🬵C[🬆🬻
-|2: {🬲🬍s🬕/*%!🬖🬹╱?🬷C🬔3q🬗]Q┼🬆🬹
-|3: }=^!t🬺R'My┼▐jP▞🬡y}▄V🬆~
-|4: 6(9?🬝🬳J1🬢k?g🬶🬙SY%t🬆▄█
-|5: ╲Ep^w🬪2zJbxF&🬷🬦a🬝~
-|6: 🬥K`🬙🬲$'#3x(▜🬌a▛🬹
-|7: zj🬡{U🬨(j🬗🬔E[▛🬹█
-|8: 🬺🬊*V*]g^🬳p▀🬹
-|9: [;🬬/M🬊🬲🬻🬆🬻
-|10: │🬕r🬜┼e🬆🬻
-|11: [🬝g4🬆🬹
-|12: 🬐🬹🬆🬹
-|13: 🬎🬻█
-|14: img petscii:off palette:commodore ascii:on /tmp/pardes-snap/tagbottomimage/cwd/pic.ppm New Newtty Del
-|15: ls
-|16: pic.ppm
-|17:
-|20: pic.ppm
-|21:
-|29: /tmp/pardes-snap/tagbottomimage/cwd Save New Newtty Del Filter
-== style img-bottom grid=150x30
-|0: 0-74 #949494,#121212, 75-149 d,#121212,
-|1: 0-0 d,#121212, 1-62 d,#080808, 63-64 #959595,#6c6c6c, 65-66 #6c6c6c,#959595, 67-68 #959595,#6c6c6c, 69-69 #6c6c6c,#959595, 70-71 #959595,#6c6c6c, 72-72 #6c6c6c,#959595, 73-74 #959595,#6c6c6c, 75-76 #6c6c6c,#959595, 77-77 #959595,#6c6c6c, 78-78 #6c6c6c,#959595, 79-79 #959595,#6c6c6c, 80-80 #6c6c6c,#959595, 81-81 #959595,#6c6c6c, 82-82 #6c6c6c,#959595, 83-83 #959595,#6c6c6c, 84-84 #6c6c6c,#959595, 85-86 #959595,#6c6c6c, 87-87 #959595,#6c5eb5, 88-88 #352879,#959595, 89-149 d,#080808,
-|2: 0-0 d,#121212, 1-62 d,#080808, 63-64 #6c6c6c,#959595, 65-65 #959595,#6c6c6c, 66-67 #6c6c6c,#959595, 68-75 #959595,#6c6c6c, 76-81 #6c6c6c,#959595, 82-82 #959595,#6c6c6c, 83-83 #6c6c6c,#959595, 84-84 #959595,#6c6c6c, 85-85 #6c6c6c,#6c5eb5, 86-86 #352879,#6c5eb5, 87-88 #352879,#352879, 89-149 d,#080808,
-|3: 0-0 d,#121212, 1-62 d,#080808, 63-63 #6c6c6c,#959595, 64-66 #959595,#6c6c6c, 67-69 #6c6c6c,#959595, 70-71 #959595,#6c6c6c, 72-74 #6c6c6c,#959595, 75-77 #959595,#6c6c6c, 78-78 #6c6c6c,#959595, 79-82 #959595,#6c6c6c, 83-83 #959595,#6c5eb5, 84-84 #6c6c6c,#352879, 85-88 #352879,#352879, 89-149 d,#080808,
-|4: 0-0 d,#121212, 1-62 d,#080808, 63-67 #959595,#6c6c6c, 68-69 #6c6c6c,#959595, 70-73 #959595,#6c6c6c, 74-77 #6c6c6c,#959595, 78-79 #959595,#6c6c6c, 80-80 #6c6c6c,#959595, 81-81 #959595,#6c5eb5, 82-83 #352879,#6c5eb5, 84-88 #352879,#352879, 89-149 d,#080808,
-|5: 0-0 d,#121212, 1-62 d,#080808, 63-63 #959595,#6c6c6c, 64-64 #6c6c6c,#959595, 65-65 #959595,#6c6c6c, 66-66 #6c6c6c,#959595, 67-70 #959595,#6c6c6c, 71-72 #6c6c6c,#959595, 73-75 #959595,#6c6c6c, 76-78 #6c6c6c,#959595, 79-80 #6c6c6c,#352879, 81-88 #352879,#352879, 89-149 d,#080808,
-|6: 0-0 d,#121212, 1-62 d,#080808, 63-63 #6c6c6c,#959595, 64-65 #959595,#6c6c6c, 66-68 #6c6c6c,#959595, 69-69 #959595,#6c6c6c, 70-70 #6c6c6c,#959595, 71-73 #959595,#6c6c6c, 74-75 #6c6c6c,#959595, 76-76 #959595,#6c6c6c, 77-77 #6c6c6c,#352879, 78-78 #352879,#6c5eb5, 79-88 #352879,#352879, 89-149 d,#080808,
-|7: 0-0 d,#121212, 1-62 d,#080808, 63-64 #959595,#6c6c6c, 65-65 #6c6c6c,#959595, 66-67 #959595,#6c6c6c, 68-68 #6c6c6c,#959595, 69-69 #959595,#6c6c6c, 70-71 #6c6c6c,#959595, 72-73 #959595,#6c6c6c, 74-74 #6c6c6c,#959595, 75-75 #6c6c6c,#352879, 76-77 #352879,#6c5eb5, 78-88 #352879,#352879, 89-149 d,#080808,
-|8: 0-0 d,#121212, 1-62 d,#080808, 63-63 #6c6c6c,#959595, 64-68 #959595,#6c6c6c, 69-69 #6c6c6c,#959595, 70-70 #959595,#6c6c6c, 71-71 #6c6c6c,#959595, 72-72 #959595,#6c6c6c, 73-73 #6c6c6c,#6c5eb5, 74-74 #352879,#6c5eb5, 75-88 #352879,#352879, 89-149 d,#080808,
-|9: 0-0 d,#121212, 1-62 d,#080808, 63-64 #959595,#6c6c6c, 65-65 #6c6c6c,#959595, 66-66 #959595,#6c6c6c, 67-68 #6c6c6c,#959595, 69-69 #959595,#6c6c6c, 70-70 #6c6c6c,#959595, 71-71 #6c6c6c,#6c5eb5, 72-72 #352879,#6c6c6c, 73-88 #352879,#352879, 89-149 d,#080808,
-|10: 0-0 d,#121212, 1-62 d,#080808, 63-64 #6c6c6c,#959595, 65-65 #959595,#6c6c6c, 66-68 #6c6c6c,#959595, 69-69 #6c6c6c,#6c5eb5, 70-70 #352879,#6c6c6c, 71-88 #352879,#352879, 89-149 d,#080808,
-|11: 0-0 d,#121212, 1-62 d,#080808, 63-64 #959595,#6c6c6c, 65-66 #6c6c6c,#959595, 67-67 #6c6c6c,#6c5eb5, 68-68 #352879,#6c5eb5, 69-88 #352879,#352879, 89-149 d,#080808,
-|12: 0-0 d,#121212, 1-62 d,#080808, 63-63 #959595,#6c6c6c, 64-64 #6c6c6c,#959595, 65-65 #6c6c6c,#6c5eb5, 66-66 #352879,#6c5eb5, 67-88 #352879,#352879, 89-149 d,#080808,
-|13: 0-0 d,#121212, 1-62 d,#080808, 63-63 #6c6c6c,#352879, 64-64 #352879,#6c6c6c, 65-65 #352879,#6c5eb5, 66-88 #352879,#352879, 89-149 d,#080808,
-|14: 0-1 #ffffff,#626262, 2-129 #949494,#121212, 130-149 d,#121212,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-149 #bdbdbd,#080808,
-|16: 0-0 d,#444444, 1-1 d,#080808, 2-149 #bdbdbd,#080808,
-|17: 0-0 d,#444444, 1-149 d,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-149 #bdbdbd,#080808,
-|19: 0-0 d,#444444, 1-1 d,#080808, 2-149 #bdbdbd,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-10 #bdbdbd,#080808, 11-149 d,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-149 #bdbdbd,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-149 #bdbdbd,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-149 #bdbdbd,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-149 #bdbdbd,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-149 #bdbdbd,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-149 #bdbdbd,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-149 #bdbdbd,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-149 #bdbdbd,#080808,
-|29: 0-1 #ffffff,#262626, 2-129 #949494,#121212, 130-149 d,#121212,
-== snap search-prompt grid=150x30 cursor=6,13
-|13: /ZZ
-== snap del-image grid=150x30 cursor=5,6
-|1: ls
-|2: pic.ppm
-|3:
+| img petscii:off palette:commodore ascii:on /tmp/pardes-snap/tagbottomimage/cwd/pic.ppm Tty Del Collapse
+| 4*🬹~F~N🬰|G🬏▚Y~KF🬴s<fcSf🬰b^🬘J%🬝ZH|S_"Z}╲%'"qA🬗a🬝🬻
+| 8jDStG▄40e~.>>T&zZ/🬻iTY=`S~╳bkZR37v🬦🬵d4QHZ8X▛▟
+| ^🬪🬛$}DrydNU&wsz=`*r🬒🬓🬳🬟*Y🬴G6🬧f🬮/>t🬧u🬲1Rg1t🬝🬻█
+| ▖#_{🬗X@🬢&$s'C%*=w@🬆▀wq%🬡d┼a┼m─>🬭🬜A▀A🬲H]p🬝🬹
+| %?WX🬕f🬩*TA8n╱┼E▘🬭Y#qo~XVE▐(╳▀H4^[mj🬗=🬒🬕▟█
+| ]Z🬷eb~Oyl3=SL▙a🬱🬉~MPMz}FMu<🬝▚>3&▖🬷WS🬝~█
+| EF-🬑y🬔!r🬙🬐╳O🬩▐%Qj─4za/?/\a🬜"🬖🬈🬛🬟A🬙🬝▄
+| 🬃N@xzOnczIK=t0@🬖j5🬮🬧65▟{🬮🬉🬄🬩zQ9/🬝🬻
+| ╲${&%@"#ctt▀Cr5F;🬐ARM╱uej╳75🬹9▛🬻
+| h^🬜"🬈🬨▜╲|W🬊🬦k6^🬰🬶rZ─▄\z9🬎🬉4^🬎🬻
+| 🬆f│Q_V🬗wGx🬱=5▛5*&V🬟🬄ZrXGz2🬝🬻█
+| !🬷W🬐(🬭]7x_>▗er🬯~▚di🬬4jY:🬝▟
+| gU~🬧3▙bjr\C#kKMpffAjps🬝🬻
+| *🬯G"🬣▟d🬮▀zJ🬪EHV▟╳9}y▛▄
+| ``))~RyJ🬴jA~w=hLpX🬝🬻█
+| 4x▀J"TG7=y-QZ🬙╲~▛🬻
+| 🬯/+╳f9ZG🬕+{QN_🬝🬹
+| E<'─🬫pS!"n4&🬝~
+| m$dx"!2🬳&{🬝🬻
+| *8f🬩▙Jb🬒🬝🬻█
+| m🬩7CiN🬎🬹
+| pG╲L🬝🬻
+| 🬡L🬝▄
+| 🬝~
+== snap img-bottom grid=150x31 cursor=11,8
+|2: ls
+|3: pic.ppm
|4:
+|5: /tmp/pardes-snap/tagbottomimage/cwd Save Tty Del Togglettymode Filter Collapse
+|6: 4*🬹~F~N🬰|G🬏▚Y~KF🬴s<fcSf🬰b^🬘J%🬝ZH|S_"Z}╲%'"qA🬗a🬝🬻
+|7: 8jDStG▄40e~.>>T&zZ/🬻iTY=`S~╳bkZR37v🬦🬵d4QHZ8X▛▟
+|8: ^🬪🬛$}DrydNU&wsz=`*r🬒🬓🬳🬟*Y🬴G6🬧f🬮/>t🬧u🬲1Rg1t🬝🬻█
+|9: ▖#_{🬗X@🬢&$s'C%*=w@🬆▀wq%🬡d┼a┼m─>🬭🬜A▀A🬲H]p🬝🬹
+|10: %?WX🬕f🬩*TA8n╱┼E▘🬭Y#qo~XVE▐(╳▀H4^[mj🬗=🬒🬕▟█
+|11: ]Z🬷eb~Oyl3=SL▙a🬱🬉~MPMz}FMu<🬝▚>3&▖🬷WS🬝~█
+|12: EF-🬑y🬔!r🬙🬐╳O🬩▐%Qj─4za/?/\a🬜"🬖🬈🬛🬟A🬙🬝▄
+|13: 🬃N@xzOnczIK=t0@🬖j5🬮🬧65▟{🬮🬉🬄🬩zQ9/🬝🬻
+|14: ╲${&%@"#ctt▀Cr5F;🬐ARM╱uej╳75🬹9▛🬻
+|15: h^🬜"🬈🬨▜╲|W🬊🬦k6^🬰🬶rZ─▄\z9🬎🬉4^🬎🬻
+|16: 🬆f│Q_V🬗wGx🬱=5▛5*&V🬟🬄ZrXGz2🬝🬻█
+|17: !🬷W🬐(🬭]7x_>▗er🬯~▚di🬬4jY:🬝▟
+|18: gU~🬧3▙bjr\C#kKMpffAjps🬝🬻
+|19: *🬯G"🬣▟d🬮▀zJ🬪EHV▟╳9}y▛▄
+|20: ``))~RyJ🬴jA~w=hLpX🬝🬻█
+|21: 4x▀J"TG7=y-QZ🬙╲~▛🬻
+|22: 🬯/+╳f9ZG🬕+{QN_🬝🬹
+|23: E<'─🬫pS!"n4&🬝~
+|24: m$dx"!2🬳&{🬝🬻
+|25: *8f🬩▙Jb🬒🬝🬻█
+|26: m🬩7CiN🬎🬹
+|27: pG╲L🬝🬻
+|28: 🬡L🬝▄
+|29: 🬝~
+|30: img petscii:off palette:commodore ascii:on /tmp/pardes-snap/tagbottomimage/cwd/pic.ppm Tty Del Collapse
+== style img-bottom grid=150x31
+|0: 0-70 #b2c3b8,#1d2824, 71-149 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-149 d,#26362d,
+|2: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-149 #e5eee5,#0d1410,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-149 #e5eee5,#0d1410,
+|4: 0-0 d,#637f6a, 1-149 d,#0d1410,
+|5: 0-1 #ffffff,#4c6356, 2-79 #b2c3b8,#1d2824, 80-149 d,#1d2824,
+|6: 0-0 d,#152019, 1-51 d,#0d1410, 52-59 #959595,#6c6c6c, 60-60 #6c6c6c,#959595, 61-65 #959595,#6c6c6c, 66-66 #6c6c6c,#959595, 67-70 #959595,#6c6c6c, 71-73 #6c6c6c,#959595, 74-75 #959595,#6c6c6c, 76-76 #6c6c6c,#959595, 77-84 #959595,#6c6c6c, 85-85 #6c6c6c,#959595, 86-90 #959595,#6c6c6c, 91-91 #6c6c6c,#959595, 92-95 #959595,#6c6c6c, 96-97 #6c6c6c,#959595, 98-98 #959595,#352879, 99-99 #352879,#959595, 100-149 d,#0d1410,
+|7: 0-0 d,#152019, 1-51 d,#0d1410, 52-52 #6c6c6c,#959595, 53-54 #959595,#6c6c6c, 55-55 #6c6c6c,#959595, 56-56 #959595,#6c6c6c, 57-57 #6c6c6c,#959595, 58-58 #959595,#6c6c6c, 59-59 #6c6c6c,#959595, 60-60 #959595,#6c6c6c, 61-61 #6c6c6c,#959595, 62-66 #959595,#6c6c6c, 67-67 #6c6c6c,#959595, 68-70 #959595,#6c6c6c, 71-72 #6c6c6c,#959595, 73-73 #959595,#6c6c6c, 74-74 #6c6c6c,#959595, 75-75 #959595,#6c6c6c, 76-76 #444444,#959595, 77-77 #6c6c6c,#959595, 78-81 #959595,#6c6c6c, 82-84 #6c6c6c,#959595, 85-85 #959595,#6c6c6c, 86-86 #6c6c6c,#959595, 87-89 #959595,#6c6c6c, 90-90 #6c6c6c,#959595, 91-92 #959595,#6c6c6c, 93-94 #6c6c6c,#959595, 95-95 #959595,#6c6c6c, 96-96 #959595,#352879, 97-97 #352879,#959595, 98-99 #352879,#352879, 100-149 d,#0d1410,
+|8: 0-0 d,#152019, 1-51 d,#0d1410, 52-55 #959595,#6c6c6c, 56-56 #6c6c6c,#959595, 57-57 #959595,#6c6c6c, 58-58 #6c6c6c,#959595, 59-59 #959595,#6c6c6c, 60-60 #6c6c6c,#959595, 61-61 #959595,#6c6c6c, 62-62 #6c6c6c,#959595, 63-64 #959595,#6c6c6c, 65-65 #6c6c6c,#959595, 66-66 #959595,#6c6c6c, 67-67 #6c6c6c,#959595, 68-68 #959595,#6c6c6c, 69-69 #6c6c6c,#959595, 70-70 #959595,#6c6c6c, 71-71 #6c6c6c,#959595, 72-75 #959595,#6c6c6c, 76-78 #6c6c6c,#959595, 79-80 #959595,#6c6c6c, 81-81 #6c6c6c,#959595, 82-83 #959595,#6c6c6c, 84-86 #6c6c6c,#959595, 87-88 #959595,#6c6c6c, 89-91 #6c6c6c,#959595, 92-92 #959595,#6c6c6c, 93-93 #6c6c6c,#959595, 94-94 #6c6c6c,#352879, 95-95 #352879,#959595, 96-96 #352879,#6c5eb5, 97-99 #352879,#352879, 100-149 d,#0d1410,
+|9: 0-0 d,#152019, 1-51 d,#0d1410, 52-56 #959595,#6c6c6c, 57-57 #6c6c6c,#959595, 58-60 #959595,#6c6c6c, 61-61 #6c6c6c,#959595, 62-66 #959595,#6c6c6c, 67-67 #444444,#6c6c6c, 68-68 #959595,#6c6c6c, 69-70 #6c6c6c,#959595, 71-71 #959595,#6c6c6c, 72-72 #6c6c6c,#959595, 73-73 #959595,#6c6c6c, 74-74 #6c6c6c,#959595, 75-75 #959595,#6c6c6c, 76-79 #6c6c6c,#959595, 80-82 #959595,#6c6c6c, 83-83 #6c6c6c,#959595, 84-84 #959595,#6c6c6c, 85-85 #6c6c6c,#959595, 86-86 #959595,#6c6c6c, 87-87 #6c6c6c,#959595, 88-88 #959595,#6c6c6c, 89-89 #6c6c6c,#959595, 90-91 #959595,#6c6c6c, 92-92 #6c6c6c,#352879, 93-93 #352879,#6c5eb5, 94-99 #352879,#352879, 100-149 d,#0d1410,
+|10: 0-0 d,#152019, 1-51 d,#0d1410, 52-55 #6c6c6c,#959595, 56-57 #959595,#6c6c6c, 58-59 #6c6c6c,#959595, 60-62 #959595,#6c6c6c, 63-63 #6c6c6c,#959595, 64-64 #959595,#6c6c6c, 65-66 #6c6c6c,#959595, 67-68 #959595,#6c6c6c, 69-72 #6c6c6c,#959595, 73-75 #959595,#6c6c6c, 76-76 #6c6c6c,#959595, 77-77 #959595,#6c6c6c, 78-80 #6c6c6c,#959595, 81-89 #959595,#6c6c6c, 90-90 #959595,#352879, 91-91 #352879,#6c6c6c, 92-92 #352879,#6c5eb5, 93-99 #352879,#352879, 100-149 d,#0d1410,
+|11: 0-0 d,#152019, 1-51 d,#0d1410, 52-55 #959595,#6c6c6c, 56-56 #6c6c6c,#959595, 57-57 #959595,#6c6c6c, 58-59 #6c6c6c,#959595, 60-60 #959595,#6c6c6c, 61-61 #6c6c6c,#959595, 62-62 #959595,#6c6c6c, 63-64 #6c6c6c,#959595, 65-66 #959595,#6c6c6c, 67-67 #6c6c6c,#959595, 68-70 #959595,#6c6c6c, 71-72 #6c6c6c,#959595, 73-78 #959595,#6c6c6c, 79-80 #6c6c6c,#959595, 81-85 #959595,#6c6c6c, 86-86 #6c6c6c,#959595, 87-87 #959595,#6c6c6c, 88-89 #959595,#352879, 90-90 #352879,#6c5eb5, 91-99 #352879,#352879, 100-149 d,#0d1410,
+|12: 0-0 d,#152019, 1-51 d,#0d1410, 52-52 #959595,#6c6c6c, 53-53 #6c6c6c,#959595, 54-56 #959595,#6c6c6c, 57-57 #6c6c6c,#959595, 58-58 #959595,#6c6c6c, 59-59 #6c6c6c,#959595, 60-66 #959595,#6c6c6c, 67-67 #6c6c6c,#959595, 68-71 #959595,#6c6c6c, 72-72 #6c6c6c,#959595, 73-73 #959595,#6c6c6c, 74-74 #6c6c6c,#959595, 75-76 #959595,#6c6c6c, 77-78 #6c6c6c,#959595, 79-81 #959595,#6c6c6c, 82-82 #6c6c6c,#959595, 83-83 #959595,#6c6c6c, 84-84 #6c6c6c,#959595, 85-85 #959595,#6c6c6c, 86-86 #959595,#352879, 87-87 #352879,#6c5eb5, 88-99 #352879,#352879, 100-149 d,#0d1410,
+|13: 0-0 d,#152019, 1-51 d,#0d1410, 52-52 #959595,#6c6c6c, 53-54 #6c6c6c,#959595, 55-55 #959595,#6c6c6c, 56-58 #6c6c6c,#959595, 59-61 #959595,#6c6c6c, 62-62 #6c6c6c,#959595, 63-65 #959595,#6c6c6c, 66-66 #6c6c6c,#959595, 67-67 #959595,#6c6c6c, 68-68 #6c6c6c,#959595, 69-72 #959595,#6c6c6c, 73-74 #6c6c6c,#959595, 75-75 #959595,#6c6c6c, 76-76 #6c6c6c,#959595, 77-77 #959595,#6c6c6c, 78-78 #6c6c6c,#959595, 79-79 #959595,#6c6c6c, 80-80 #6c6c6c,#959595, 81-81 #959595,#6c6c6c, 82-82 #6c6c6c,#959595, 83-83 #959595,#6c6c6c, 84-84 #6c6c6c,#352879, 85-85 #352879,#6c6c6c, 86-99 #352879,#352879, 100-149 d,#0d1410,
+|14: 0-0 d,#152019, 1-51 d,#0d1410, 52-52 #444444,#959595, 53-55 #959595,#6c6c6c, 56-56 #6c6c6c,#959595, 57-57 #959595,#6c6c6c, 58-58 #444444,#959595, 59-61 #959595,#6c6c6c, 62-63 #6c6c6c,#959595, 64-64 #959595,#6c6c6c, 65-66 #6c6c6c,#959595, 67-67 #959595,#6c6c6c, 68-68 #6c6c6c,#959595, 69-70 #959595,#6c6c6c, 71-71 #6c6c6c,#959595, 72-73 #959595,#6c6c6c, 74-74 #6c6c6c,#959595, 75-75 #959595,#6c6c6c, 76-76 #6c6c6c,#959595, 77-78 #959595,#6c6c6c, 79-80 #6c6c6c,#959595, 81-81 #959595,#6c6c6c, 82-82 #959595,#352879, 83-83 #352879,#6c6c6c, 84-99 #352879,#352879, 100-149 d,#0d1410,
+|15: 0-0 d,#152019, 1-51 d,#0d1410, 52-56 #959595,#6c6c6c, 57-57 #6c6c6c,#959595, 58-59 #959595,#6c6c6c, 60-61 #6c6c6c,#959595, 62-63 #959595,#6c6c6c, 64-64 #6c6c6c,#959595, 65-65 #959595,#6c6c6c, 66-66 #6c6c6c,#959595, 67-68 #959595,#6c6c6c, 69-69 #6c6c6c,#959595, 70-74 #959595,#6c6c6c, 75-76 #6c6c6c,#959595, 77-78 #959595,#6c6c6c, 79-79 #6c6c6c,#959595, 80-80 #959595,#352879, 81-81 #352879,#959595, 82-99 #352879,#352879, 100-149 d,#0d1410,
+|16: 0-0 d,#152019, 1-51 d,#0d1410, 52-52 #6c6c6c,#959595, 53-53 #959595,#6c6c6c, 54-54 #6c6c6c,#959595, 55-59 #959595,#6c6c6c, 60-61 #6c6c6c,#959595, 62-64 #959595,#6c6c6c, 65-65 #6c6c6c,#959595, 66-67 #959595,#6c6c6c, 68-69 #6c6c6c,#959595, 70-71 #959595,#6c6c6c, 72-75 #6c6c6c,#959595, 76-77 #959595,#6c6c6c, 78-78 #6c6c6c,#352879, 79-79 #352879,#959595, 80-80 #352879,#6c5eb5, 81-99 #352879,#352879, 100-149 d,#0d1410,
+|17: 0-0 d,#152019, 1-51 d,#0d1410, 52-52 #959595,#6c6c6c, 53-53 #6c6c6c,#959595, 54-63 #959595,#6c6c6c, 64-65 #6c6c6c,#959595, 66-68 #959595,#6c6c6c, 69-71 #6c6c6c,#959595, 72-73 #959595,#6c6c6c, 74-75 #6c6c6c,#959595, 76-76 #6c6c6c,#352879, 77-77 #352879,#6c6c6c, 78-99 #352879,#352879, 100-149 d,#0d1410,
+|18: 0-0 d,#152019, 1-51 d,#0d1410, 52-52 #959595,#6c6c6c, 53-55 #6c6c6c,#959595, 56-60 #959595,#6c6c6c, 61-61 #444444,#959595, 62-62 #959595,#6c6c6c, 63-63 #6c6c6c,#959595, 64-64 #959595,#6c6c6c, 65-66 #6c6c6c,#959595, 67-69 #959595,#6c6c6c, 70-71 #6c6c6c,#959595, 72-72 #959595,#6c6c6c, 73-73 #6c6c6c,#959595, 74-74 #6c6c6c,#352879, 75-75 #352879,#6c6c6c, 76-99 #352879,#352879, 100-149 d,#0d1410,
+|19: 0-0 d,#152019, 1-51 d,#0d1410, 52-52 #959595,#6c6c6c, 53-55 #6c6c6c,#959595, 56-63 #959595,#6c6c6c, 64-64 #6c6c6c,#959595, 65-66 #959595,#6c6c6c, 67-67 #6c6c6c,#959595, 68-69 #959595,#6c6c6c, 70-70 #6c6c6c,#959595, 71-71 #959595,#6c6c6c, 72-72 #959595,#352879, 73-73 #352879,#6c5eb5, 74-99 #352879,#352879, 100-149 d,#0d1410,
+|20: 0-0 d,#152019, 1-51 d,#0d1410, 52-56 #959595,#6c6c6c, 57-59 #6c6c6c,#959595, 60-62 #959595,#6c6c6c, 63-63 #6c6c6c,#959595, 64-66 #959595,#6c6c6c, 67-69 #6c6c6c,#959595, 70-70 #6c6c6c,#352879, 71-71 #352879,#6c6c6c, 72-72 #352879,#6c5eb5, 73-99 #352879,#352879, 100-149 d,#0d1410,
+|21: 0-0 d,#152019, 1-51 d,#0d1410, 52-52 #6c6c6c,#959595, 53-56 #959595,#6c6c6c, 57-57 #6c6c6c,#959595, 58-67 #959595,#6c6c6c, 68-68 #6c6c6c,#352879, 69-69 #352879,#6c6c6c, 70-99 #352879,#352879, 100-149 d,#0d1410,
+|22: 0-0 d,#152019, 1-51 d,#0d1410, 52-52 #959595,#6c6c6c, 53-53 #6c6c6c,#959595, 54-54 #959595,#6c6c6c, 55-55 #6c6c6c,#959595, 56-58 #959595,#6c6c6c, 59-62 #6c6c6c,#959595, 63-65 #959595,#6c6c6c, 66-66 #6c6c6c,#352879, 67-67 #352879,#6c5eb5, 68-99 #352879,#352879, 100-149 d,#0d1410,
+|23: 0-0 d,#152019, 1-51 d,#0d1410, 52-52 #959595,#6c6c6c, 53-53 #6c6c6c,#959595, 54-55 #959595,#6c6c6c, 56-56 #6c6c6c,#959595, 57-60 #959595,#6c6c6c, 61-62 #6c6c6c,#959595, 63-63 #959595,#6c6c6c, 64-64 #6c6c6c,#352879, 65-65 #959595,#352879, 66-99 #352879,#352879, 100-149 d,#0d1410,
+|24: 0-0 d,#152019, 1-51 d,#0d1410, 52-53 #959595,#6c6c6c, 54-55 #6c6c6c,#959595, 56-56 #959595,#6c6c6c, 57-57 #6c6c6c,#959595, 58-58 #959595,#6c6c6c, 59-61 #6c6c6c,#959595, 62-62 #6c6c6c,#352879, 63-63 #352879,#959595, 64-99 #352879,#352879, 100-149 d,#0d1410,
+|25: 0-0 d,#152019, 1-51 d,#0d1410, 52-52 #959595,#6c6c6c, 53-53 #6c6c6c,#959595, 54-55 #959595,#6c6c6c, 56-56 #6c6c6c,#959595, 57-57 #959595,#6c6c6c, 58-58 #6c6c6c,#959595, 59-59 #959595,#6c6c6c, 60-60 #6c6c6c,#352879, 61-61 #352879,#959595, 62-62 #352879,#6c5eb5, 63-99 #352879,#352879, 100-149 d,#0d1410,
+|26: 0-0 d,#152019, 1-51 d,#0d1410, 52-53 #959595,#6c6c6c, 54-57 #6c6c6c,#959595, 58-58 #959595,#352879, 59-59 #352879,#6c6c6c, 60-99 #352879,#352879, 100-149 d,#0d1410,
+|27: 0-0 d,#152019, 1-51 d,#0d1410, 52-52 #959595,#6c6c6c, 53-53 #6c6c6c,#959595, 54-55 #959595,#6c6c6c, 56-56 #6c6c6c,#352879, 57-57 #352879,#959595, 58-99 #352879,#352879, 100-149 d,#0d1410,
+|28: 0-0 d,#152019, 1-51 d,#0d1410, 52-53 #959595,#6c6c6c, 54-54 #6c6c6c,#352879, 55-55 #352879,#6c5eb5, 56-99 #352879,#352879, 100-149 d,#0d1410,
+|29: 0-0 d,#152019, 1-51 d,#0d1410, 52-52 #6c6c6c,#352879, 53-53 #959595,#352879, 54-99 #352879,#352879, 100-149 d,#0d1410,
+|30: 0-1 #000000,#adcc91, 2-104 #becfc4,#26362d, 105-149 d,#26362d,
+== snap search-prompt grid=150x31 cursor=6,29
+|29: /ZZ
+== snap del-image grid=150x31 cursor=5,7
|5:
-|6: pic.ppm
-|7:
+|6:
+|7: pic.ppm
|8:
|9:
|10:
@@ -92,4 +107,17 @@
|14:
|15:
|16:
+|17:
+|18:
+|19:
|20:
+|21:
+|22:
+|23:
+|24:
+|25:
+|26:
+|27:
+|28:
+|29:
+|30: /tmp/pardes-snap/tagbottomimage/cwd Save Tty Del Togglettymode Filter Collapse
diff --git a/test/snapshots/tagbottomimage.snap b/test/snapshots/tagbottomimage.snap
index 94f1e013..e24a5c5c 100644
--- a/test/snapshots/tagbottomimage.snap
+++ b/test/snapshots/tagbottomimage.snap
@@ -4,24 +4,24 @@
# "the tag moved" and "the message row moved with it" can come apart. Nothing
# in tagbottom.snap touches one.
ppmdiag pic.ppm
-start 30 150 -n 1
-wait 8000 New Newcol
+start 31 150 -n 1
+wait 8000 Newcol Joincol
stable 700 20000
# open it the way images.snap does: type the name into the shell pane's own
-# text and right-click it. The image lands in a column of its own on the left.
-press left 5 8
-release left 5 8
+# text and right-click it. The narrow-window image splits below that shell.
+press left 5 9
+release left 5 9
stable 400 5000
key i
text pic.ppm
key esc
settle 100
-press right 6 8
-release right 6 8
+press right 6 9
+release right 6 9
wait 10000 img
stable 700 20000
snap img-top
-# SPC t b: the tag leaves row 1 for row 29 and the glyph art slides up into the
+# SPC t b: the tag leaves grid row 6 for row 30 and the glyph art slides up into the
# row it left. The style capture is the half a text grid cannot see — the
# tagline's chrome colours have to travel with it, and a tag row drawn in the
# palette of the cell art under it would read as part of the picture.
@@ -32,7 +32,7 @@ snapstyle img-bottom
# `/` on an image pane. There is no text to search, and that is the point: the
# prompt is drawn by the message-row pass, which runs OUTSIDE renderPane
# precisely so an early-returning pane still gets one. With Tagbottom it lands
-# on the last row of the art (grid 28), just above the tagline on grid 29 —
+# on the last row of the art (grid 29), just above the tagline on grid 30 —
# over the picture, never over the tag it was cut from.
key /
send ZZ
@@ -43,18 +43,11 @@ key esc
settle 100
stable 400 5000
# ...and EXECUTE `Del` on that bottom tagline, which is the assertion the
-# pixels cannot make: the middle click has to map row 15 to the image pane's
+# pixels cannot make: the middle click has to map grid row 30 to the image pane's
# TAG row rather than to a body row it has no body for. The image pane goes
# away entirely and the shell takes the whole window back.
-#
-# Row 15 is the image pane's OWN last row, which is where Tagbottom puts its
-# tag; row 30 is the shell's. This used to click column 95 of row 30, which is
-# blank space 176 columns short of the shell's right-aligned `Del` and in the
-# wrong pane besides, so it deleted nothing and the golden recorded an image
-# pane that never went away - along with a widen-to-300-and-back either side of
-# it, scaffolding for a column that was wrong anyway. `New Newtty Del` is fully
-# on screen at 150 columns (see the img-bottom capture above).
-press middle @Del 15
-release middle @Del 15
+# `@Del` locates the command text without depending on the image's metadata.
+press middle @Del 31
+release middle @Del 31
stable 700 15000
snap del-image
diff --git a/test/snapshots/tagbottomshort.golden b/test/snapshots/tagbottomshort.golden
index 303be3d8..0bb678cd 100644
--- a/test/snapshots/tagbottomshort.golden
+++ b/test/snapshots/tagbottomshort.golden
@@ -1,5 +1,6 @@
-== snap roomy grid=80x10 cursor=6,8
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+== snap roomy grid=80x11 cursor=6,9
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
| 1 one
| 2 two
| 3 three
@@ -8,21 +9,24 @@
| 6 six
|
| /ZZ
-| /tmp/pardes-snap/tagbottomshort/cwd/s.txt Save New Newtty Del
-== snap two-body grid=80x4 cursor=6,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /tmp/pardes-snap/tagbottomshort/cwd/s.txt Save Tty Del Collapse
+== snap two-body grid=80x5 cursor=6,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
| 1 one
| /ZZ
-| /tmp/pardes-snap/tagbottomshort/cwd/s.txt Save New Newtty Del
-== snap one-body grid=80x3 cursor=6,1
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /tmp/pardes-snap/tagbottomshort/cwd/s.txt Save Tty Del Collapse
+== snap one-body grid=80x4 cursor=6,2
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
| /ZZ
-| /tmp/pardes-snap/tagbottomshort/cwd/s.txt Save New Newtty Del
-== snap tag-only grid=80x2 cursor=67,1
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/tagbottomshort/cwd/s.txt Save New Newtty Del
-== snap regrown grid=80x10 cursor=6,8
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /tmp/pardes-snap/tagbottomshort/cwd/s.txt Save Tty Del Collapse
+== snap tag-only grid=80x2 cursor=69,1
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /tmp/pardes-snap/tagbottomshort/cwd/s.txt Save Tty Del Collapse
+== snap regrown grid=80x11 cursor=6,9
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
| 1 one
| 2 two
| 3 three
@@ -31,8 +35,9 @@
| 6 six
|
| /ZZ
-| /tmp/pardes-snap/tagbottomshort/cwd/s.txt Save New Newtty Del
-== snap leader-one-body grid=80x3 cursor=7,1
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+| /tmp/pardes-snap/tagbottomshort/cwd/s.txt Save Tty Del Collapse
+== snap leader-one-body grid=80x4 cursor=7,2
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
| SPC
-| /tmp/pardes-snap/tagbottomshort/cwd/s.txt Save New Newtty Del
+| /tmp/pardes-snap/tagbottomshort/cwd/s.txt Save Tty Del Collapse
diff --git a/test/snapshots/tagbottomshort.snap b/test/snapshots/tagbottomshort.snap
index a6ca2828..2574df36 100644
--- a/test/snapshots/tagbottomshort.snap
+++ b/test/snapshots/tagbottomshort.snap
@@ -5,7 +5,7 @@
# message waits: not drawn over the tag, and not on the row above the pane,
# which is what `r.y + r.h - 1 - BOX_H` gives you when the guard is off by one.
file s.txt one\ntwo\nthree\nfour\nfive\nsix
-start 10 80 s.txt
+start 11 80 s.txt
wait 8000 s.txt
stable 700 20000
key space t b
@@ -18,12 +18,12 @@ stable 600 8000
stable 400 5000
snap roomy
# two body rows left; the prompt takes the lower one and line 1 still shows
-resize 4 80
+resize 5 80
stable 700 10000
snap two-body
# one body row, and the prompt takes it. The tagline underneath must still be
# drawn in full — this is where an off-by-one eats it.
-resize 3 80
+resize 4 80
stable 700 10000
snap one-body
# the tagline alone. No body row, so nothing of the prompt is drawn anywhere —
@@ -34,7 +34,7 @@ resize 2 80
stable 700 10000
snap tag-only
# ...and grown back, still armed, back on the last body row
-resize 10 80
+resize 11 80
stable 700 10000
snap regrown
key esc
@@ -42,7 +42,7 @@ settle 100
stable 400 5000
# the SPC leader indicator rides the same row, right-aligned, and shrinks onto
# the single body row with it
-resize 3 80
+resize 4 80
stable 700 10000
key space
stable 400 8000
diff --git a/test/snapshots/tagcmd.golden b/test/snapshots/tagcmd.golden
index ac4071f0..8fd1a9dd 100644
--- a/test/snapshots/tagcmd.golden
+++ b/test/snapshots/tagcmd.golden
@@ -1,6 +1,7 @@
-== snap edited grid=100x30 cursor=13,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/tagcmd/cwd/c.txt * Save New Newtty Del
+== snap edited grid=100x31 cursor=13,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/tagcmd/cwd/c.txt * Save Tty Del Collapse
| 1 ZZEDITline 1
| 2 line 2
| 3 line 3
@@ -8,11 +9,11 @@
| 5 line 5
| 6 line 6
| 7
-== snap colon grid=100x30 cursor=61,1
-== snap word grid=100x30 cursor=65,1
-== snap saved grid=100x30 cursor=13,2
-|1: /tmp/pardes-snap/tagcmd/cwd/c.txt Save New Newtty Del
-|29: --:--:-- saved /tmp/pardes-snap/tagcmd/cwd/c.txt
+== snap colon grid=100x31 cursor=38,2
+== snap word grid=100x31 cursor=42,2
+== snap saved grid=100x31 cursor=13,3
+|2: /tmp/pardes-snap/tagcmd/cwd/c.txt Save Tty Del Collapse
+|30: --:--:-- saved /tmp/pardes-snap/tagcmd/cwd/c.txt
== file written
ZZEDITline 1
line 2
@@ -22,5 +23,5 @@ line 5
line 6
== end file
-== snap escaped grid=100x30 cursor=13,2
-|29:
+== snap escaped grid=100x31 cursor=13,3
+|30:
diff --git a/test/snapshots/tagcmd.snap b/test/snapshots/tagcmd.snap
index 5f869288..305ed521 100644
--- a/test/snapshots/tagcmd.snap
+++ b/test/snapshots/tagcmd.snap
@@ -7,8 +7,8 @@
# body back in normal mode — same keys as the body, so Tab by default (see
# config.look_key/exec_key). Esc backs out instead, leaving the tail as it was.
lines c.txt 6
-start 30 100 c.txt
-wait 8000 New Newcol
+start 31 100 c.txt
+wait 8000 Newcol Joincol
wait 8000 c.txt
stable 700 20000
# edit line 1 so Save has something to write
diff --git a/test/snapshots/tagnav.golden b/test/snapshots/tagnav.golden
index d32a9825..6491dd38 100644
--- a/test/snapshots/tagnav.golden
+++ b/test/snapshots/tagnav.golden
@@ -1,6 +1,7 @@
-== snap start grid=100x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/tagnav/cwd/w.txt Save New Newtt /tmp/pardes-snap/tagnav/cwd Save New Newtty Del
+== snap start grid=100x31 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/tagnav/cwd/w.txt Save Tty Del C /tmp/pardes-snap/tagnav/cwd Save Tty Del Togglet
| 1 alpha ls
| 2 beta w.txt
| 3 gamma
@@ -15,37 +16,51 @@
|
|
|
-| /tmp/pardes-snap/tagnav/cwd Save New Newtty Del
+| /tmp/pardes-snap/tagnav/cwd Save Tty Del Togglet
| ls
| w.txt
-== snap colon grid=100x30 cursor=36,1
-== snap right-tag grid=100x30 cursor=80,1
-== snap left-tag grid=100x30 cursor=36,1
-== snap down-tag grid=100x30 cursor=30,16
-== snap up-tag grid=100x30 cursor=36,1
-== snap up-edge grid=100x30 cursor=0,0
-== snap topbar-word grid=100x30 cursor=3,0
-== snap topbar-graphemes grid=100x30 cursor=5,0
-== snap back-down grid=100x30 cursor=36,1
-== snap arrows-still-motion grid=100x30 cursor=38,1
-== snap back-to-body grid=100x30 cursor=7,2
-== snap tty-on grid=100x30 cursor=54,4
-|1: /tmp/pardes-snap/tagnav/cwd/w.txt Save New Newtt$ /tmp/pardes-snap/tagnav/cwd Save New Newtty Del
-|2: 1 alpha $ ls
-|4: 3 gamma $
-== snap tty-tag grid=100x30 cursor=80,1
-|2: 1 alpha ls
-|4: 3 gamma
-== snap tty-restored grid=100x30 cursor=54,4
-|2: 1 alpha $ ls
-|4: 3 gamma $
-== snap topbar-dollar grid=100x30 cursor=74,0
-== snap topbar-dump-word grid=100x30 cursor=50,0
-== snap topbar-exec grid=100x30 cursor=7,2
-|0: New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill Restore /tmp/pardes-snap
-== snap topbar-restore-word grid=100x30 cursor=76,0
-== snap topbar-restored grid=100x30 cursor=7,2
-|0: New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|1: /tmp/pardes-snap/tagnav/cwd/w.txt Save New Newtt /tmp/pardes-snap/tagnav/cwd Save New Newtty Del
-|2: 1 alpha ls
-|4: 3 gamma
+== snap colon grid=100x31 cursor=28,2
+|2: des-snap/tagnav/cwd/w.txt Save Tty Del Collapse /tmp/pardes-snap/tagnav/cwd Save Tty Del Togglet
+== snap right-tag grid=100x31 cursor=57,2
+|2: /tmp/pardes-snap/tagnav/cwd/w.txt Save Tty Del C /cwd Save Tty Del Togglettymode Filter Collapse
+== snap left-tag grid=100x31 cursor=28,2
+|2: des-snap/tagnav/cwd/w.txt Save Tty Del Collapse /tmp/pardes-snap/tagnav/cwd Save Tty Del Togglet
+== snap down-tag grid=100x31 cursor=7,17
+|2: /tmp/pardes-snap/tagnav/cwd/w.txt Save Tty Del C /tmp/pardes-snap/tagnav/cwd Save Tty Del Togglet
+|17: /cwd Save Tty Del Togglettymode Filter Collapse
+== snap up-tag grid=100x31 cursor=28,2
+|2: des-snap/tagnav/cwd/w.txt Save Tty Del Collapse /tmp/pardes-snap/tagnav/cwd Save Tty Del Togglet
+|17: /tmp/pardes-snap/tagnav/cwd Save Tty Del Togglet
+== snap column-tag grid=100x31 cursor=0,1
+|2: /tmp/pardes-snap/tagnav/cwd/w.txt Save Tty Del C /tmp/pardes-snap/tagnav/cwd Save Tty Del Togglet
+== snap up-edge grid=100x31 cursor=0,0
+== snap topbar-word grid=100x31 cursor=6,0
+== snap topbar-graphemes grid=100x31 cursor=8,0
+== snap column-down grid=100x31 cursor=0,1
+== snap back-down grid=100x31 cursor=28,2
+|2: des-snap/tagnav/cwd/w.txt Save Tty Del Collapse /tmp/pardes-snap/tagnav/cwd Save Tty Del Togglet
+== snap arrows-still-motion grid=100x31 cursor=30,2
+== snap back-to-body grid=100x31 cursor=7,3
+|2: /tmp/pardes-snap/tagnav/cwd/w.txt Save Tty Del C /tmp/pardes-snap/tagnav/cwd Save Tty Del Togglet
+== snap tty-on grid=100x31 cursor=54,5
+|2: /tmp/pardes-snap/tagnav/cwd/w.txt Save Tty Del C$ /tmp/pardes-snap/tagnav/cwd Save Tty Del Togglet
+|3: 1 alpha $ ls
+|5: 3 gamma $
+== snap tty-tag grid=100x31 cursor=57,2
+|2: /tmp/pardes-snap/tagnav/cwd/w.txt Save Tty Del C$ /cwd Save Tty Del Togglettymode Filter Collapse
+|3: 1 alpha ls
+|5: 3 gamma
+== snap tty-restored grid=100x31 cursor=54,5
+|2: /tmp/pardes-snap/tagnav/cwd/w.txt Save Tty Del C$ /tmp/pardes-snap/tagnav/cwd Save Tty Del Togglet
+|3: 1 alpha $ ls
+|5: 3 gamma $
+== snap topbar-dollar grid=100x31 cursor=70,0
+== snap topbar-dump-word grid=100x31 cursor=46,0
+== snap topbar-exec grid=100x31 cursor=7,3
+|0: Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill Restore /tmp/pardes-snap/tag
+== snap topbar-restore-word grid=100x31 cursor=72,0
+== snap topbar-restored grid=100x31 cursor=7,3
+|0: Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|2: /tmp/pardes-snap/tagnav/cwd/w.txt Save Tty Del C /tmp/pardes-snap/tagnav/cwd Save Tty Del Togglet
+|3: 1 alpha ls
+|5: 3 gamma
diff --git a/test/snapshots/tagnav.snap b/test/snapshots/tagnav.snap
index da3cdd79..c375e644 100644
--- a/test/snapshots/tagnav.snap
+++ b/test/snapshots/tagnav.snap
@@ -12,8 +12,8 @@
# tag edit parks the body mode rather than overwriting it, so the box keeps
# saying what the pane we left will be when we hop back off its tagline.
file w.txt alpha\nbeta\ngamma
-start 30 100 w.txt
-wait 8000 New Newcol
+start 31 100 w.txt
+wait 8000 Newcol Joincol
wait 8000 w.txt
stable 700 20000
# A FILE boots alone now, so the shell this script calls "the launch shell" is
@@ -52,11 +52,11 @@ snap down-tag
key k
stable 400 5000
snap up-tag
-# k again: nothing above the file — but "nothing" is not nowhere. Above the
-# topmost tagline is the TOPBAR, row 0, the global one. It is not a pane, so
-# focusDir can never find it; this fallback is the one place k walks off the
-# layout entirely. Evidence is the cursor=0,0 header: the bar has the keyboard
-# and parks on `New`, the first and most frequent action.
+# k visits the column tag first, then the workspace tag. Both stay in normal
+# navigation mode; neither hop drops into a pane body.
+key k
+stable 400 5000
+snap column-tag
key k
stable 400 5000
snap up-edge
@@ -73,6 +73,9 @@ snap topbar-graphemes
# tagline, still in normal mode, so the hop is a round trip
key j
stable 400 5000
+snap column-down
+key j
+stable 400 5000
snap back-down
# the arrows are still in-tag motion: two rights walk two columns of the tail
key right right
@@ -111,7 +114,7 @@ snap tty-restored
key c-w h
stable 400 5000
key :
-key k
+key k k
stable 400 5000
key $
stable 400 5000
@@ -128,7 +131,7 @@ snap topbar-exec
# that step over a path in one go — and run it. The bar drops focus BEFORE the
# builtin, so nothing reaches for state the swap already freed.
key :
-key k
+key k k
stable 400 5000
key $ B B
stable 400 5000
diff --git a/test/snapshots/tagpath.golden b/test/snapshots/tagpath.golden
index 3866e8f2..4f758365 100644
--- a/test/snapshots/tagpath.golden
+++ b/test/snapshots/tagpath.golden
@@ -1,50 +1,57 @@
-== snap start grid=100x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/tagpath/cwd/c.txt Save New Newtty Del
+== snap start grid=100x31 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/tagpath/cwd/c.txt Save Tty Del Collapse
| 1 line 1
| 2 line 2
| 3 line 3
| 4 line 4
| 5
-== snap colon grid=100x30 cursor=61,1
-== snap col0 grid=100x30 cursor=2,1
-== snap sel-path grid=100x30 cursor=35,1
-== style sel-path grid=100x30
-|0: 0-74 #949494,#121212, 75-99 d,#121212,
-|1: 0-1 #ffffff,#626262, 2-35 #080808,#80a0ff, 36-79 #949494,#121212, 80-99 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|8: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|11: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|16: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|19: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-|29: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
-== snap yanked-path grid=100x30 cursor=41,2
-|1: /tmp/pardes-snap/tagpath/cwd/c.txt * Save New Newtty Del
-|2: 1 l/tmp/pardes-snap/tagpath/cwd/c.txtine 1
-== snap drag-cross grid=100x30 cursor=41,1
-== style drag-cross grid=100x30
-|1: 0-1 #ffffff,#626262, 2-10 #949494,#121212, 11-41 #080808,#80a0ff, 42-81 #949494,#121212, 82-99 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-46 #bdbdbd,#080808, 47-99 d,#080808,
-== snap path-inert grid=100x30 cursor=11,1
+== snap colon grid=100x31 cursor=37,2
+== snap col0 grid=100x31 cursor=2,2
+== snap sel-path grid=100x31 cursor=35,2
+== style sel-path grid=100x31
+|0: 0-70 #b2c3b8,#1d2824, 71-99 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-99 d,#26362d,
+|2: 0-1 #000000,#adcc91, 2-35 #f5f7ee,#405d4b, 36-57 #becfc4,#26362d, 58-99 d,#26362d,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-99 d,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-99 d,#0d1410,
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-99 d,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-99 d,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|17: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|20: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-99 d,#0d1410,
+== snap yanked-path grid=100x31 cursor=41,3
+|2: /tmp/pardes-snap/tagpath/cwd/c.txt * Save Tty Del Collapse
+|3: 1 l/tmp/pardes-snap/tagpath/cwd/c.txtine 1
+== snap drag-cross grid=100x31 cursor=41,2
+== style drag-cross grid=100x31
+|2: 0-1 #000000,#adcc91, 2-10 #becfc4,#26362d, 11-41 #f5f7ee,#405d4b, 42-59 #becfc4,#26362d, 60-99 d,#26362d,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-46 #e5eee5,#0d1410, 47-99 d,#0d1410,
+== snap name-draft grid=100x31 cursor=10,2
+|2: /renamed/tmp/pardes-snap/tagpath/cwd/c.txt * Save Tty Del Collapse
+== snap name-cancelled grid=100x31 cursor=41,3
+|2: /tmp/pardes-snap/tagpath/cwd/c.txt * Save Tty Del Collapse
+== snap name-committed grid=100x31 cursor=41,3
+|2: /renamed/tmp/pardes-snap/tagpath/cwd/c.txt * Save Tty Del Collapse
diff --git a/test/snapshots/tagpath.snap b/test/snapshots/tagpath.snap
index 739008a1..cf431fa1 100644
--- a/test/snapshots/tagpath.snap
+++ b/test/snapshots/tagpath.snap
@@ -1,68 +1,50 @@
-# THE PATH IN A TAG IS SELECTABLE, NOT EDITABLE.
-# tag_col/tag_anchor index the WHOLE rendered tag (prefix ++ tail) — one
-# coordinate space, no conversions: the renderer prints the cursor at tag_col
-# verbatim and a mouse column IS a tag column. So motions and sweeps reach the
-# path, a selection over it yanks and executes like any other text, and the
-# ONLY thing fenced off is EDITING: every edit op measures from the first
-# editable column (tagPrefix().len) and does nothing to the left of it.
-#
-# The prefix IS the path now — the mode word that used to lead it is a single
-# character in the layout box — so column 0 of the tag is the path's first byte.
+# Filename drafts share the selectable tag coordinate space with commands.
+# Escape cancels; Enter changes buffer identity, never renames a disk file.
lines c.txt 4
-start 30 100 c.txt
-wait 8000 New Newcol
+start 31 100 c.txt
+wait 8000 Newcol Joincol
wait 8000 c.txt
stable 700 20000
snap start
-# --- keyboard: select part of the PATH ---
-# `:` parks at the tail's start (the first EDITABLE column) — unchanged, that
-# is what makes `:w<Tab>` the same two keystrokes every time
key :
stable 400 5000
snap colon
-# 0 goes to column 0 of the RENDERED tag: the path's leading "/", a column the
-# keyboard could not name at all before
key 0
stable 400 5000
snap col0
-# E: extend to the end of the long word under the cursor — the style capture
-# shows ONE highlighted run over the whole path, read-only prefix though it is
key E
stable 400 5000
snap sel-path
snapstyle sel-path
-# y yanks the selection. Esc hands the body back; p pastes the register into
-# the file, which is the only way a snapshot can see what was yanked.
key y
key esc
settle 100
-stable 400 5000
key p
stable 400 5000
snap yanked-path
-# --- mouse: a sweep across the prefix/tail boundary ---
-# a left press on a tagline anchors a TAG sweep (not the body's block
-# selection), so the drag paints one run of the tag row. Press at col 12
-# (inside the path), release at col 42 (just past "Save" in the tail): the
-# highlight crosses the boundary — screen col 36, where the tail starts, four
-# columns left of where it used to be — in one piece, which is the whole point
-# of there being one coordinate space.
-press left 12 2
-drag left 30 2
-drag left 42 2
-release left 42 2
+# Sweep across the path / command boundary without injected padding.
+press left 12 3
+drag left 30 3
+drag left 42 3
+release left 42 3
stable 400 5000
snap drag-cross
snapstyle drag-cross
-# --- the path is inert to editing ---
-# a plain click INSIDE the path leaves the cursor there (no clamp into the
-# tail), in insert mode like any tag click — and then typing and backspace do
-# NOTHING: the tag row below is byte-identical to the one in `yanked-path`.
-press left 12 2
-release left 12 2
+key esc
+settle 100
+key :
+key 0
+key i
+text /renamed
stable 400 5000
-text ZZNOPE
-key bs
-key bs
+snap name-draft
+key esc
+stable 400 5000
+snap name-cancelled
+key :
+key 0
+key i
+text /renamed
+key enter
stable 400 5000
-snap path-inert
+snap name-committed
diff --git a/test/snapshots/theme.golden b/test/snapshots/theme.golden
index 4ec5990a..beada5be 100644
--- a/test/snapshots/theme.golden
+++ b/test/snapshots/theme.golden
@@ -1,6 +1,7 @@
-== snap helix grid=100x30 cursor=4,4
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/theme/cwd Save New Newtty Del F /tmp/pardes-snap/theme/cwd Save New Newtty Del F
+== snap orchard grid=100x31 cursor=4,5
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/theme/cwd Save Tty Del Togglett /tmp/pardes-snap/theme/cwd Save Tty Del Togglett
| ls ls
| t.txt t.txt
|
@@ -15,16 +16,540 @@
|
|
|
-| /tmp/pardes-snap/theme/cwd Save New Newtty Del F
+| /tmp/pardes-snap/theme/cwd Save Tty Del Togglett
| ls
| t.txt
-== style helix grid=100x30
-|0: 0-74 #949494,#121212, 75-99 d,#121212,
-|1: 0-1 #ffffff,#626262, 2-49 #949494,#121212, 50-51 #ffffff,#262626, 52-99 #949494,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
+== style orchard grid=100x31
+|0: 0-70 #b2c3b8,#1d2824, 71-99 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-49 d,#26362d, 50-74 #b2c3b8,#1d2824, 75-99 d,#1d2824,
+|2: 0-1 #000000,#adcc91, 2-49 #becfc4,#26362d, 50-51 #ffffff,#4c6356, 52-99 #b2c3b8,#1d2824,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|5: 0-0 d,#637f6a, 1-49 d,#0d1410, 50-50 d,#637f6a, 51-99 d,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|17: 0-1 #ffffff,#4c6356, 2-49 #b2c3b8,#1d2824, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|20: 0-0 d,#637f6a, 1-49 d,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#637f6a, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410,
+== snap dusk grid=100x31 cursor=4,5
+== style dusk grid=100x31
+|0: 0-50 #c6b6c5,#2c2630, 51-59 #fff0eb,#614453, 60-70 #c6b6c5,#2c2630, 71-99 d,#2c2630,
+|1: 0-24 #d2c2d1,#3b2f3b, 25-49 d,#3b2f3b, 50-74 #c6b6c5,#2c2630, 75-99 d,#2c2630,
+|2: 0-1 #000000,#e4b39b, 2-49 #d2c2d1,#3b2f3b, 50-51 #ffffff,#715768, 52-99 #c6b6c5,#2c2630,
+|3: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|4: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|5: 0-0 d,#8b697c, 1-49 d,#39323b, 50-50 d,#8b697c, 51-99 d,#39323b,
+|6: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|7: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|8: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|9: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|10: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|11: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|12: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|13: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|14: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|15: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|16: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|17: 0-1 #ffffff,#715768, 2-49 #c6b6c5,#2c2630, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|18: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|19: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|20: 0-0 d,#8b697c, 1-49 d,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|21: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|22: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|23: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|24: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|25: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|26: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|27: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|28: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|29: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+|30: 0-0 d,#8b697c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8b697c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b,
+== snap ink grid=100x31 cursor=4,5
+== style ink grid=100x31
+|0: 0-50 #d5e4f1,#15212c, 51-59 #ffffff,#265271, 60-70 #d5e4f1,#15212c, 71-99 d,#15212c,
+|1: 0-24 #e1eef9,#223342, 25-49 d,#223342, 50-74 #d5e4f1,#15212c, 75-99 d,#15212c,
+|2: 0-1 #000000,#86d8ff, 2-49 #e1eef9,#223342, 50-51 #ffffff,#64798b, 52-99 #d5e4f1,#15212c,
+|3: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|4: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|5: 0-0 d,#8ba7bd, 1-49 d,#000000, 50-50 d,#8ba7bd, 51-99 d,#000000,
+|6: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|7: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|8: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|9: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|10: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|11: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|12: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|13: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|14: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|15: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|16: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|17: 0-1 #ffffff,#64798b, 2-49 #d5e4f1,#15212c, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|18: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|19: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|20: 0-0 d,#8ba7bd, 1-49 d,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|21: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|22: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|23: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|24: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|25: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|26: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|27: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|28: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|29: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+|30: 0-0 d,#8ba7bd, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#8ba7bd, 51-51 d,#000000, 52-99 #f3f7fc,#000000,
+== snap paper grid=100x31 cursor=4,5
+== style paper grid=100x31
+|0: 0-50 #52625a,#e8eae3, 51-59 #203e31,#c8dfd1, 60-70 #52625a,#e8eae3, 71-99 d,#e8eae3,
+|1: 0-24 #4a5a52,#dce5dc, 25-49 d,#dce5dc, 50-74 #52625a,#e8eae3, 75-99 d,#e8eae3,
+|2: 0-1 #ffffff,#3c6b56, 2-49 #4a5a52,#dce5dc, 50-51 #000000,#91a395, 52-99 #52625a,#e8eae3,
+|3: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|4: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|5: 0-0 d,#889b8b, 1-49 d,#f5f3ed, 50-50 d,#889b8b, 51-99 d,#f5f3ed,
+|6: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|7: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|8: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|9: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|10: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|11: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|12: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|13: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|14: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|15: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|16: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|17: 0-1 #000000,#91a395, 2-49 #52625a,#e8eae3, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|18: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|19: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|20: 0-0 d,#889b8b, 1-49 d,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|21: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|22: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|23: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|24: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|25: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|26: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|27: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|28: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|29: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+|30: 0-0 d,#889b8b, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#889b8b, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed,
+== snap daybreak grid=100x31 cursor=4,5
+== style daybreak grid=100x31
+|0: 0-50 #29465e,#edf2f7, 51-59 #10364f,#c1def3, 60-70 #29465e,#edf2f7, 71-99 d,#edf2f7,
+|1: 0-24 #213e56,#dfeaf3, 25-49 d,#dfeaf3, 50-74 #29465e,#edf2f7, 75-99 d,#edf2f7,
+|2: 0-1 #ffffff,#075f91, 2-49 #213e56,#dfeaf3, 50-51 #000000,#819db1, 52-99 #29465e,#edf2f7,
+|3: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|4: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|5: 0-0 d,#6b859b, 1-49 d,#ffffff, 50-50 d,#6b859b, 51-99 d,#ffffff,
+|6: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|7: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|8: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|9: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|10: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|11: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|12: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|13: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|14: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|15: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|16: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|17: 0-1 #000000,#819db1, 2-49 #29465e,#edf2f7, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|18: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|19: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|20: 0-0 d,#6b859b, 1-49 d,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|21: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|22: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|23: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|24: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|25: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|26: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|27: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|28: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|29: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+|30: 0-0 d,#6b859b, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6b859b, 51-51 d,#ffffff, 52-99 #142d40,#ffffff,
+== snap atelier grid=100x31 cursor=4,5
+== style atelier grid=100x31
+|0: 0-50 #3d6055,#e4f0ed, 51-59 #35492d,#e5e9ae, 60-70 #3d6055,#e4f0ed, 71-99 d,#e4f0ed,
+|1: 0-24 #35584d,#d3e7df, 25-49 d,#d3e7df, 50-74 #3d6055,#e4f0ed, 75-99 d,#e4f0ed,
+|2: 0-1 #ffffff,#3e7a68, 2-49 #35584d,#d3e7df, 50-51 #000000,#99b6a3, 52-99 #3d6055,#e4f0ed,
+|3: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|4: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|5: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|6: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|7: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|8: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|9: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|10: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|11: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|12: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|13: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|14: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|15: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|16: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|17: 0-1 #000000,#99b6a3, 2-49 #3d6055,#e4f0ed, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|18: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|19: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|20: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|21: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|22: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|23: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|24: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|25: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|26: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|27: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|28: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|29: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+|30: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb,
+== snap colors-off grid=100x31 cursor=4,5
+== style colors-off grid=100x31
+|3: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-3 #293f35,#fffdeb, 4-49 d,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-53 #293f35,#fffdeb, 54-99 d,#fffdeb,
+|4: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-6 #293f35,#fffdeb, 7-49 d,#fffdeb, 50-50 d,#9da97b, 51-51 d,#fffdeb, 52-56 #293f35,#fffdeb, 57-99 d,#fffdeb,
+|6: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|7: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|8: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|9: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|10: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|11: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|12: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|13: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|14: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|15: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|16: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|17: 0-1 #000000,#99b6a3, 2-49 #3d6055,#e4f0ed, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|18: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-3 #293f35,#fffdeb, 4-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|19: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-6 #293f35,#fffdeb, 7-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|20: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|21: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|22: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|23: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|24: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|25: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|26: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|27: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|28: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|29: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+|30: 0-0 d,#9da97b, 1-49 d,#fffdeb, 50-50 d,#9da97b, 51-99 d,#fffdeb,
+== snap forge grid=100x31 cursor=4,5
+== style forge grid=100x31
+|0: 0-50 #c5c9d2,#22252b, 51-59 #e2eef4,#264f68, 60-70 #c5c9d2,#22252b, 71-99 d,#22252b,
+|1: 0-24 #d1d5de,#2d3440, 25-49 d,#2d3440, 50-74 #c5c9d2,#22252b, 75-99 d,#22252b,
+|2: 0-1 #000000,#a5c4ee, 2-49 #d1d5de,#2d3440, 50-51 #ffffff,#596577, 52-99 #c5c9d2,#22252b,
+|3: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|4: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|5: 0-0 d,#738092, 1-49 d,#0c0c0e, 50-50 d,#738092, 51-99 d,#0c0c0e,
+|6: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|7: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|8: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|9: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|10: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|11: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|12: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|13: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|14: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|15: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|16: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|17: 0-1 #ffffff,#596577, 2-49 #c5c9d2,#22252b, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|18: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|19: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|20: 0-0 d,#738092, 1-49 d,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|21: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|22: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|23: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|24: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|25: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|26: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|27: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|28: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|29: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+|30: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#738092, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e,
+== snap lagoon grid=100x31 cursor=4,5
+== style lagoon grid=100x31
+|0: 0-50 #bbd7cb,#29443f, 51-59 #e6f2f3,#395b65, 60-70 #bbd7cb,#29443f, 71-99 d,#29443f,
+|1: 0-24 #c7e3d7,#34574d, 25-49 d,#34574d, 50-74 #bbd7cb,#29443f, 75-99 d,#29443f,
+|2: 0-1 #000000,#89c7b4, 2-49 #c7e3d7,#34574d, 50-51 #ffffff,#597e71, 52-99 #bbd7cb,#29443f,
+|3: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|4: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|5: 0-0 d,#72978a, 1-49 d,#34464c, 50-50 d,#72978a, 51-99 d,#34464c,
+|6: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|7: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|8: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|9: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|10: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|11: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|12: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|13: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|14: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|15: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|16: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|17: 0-1 #ffffff,#597e71, 2-49 #bbd7cb,#29443f, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|18: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|19: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|20: 0-0 d,#72978a, 1-49 d,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|21: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|22: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|23: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|24: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|25: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|26: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|27: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|28: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|29: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+|30: 0-0 d,#72978a, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#72978a, 51-51 d,#34464c, 52-99 #bac9ce,#34464c,
+== snap solarium grid=100x31 cursor=4,5
+== style solarium grid=100x31
+|0: 0-50 #c7d4bd,#123f43, 51-59 #eee8d5,#27565c, 60-70 #c7d4bd,#123f43, 71-99 d,#123f43,
+|1: 0-24 #d3e0c9,#214e50, 25-49 d,#214e50, 50-74 #c7d4bd,#123f43, 75-99 d,#123f43,
+|2: 0-1 #000000,#d5bc72, 2-49 #d3e0c9,#214e50, 50-51 #ffffff,#4c7972, 52-99 #c7d4bd,#123f43,
+|3: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|4: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|5: 0-0 d,#69938a, 1-49 d,#173e45, 50-50 d,#69938a, 51-99 d,#173e45,
+|6: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|7: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|8: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|9: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|10: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|11: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|12: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|13: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|14: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|15: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|16: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|17: 0-1 #ffffff,#4c7972, 2-49 #c7d4bd,#123f43, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|18: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|19: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|20: 0-0 d,#69938a, 1-49 d,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|21: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|22: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|23: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|24: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|25: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|26: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|27: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|28: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|29: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+|30: 0-0 d,#69938a, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#69938a, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45,
+== snap spectrum grid=100x31 cursor=4,5
+== style spectrum grid=100x31
+|0: 0-50 #ddd8bb,#3b3830, 51-59 #fcfcfa,#51435c, 60-70 #ddd8bb,#3b3830, 71-99 d,#3b3830,
+|1: 0-24 #e9e4c7,#4d4736, 25-49 d,#4d4736, 50-74 #ddd8bb,#3b3830, 75-99 d,#3b3830,
+|2: 0-1 #000000,#ffd866, 2-49 #e9e4c7,#4d4736, 50-51 #ffffff,#8b8056, 52-99 #ddd8bb,#3b3830,
+|3: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|4: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|5: 0-0 d,#918b72, 1-49 d,#100e11, 50-50 d,#918b72, 51-99 d,#100e11,
+|6: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|7: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|8: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|9: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|10: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|11: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|12: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|13: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|14: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|15: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|16: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|17: 0-1 #ffffff,#8b8056, 2-49 #ddd8bb,#3b3830, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|18: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|19: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|20: 0-0 d,#918b72, 1-49 d,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|21: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|22: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|23: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|24: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|25: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|26: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|27: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|28: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|29: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+|30: 0-0 d,#918b72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#918b72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11,
+== snap harvest grid=100x31 cursor=4,5
+== style harvest grid=100x31
+|0: 0-50 #d5d8b8,#343b2e, 51-59 #f3f2cc,#4d5438, 60-70 #d5d8b8,#343b2e, 71-99 d,#343b2e,
+|1: 0-24 #e1e4c4,#424d38, 25-49 d,#424d38, 50-74 #d5d8b8,#343b2e, 75-99 d,#343b2e,
+|2: 0-1 #000000,#cfba8b, 2-49 #e1e4c4,#424d38, 50-51 #ffffff,#777953, 52-99 #d5d8b8,#343b2e,
+|3: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|4: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|5: 0-0 d,#858a62, 1-49 d,#100e0b, 50-50 d,#858a62, 51-99 d,#100e0b,
+|6: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|7: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|8: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|9: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|10: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|11: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|12: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|13: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|14: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|15: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|16: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|17: 0-1 #ffffff,#777953, 2-49 #d5d8b8,#343b2e, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|18: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|19: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|20: 0-0 d,#858a62, 1-49 d,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|21: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|22: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|23: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|24: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|25: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|26: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|27: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|28: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|29: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+|30: 0-0 d,#858a62, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#858a62, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b,
+== snap clay grid=100x31 cursor=4,5
+== style clay grid=100x31
+|0: 0-50 #d7d6b6,#343f36, 51-59 #fbf1c7,#4f583c, 60-70 #d7d6b6,#343f36, 71-99 d,#343f36,
+|1: 0-24 #e3e2c2,#424f40, 25-49 d,#424f40, 50-74 #d7d6b6,#343f36, 75-99 d,#343f36,
+|2: 0-1 #000000,#8ec07c, 2-49 #e3e2c2,#424f40, 50-51 #ffffff,#677752, 52-99 #d7d6b6,#343f36,
+|3: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|4: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|5: 0-0 d,#8a906b, 1-49 d,#10100e, 50-50 d,#8a906b, 51-99 d,#10100e,
+|6: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|7: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|8: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|9: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|10: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|11: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|12: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|13: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|14: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|15: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|16: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|17: 0-1 #ffffff,#677752, 2-49 #d7d6b6,#343f36, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|18: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|19: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|20: 0-0 d,#8a906b, 1-49 d,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|21: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|22: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|23: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|24: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|25: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|26: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|27: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|28: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|29: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+|30: 0-0 d,#8a906b, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8a906b, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e,
+== snap forge-black grid=100x31 cursor=4,5
+== style forge-black grid=100x31
+|0: 0-50 #c5c9d2,#22252b, 51-59 #e2eef4,#264f68, 60-70 #c5c9d2,#22252b, 71-99 d,#22252b,
+|1: 0-24 #d1d5de,#2d3440, 25-49 d,#2d3440, 50-74 #c5c9d2,#22252b, 75-99 d,#22252b,
+|2: 0-1 #000000,#a5c4ee, 2-49 #d1d5de,#2d3440, 50-51 #ffffff,#596577, 52-99 #c5c9d2,#22252b,
+|3: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|4: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|5: 0-0 d,#738092, 1-49 d,#000000, 50-50 d,#738092, 51-99 d,#000000,
+|6: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|7: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|8: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|9: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|10: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|11: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|12: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|13: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|14: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|15: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|16: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|17: 0-1 #ffffff,#596577, 2-49 #c5c9d2,#22252b, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|18: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|19: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|20: 0-0 d,#738092, 1-49 d,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|21: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|22: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|23: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|24: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|25: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|26: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|27: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|28: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|29: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+|30: 0-0 d,#738092, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738092, 51-51 d,#000000, 52-99 #f6f6f6,#000000,
+== snap forge-soft grid=100x31 cursor=4,5
+== style forge-soft grid=100x31
+|0: 0-50 #c5c9d2,#2a2d34, 51-59 #e2eef4,#264f68, 60-70 #c5c9d2,#2a2d34, 71-99 d,#2a2d34,
+|1: 0-24 #d1d5de,#373e49, 25-49 d,#373e49, 50-74 #c5c9d2,#2a2d34, 75-99 d,#2a2d34,
+|2: 0-1 #000000,#a5c4ee, 2-49 #d1d5de,#373e49, 50-51 #ffffff,#596577, 52-99 #c5c9d2,#2a2d34,
+|3: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|4: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|5: 0-0 d,#738092, 1-49 d,#35383e, 50-50 d,#738092, 51-99 d,#35383e,
+|6: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|7: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|8: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|9: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|10: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|11: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|12: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|13: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|14: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|15: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|16: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|17: 0-1 #ffffff,#596577, 2-49 #c5c9d2,#2a2d34, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|18: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|19: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|20: 0-0 d,#738092, 1-49 d,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|21: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|22: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|23: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|24: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|25: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|26: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|27: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|28: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|29: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+|30: 0-0 d,#738092, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#738092, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e,
+== snap orchard-black grid=100x31 cursor=4,5
+== style orchard-black grid=100x31
+|0: 0-50 #b2c3b8,#1d2824, 51-59 #f5f7ee,#405d4b, 60-70 #b2c3b8,#1d2824, 71-99 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-49 d,#26362d, 50-74 #b2c3b8,#1d2824, 75-99 d,#1d2824,
+|2: 0-1 #000000,#adcc91, 2-49 #becfc4,#26362d, 50-51 #ffffff,#4c6356, 52-99 #b2c3b8,#1d2824,
+|3: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|4: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|5: 0-0 d,#637f6a, 1-49 d,#000000, 50-50 d,#637f6a, 51-99 d,#000000,
+|6: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|7: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|8: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|9: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|10: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|11: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|12: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|13: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|14: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|15: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|16: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|17: 0-1 #ffffff,#4c6356, 2-49 #b2c3b8,#1d2824, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|18: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|19: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|20: 0-0 d,#637f6a, 1-49 d,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|21: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|22: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|23: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|24: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|25: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|26: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|27: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|28: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|29: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+|30: 0-0 d,#637f6a, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#637f6a, 51-51 d,#000000, 52-99 #f2f8ef,#000000,
+== snap helix grid=100x31 cursor=4,5
+== style helix grid=100x31
+|0: 0-50 #949494,#121212, 51-59 #080808,#80a0ff, 60-70 #949494,#121212, 71-99 d,#121212,
+|1: 0-24 #949494,#121212, 25-49 d,#121212, 50-74 #949494,#121212, 75-99 d,#121212,
+|2: 0-1 #ffffff,#626262, 2-49 #949494,#121212, 50-51 #ffffff,#262626, 52-99 #949494,#121212,
|3: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|4: 0-0 d,#444444, 1-49 d,#080808, 50-50 d,#444444, 51-99 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
+|4: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
+|5: 0-0 d,#444444, 1-49 d,#080808, 50-50 d,#444444, 51-99 d,#080808,
|6: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
|7: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
|8: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
@@ -35,11 +560,11 @@
|13: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
|14: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
|15: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|16: 0-1 #ffffff,#262626, 2-49 #949494,#121212, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
+|16: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
+|17: 0-1 #ffffff,#262626, 2-49 #949494,#121212, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
|18: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|19: 0-0 d,#444444, 1-49 d,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
+|19: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
+|20: 0-0 d,#444444, 1-49 d,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
|21: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
|22: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
|23: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
@@ -49,14 +574,15 @@
|27: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
|28: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
|29: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
-== snap dark grid=100x30 cursor=4,4
-== style dark grid=100x30
-|0: 0-54 #969696,#2c2a3e, 55-63 #d8c8a8,#4a3a1e, 64-74 #969696,#2c2a3e, 75-99 d,#2c2a3e,
-|1: 0-1 #ffffff,#6e4fd0, 2-49 #969696,#2c2a3e, 50-51 #ffffff,#383c54, 52-99 #969696,#2c2a3e,
-|2: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
+|30: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808,
+== snap dark grid=100x31 cursor=4,5
+== style dark grid=100x31
+|0: 0-50 #969696,#2c2a3e, 51-59 #d8c8a8,#4a3a1e, 60-70 #969696,#2c2a3e, 71-99 d,#2c2a3e,
+|1: 0-24 #969696,#2c2a3e, 25-49 d,#2c2a3e, 50-74 #969696,#2c2a3e, 75-99 d,#2c2a3e,
+|2: 0-1 #ffffff,#6e4fd0, 2-49 #969696,#2c2a3e, 50-51 #ffffff,#383c54, 52-99 #969696,#2c2a3e,
|3: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
-|4: 0-0 d,#525252, 1-49 d,d, 50-50 d,#525252, 51-99 d,d,
-|5: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
+|4: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
+|5: 0-0 d,#525252, 1-49 d,d, 50-50 d,#525252, 51-99 d,d,
|6: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
|7: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
|8: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
@@ -67,11 +593,11 @@
|13: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
|14: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
|15: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
-|16: 0-1 #ffffff,#383c54, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
-|17: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
+|16: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
+|17: 0-1 #ffffff,#383c54, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
|18: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
-|19: 0-0 d,#525252, 1-49 d,d, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
-|20: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
+|19: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
+|20: 0-0 d,#525252, 1-49 d,d, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
|21: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
|22: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
|23: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
@@ -81,14 +607,15 @@
|27: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
|28: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
|29: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
-== snap acme grid=100x30 cursor=4,4
-== style acme grid=100x30
-|0: 0-54 #000000,#eaffff, 55-63 #000000,#eeee9e, 64-74 #000000,#eaffff, 75-99 d,#eaffff,
-|1: 0-1 #ffffff,#6e4fd0, 2-49 #000000,#eaffff, 50-51 #ffffff,#383c54, 52-99 #000000,#eaffff,
-|2: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
+|30: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e,
+== snap acme grid=100x31 cursor=4,5
+== style acme grid=100x31
+|0: 0-50 #000000,#eaffff, 51-59 #000000,#eeee9e, 60-70 #000000,#eaffff, 71-99 d,#eaffff,
+|1: 0-24 #000000,#eaffff, 25-49 d,#eaffff, 50-74 #000000,#eaffff, 75-99 d,#eaffff,
+|2: 0-1 #ffffff,#6e4fd0, 2-49 #000000,#eaffff, 50-51 #ffffff,#383c54, 52-99 #000000,#eaffff,
|3: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
-|4: 0-99 d,#ffffea,
-|5: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
+|4: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
+|5: 0-99 d,#ffffea,
|6: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
|7: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
|8: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
@@ -99,11 +626,11 @@
|13: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
|14: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
|15: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
-|16: 0-1 #ffffff,#383c54, 2-49 #000000,#eaffff, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
-|17: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
+|16: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
+|17: 0-1 #ffffff,#383c54, 2-49 #000000,#eaffff, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
|18: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
-|19: 0-51 d,#ffffea, 52-99 #000000,#ffffea,
-|20: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
+|19: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
+|20: 0-51 d,#ffffea, 52-99 #000000,#ffffea,
|21: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
|22: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
|23: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
@@ -113,43 +640,15 @@
|27: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
|28: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
|29: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
-== snap colors-off grid=100x30 cursor=4,4
-== style colors-off grid=100x30
-|2: 0-1 d,#ffffea, 2-3 #000000,#ffffea, 4-51 d,#ffffea, 52-53 #000000,#ffffea, 54-99 d,#ffffea,
-|3: 0-1 d,#ffffea, 2-6 #000000,#ffffea, 7-51 d,#ffffea, 52-56 #000000,#ffffea, 57-99 d,#ffffea,
-|5: 0-99 d,#ffffea,
-|6: 0-99 d,#ffffea,
-|7: 0-99 d,#ffffea,
-|8: 0-99 d,#ffffea,
-|9: 0-99 d,#ffffea,
-|10: 0-99 d,#ffffea,
-|11: 0-99 d,#ffffea,
-|12: 0-99 d,#ffffea,
-|13: 0-99 d,#ffffea,
-|14: 0-99 d,#ffffea,
-|15: 0-99 d,#ffffea,
-|16: 0-1 #ffffff,#383c54, 2-49 #000000,#eaffff, 50-99 d,#ffffea,
-|17: 0-1 d,#ffffea, 2-3 #000000,#ffffea, 4-99 d,#ffffea,
-|18: 0-1 d,#ffffea, 2-6 #000000,#ffffea, 7-99 d,#ffffea,
-|19: 0-99 d,#ffffea,
-|20: 0-99 d,#ffffea,
-|21: 0-99 d,#ffffea,
-|22: 0-99 d,#ffffea,
-|23: 0-99 d,#ffffea,
-|24: 0-99 d,#ffffea,
-|25: 0-99 d,#ffffea,
-|26: 0-99 d,#ffffea,
-|27: 0-99 d,#ffffea,
-|28: 0-99 d,#ffffea,
-|29: 0-99 d,#ffffea,
-== snap generated grid=100x30 cursor=4,4
-== style generated grid=100x30
-|0: 0-54 #e0e0e0,#1e262e, 55-63 #e0e0e0,#303840, 64-74 #e0e0e0,#1e262e, 75-99 d,#1e262e,
-|1: 0-1 #000000,#ffa060, 2-49 #e0e0e0,#1e262e, 50-51 #ffffff,#303840, 52-99 #e0e0e0,#1e262e,
-|2: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
+|30: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea,
+== snap generated grid=100x31 cursor=4,5
+== style generated grid=100x31
+|0: 0-50 #e0e0e0,#1e262e, 51-59 #e0e0e0,#303840, 60-70 #e0e0e0,#1e262e, 71-99 d,#1e262e,
+|1: 0-24 #e0e0e0,#1e262e, 25-49 d,#1e262e, 50-74 #e0e0e0,#1e262e, 75-99 d,#1e262e,
+|2: 0-1 #000000,#ffa060, 2-49 #e0e0e0,#1e262e, 50-51 #ffffff,#303840, 52-99 #e0e0e0,#1e262e,
|3: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
-|4: 0-0 d,#303840, 1-49 d,#161e26, 50-50 d,#303840, 51-99 d,#161e26,
-|5: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
+|4: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
+|5: 0-0 d,#303840, 1-49 d,#161e26, 50-50 d,#303840, 51-99 d,#161e26,
|6: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
|7: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
|8: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
@@ -160,11 +659,11 @@
|13: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
|14: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
|15: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
-|16: 0-1 #ffffff,#303840, 2-49 #e0e0e0,#1e262e, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
-|17: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
+|16: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
+|17: 0-1 #ffffff,#303840, 2-49 #e0e0e0,#1e262e, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
|18: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
-|19: 0-0 d,#303840, 1-49 d,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
-|20: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
+|19: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
+|20: 0-0 d,#303840, 1-49 d,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
|21: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
|22: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
|23: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
@@ -174,3 +673,4 @@
|27: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
|28: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
|29: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
+|30: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26,
diff --git a/test/snapshots/theme.snap b/test/snapshots/theme.snap
index fbaf849f..2c7610b3 100644
--- a/test/snapshots/theme.snap
+++ b/test/snapshots/theme.snap
@@ -1,34 +1,38 @@
-# The theme ring, proved by style and not by text. Boot is "helix" (index 0,
-# the default): near-black page, tag bar one grey-ramp step off it, grey move
-# box. NextColor (still in the topbar) then walks to "dark" — the OLD default,
-# which has to stay reachable — then to acme-light.
-# Colors, which left the bar for its leader path, toggles the recolor passes
-# off and on from SPC t c — the same builtin either way.
-#
-# The fourth click used to come back around to helix, because the ring was
-# three long. It is not any more: everything vendor/themes exports follows the
-# three pardes ships with (pardes.zig: `curated ++ generated`), so the click
-# lands on the FIRST GENERATED theme instead. That capture is named for what it
-# is rather than for which theme it happens to be, because the generated half
-# is sorted by name and a theme dropped into vendor/themes can take the slot.
-# The wrap itself is `% themes.len` and clicking twenty times to see it is not
-# worth a golden; themesel.snap covers reaching a theme by name.
+# Native Pardes themes lead the ring. Capture both text and cell styles so
+# every palette proves the editor, tags and embedded terminal share its colors.
+# The legacy helix/dark/acme choices stay reachable, followed by generated data.
file t.txt x
-start 30 100 -n 3
+start 31 100 -n 3
wait 8000 t.txt
stable 700 20000
-snap helix
-snapstyle helix
+snap orchard
+snapstyle orchard
press middle @NextColor 1
release middle @NextColor 1
stable 700 10000
-snap dark
-snapstyle dark
+snap dusk
+snapstyle dusk
press middle @NextColor 1
release middle @NextColor 1
stable 700 10000
-snap acme
-snapstyle acme
+snap ink
+snapstyle ink
+press middle @NextColor 1
+release middle @NextColor 1
+stable 700 10000
+snap paper
+snapstyle paper
+press middle @NextColor 1
+release middle @NextColor 1
+stable 700 10000
+snap daybreak
+snapstyle daybreak
+press middle @NextColor 1
+release middle @NextColor 1
+stable 700 10000
+snap atelier
+snapstyle atelier
+# Colors still toggles the existing recolor pass through its leader binding.
key space
key t
key c
@@ -42,5 +46,65 @@ stable 700 10000
press middle @NextColor 1
release middle @NextColor 1
stable 700 10000
+snap forge
+snapstyle forge
+press middle @NextColor 1
+release middle @NextColor 1
+stable 700 10000
+snap lagoon
+snapstyle lagoon
+press middle @NextColor 1
+release middle @NextColor 1
+stable 700 10000
+snap solarium
+snapstyle solarium
+press middle @NextColor 1
+release middle @NextColor 1
+stable 700 10000
+snap spectrum
+snapstyle spectrum
+press middle @NextColor 1
+release middle @NextColor 1
+stable 700 10000
+snap harvest
+snapstyle harvest
+press middle @NextColor 1
+release middle @NextColor 1
+stable 700 10000
+snap clay
+snapstyle clay
+press middle @NextColor 1
+release middle @NextColor 1
+stable 700 10000
+snap forge-black
+snapstyle forge-black
+press middle @NextColor 1
+release middle @NextColor 1
+stable 700 10000
+snap forge-soft
+snapstyle forge-soft
+press middle @NextColor 1
+release middle @NextColor 1
+stable 700 10000
+snap orchard-black
+snapstyle orchard-black
+press middle @NextColor 1
+release middle @NextColor 1
+stable 700 10000
+snap helix
+snapstyle helix
+press middle @NextColor 1
+release middle @NextColor 1
+stable 700 10000
+snap dark
+snapstyle dark
+press middle @NextColor 1
+release middle @NextColor 1
+stable 700 10000
+snap acme
+snapstyle acme
+press middle @NextColor 1
+release middle @NextColor 1
+stable 700 10000
snap generated
snapstyle generated
diff --git a/test/snapshots/themesel.golden b/test/snapshots/themesel.golden
index e69ad3de..76d5d71b 100644
--- a/test/snapshots/themesel.golden
+++ b/test/snapshots/themesel.golden
@@ -1,6 +1,7 @@
-== snap boot grid=100x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/themesel/cwd/t.txt Save New Newtty Del
+== snap boot grid=100x31 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/themesel/cwd/t.txt Save Tty Del Collapse
| 1 line 1
| 2 line 2
| 3 line 3
@@ -29,62 +30,563 @@
| 26 line 26
| 27 line 27
| 28 line 28
-== snap list grid=100x30 cursor=7,2
-|16: /tmp/pardes-snap/themesel/cwd/+Themes Save New Newtty Del
-|17: 1 Theme helix
-|18: 2 Theme dark
-|19: 3 Theme acme
-|20: 4 Theme acid
-|21: 5 Theme acme_helix
-|22: 6 Theme adwaita_dark
-|23: 7 Theme adwaita_light
-|24: 8 Theme akari_dawn
-|25: 9 Theme akari_night
-|26: 10 Theme amberwood
-|27: 11 Theme andromeda
-|28: 12 Theme ao
-|29: 13 Theme ashen
-== snap step-helix grid=100x30 cursor=7,17
-== style step-helix grid=100x30
-|0: 0-74 #949494,#121212, 75-99 d,#121212,
-|1: 0-1 #ffffff,#262626, 2-79 #949494,#121212, 80-99 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808,
+== snap list grid=100x31 cursor=7,3
+|17: /tmp/pardes-snap/themesel/cwd/+Themes Save Tty Del Collapse
+|18: 1 # Pardes themes
+|19: 2 Theme orchard
+|20: 3 Theme dusk
+|21: 4 Theme ink
+|22: 5 Theme paper
+|23: 6 Theme daybreak
+|24: 7 Theme atelier
+|25: 8 Theme forge
+|26: 9 Theme lagoon
+|27: 10 Theme solarium
+|28: 11 Theme spectrum
+|29: 12 Theme harvest
+|30: 13 Theme clay
+== snap step-orchard grid=100x31 cursor=7,19
+== style step-orchard grid=100x31
+|0: 0-70 #b2c3b8,#1d2824, 71-99 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-99 d,#26362d,
+|2: 0-1 #ffffff,#4c6356, 2-58 #b2c3b8,#1d2824, 59-99 d,#1d2824,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-99 d,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-99 d,#0d1410,
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-99 d,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-99 d,#0d1410,
+|7: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-99 d,#0d1410,
+|8: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-99 d,#0d1410,
+|9: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-99 d,#0d1410,
+|10: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-99 d,#0d1410,
+|11: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-99 d,#0d1410,
+|12: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-99 d,#0d1410,
+|13: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-99 d,#0d1410,
+|14: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-99 d,#0d1410,
+|15: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-99 d,#0d1410,
+|16: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-13 #e5eee5,#0d1410, 14-99 d,#0d1410,
+|17: 0-1 #000000,#adcc91, 2-60 #becfc4,#26362d, 61-99 d,#26362d,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-21 #e5eee5,#0d1410, 22-99 d,#0d1410,
+|19: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-19 #e5eee5,#0d1410, 20-99 d,#0d1410,
+|20: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-16 #e5eee5,#0d1410, 17-99 d,#0d1410,
+|21: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-15 #e5eee5,#0d1410, 16-99 d,#0d1410,
+|22: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-17 #e5eee5,#0d1410, 18-99 d,#0d1410,
+|23: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-20 #e5eee5,#0d1410, 21-99 d,#0d1410,
+|24: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-19 #e5eee5,#0d1410, 20-99 d,#0d1410,
+|25: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-17 #e5eee5,#0d1410, 18-99 d,#0d1410,
+|26: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-18 #e5eee5,#0d1410, 19-99 d,#0d1410,
+|27: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-20 #e5eee5,#0d1410, 21-99 d,#0d1410,
+|28: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-20 #e5eee5,#0d1410, 21-99 d,#0d1410,
+|29: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-19 #e5eee5,#0d1410, 20-99 d,#0d1410,
+|30: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-16 #e5eee5,#0d1410, 17-99 d,#0d1410,
+== snap step-dusk grid=100x31 cursor=7,20
+== style step-dusk grid=100x31
+|0: 0-70 #c6b6c5,#2c2630, 71-99 d,#2c2630,
+|1: 0-24 #d2c2d1,#3b2f3b, 25-99 d,#3b2f3b,
+|2: 0-1 #ffffff,#715768, 2-58 #c6b6c5,#2c2630, 59-99 d,#2c2630,
+|3: 0-0 d,#8b697c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b,
+|4: 0-0 d,#8b697c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b,
+|5: 0-0 d,#8b697c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b,
+|6: 0-0 d,#8b697c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b,
+|7: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b,
+|8: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b,
+|9: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b,
+|10: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b,
+|11: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b,
+|12: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-13 #c3b6c1,#39323b, 14-99 d,#39323b,
+|13: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-13 #c3b6c1,#39323b, 14-99 d,#39323b,
+|14: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-13 #c3b6c1,#39323b, 14-99 d,#39323b,
+|15: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-13 #c3b6c1,#39323b, 14-99 d,#39323b,
+|16: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-13 #c3b6c1,#39323b, 14-99 d,#39323b,
+|17: 0-1 #000000,#e4b39b, 2-60 #d2c2d1,#3b2f3b, 61-99 d,#3b2f3b,
+|18: 0-0 d,#8b697c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-21 #c3b6c1,#39323b, 22-99 d,#39323b,
+|19: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-19 #c3b6c1,#39323b, 20-99 d,#39323b,
+|20: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #8a7986,#39323b,b 7-16 #c3b6c1,#39323b, 17-99 d,#39323b,
+|21: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-15 #c3b6c1,#39323b, 16-99 d,#39323b,
+|22: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-17 #c3b6c1,#39323b, 18-99 d,#39323b,
+|23: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-20 #c3b6c1,#39323b, 21-99 d,#39323b,
+|24: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-19 #c3b6c1,#39323b, 20-99 d,#39323b,
+|25: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-17 #c3b6c1,#39323b, 18-99 d,#39323b,
+|26: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-18 #c3b6c1,#39323b, 19-99 d,#39323b,
+|27: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-20 #c3b6c1,#39323b, 21-99 d,#39323b,
+|28: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-20 #c3b6c1,#39323b, 21-99 d,#39323b,
+|29: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-19 #c3b6c1,#39323b, 20-99 d,#39323b,
+|30: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-16 #c3b6c1,#39323b, 17-99 d,#39323b,
+== snap step-atelier grid=100x31 cursor=7,24
+== style step-atelier grid=100x31
+|0: 0-70 #3d6055,#e4f0ed, 71-99 d,#e4f0ed,
+|1: 0-24 #35584d,#d3e7df, 25-99 d,#d3e7df,
+|2: 0-1 #000000,#99b6a3, 2-58 #3d6055,#e4f0ed, 59-99 d,#e4f0ed,
+|3: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb,
+|4: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb,
+|5: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb,
+|6: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb,
+|7: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb,
+|8: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb,
+|9: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb,
+|10: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb,
+|11: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb,
+|12: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-13 #293f35,#fffdeb, 14-99 d,#fffdeb,
+|13: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-13 #293f35,#fffdeb, 14-99 d,#fffdeb,
+|14: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-13 #293f35,#fffdeb, 14-99 d,#fffdeb,
+|15: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-13 #293f35,#fffdeb, 14-99 d,#fffdeb,
+|16: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-13 #293f35,#fffdeb, 14-99 d,#fffdeb,
+|17: 0-1 #ffffff,#3e7a68, 2-60 #35584d,#d3e7df, 61-99 d,#d3e7df,
+|18: 0-0 d,#9da97b, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-21 #293f35,#fffdeb, 22-99 d,#fffdeb,
+|19: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-19 #293f35,#fffdeb, 20-99 d,#fffdeb,
+|20: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-16 #293f35,#fffdeb, 17-99 d,#fffdeb,
+|21: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-15 #293f35,#fffdeb, 16-99 d,#fffdeb,
+|22: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-17 #293f35,#fffdeb, 18-99 d,#fffdeb,
+|23: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-20 #293f35,#fffdeb, 21-99 d,#fffdeb,
+|24: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #889078,#fffdeb,b 7-19 #293f35,#fffdeb, 20-99 d,#fffdeb,
+|25: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-17 #293f35,#fffdeb, 18-99 d,#fffdeb,
+|26: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-18 #293f35,#fffdeb, 19-99 d,#fffdeb,
+|27: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-20 #293f35,#fffdeb, 21-99 d,#fffdeb,
+|28: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-20 #293f35,#fffdeb, 21-99 d,#fffdeb,
+|29: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-19 #293f35,#fffdeb, 20-99 d,#fffdeb,
+|30: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-16 #293f35,#fffdeb, 17-99 d,#fffdeb,
+== snap step-forge grid=100x31 cursor=7,25
+== style step-forge grid=100x31
+|0: 0-70 #c5c9d2,#22252b, 71-99 d,#22252b,
+|1: 0-24 #d1d5de,#2d3440, 25-99 d,#2d3440,
+|2: 0-1 #ffffff,#596577, 2-58 #c5c9d2,#22252b, 59-99 d,#22252b,
+|3: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e,
+|4: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e,
+|5: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e,
+|6: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e,
+|7: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e,
+|8: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e,
+|9: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e,
+|10: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e,
+|11: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e,
+|12: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-13 #e5e5e5,#0c0c0e, 14-99 d,#0c0c0e,
+|13: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-13 #e5e5e5,#0c0c0e, 14-99 d,#0c0c0e,
+|14: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-13 #e5e5e5,#0c0c0e, 14-99 d,#0c0c0e,
+|15: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-13 #e5e5e5,#0c0c0e, 14-99 d,#0c0c0e,
+|16: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-13 #e5e5e5,#0c0c0e, 14-99 d,#0c0c0e,
+|17: 0-1 #000000,#a5c4ee, 2-60 #d1d5de,#2d3440, 61-99 d,#2d3440,
+|18: 0-0 d,#738092, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-21 #e5e5e5,#0c0c0e, 22-99 d,#0c0c0e,
+|19: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-19 #e5e5e5,#0c0c0e, 20-99 d,#0c0c0e,
+|20: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-16 #e5e5e5,#0c0c0e, 17-99 d,#0c0c0e,
+|21: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-15 #e5e5e5,#0c0c0e, 16-99 d,#0c0c0e,
+|22: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-17 #e5e5e5,#0c0c0e, 18-99 d,#0c0c0e,
+|23: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-20 #e5e5e5,#0c0c0e, 21-99 d,#0c0c0e,
+|24: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-19 #e5e5e5,#0c0c0e, 20-99 d,#0c0c0e,
+|25: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #6a6d74,#0c0c0e,b 7-17 #e5e5e5,#0c0c0e, 18-99 d,#0c0c0e,
+|26: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-18 #e5e5e5,#0c0c0e, 19-99 d,#0c0c0e,
+|27: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-20 #e5e5e5,#0c0c0e, 21-99 d,#0c0c0e,
+|28: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-20 #e5e5e5,#0c0c0e, 21-99 d,#0c0c0e,
+|29: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-19 #e5e5e5,#0c0c0e, 20-99 d,#0c0c0e,
+|30: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-16 #e5e5e5,#0c0c0e, 17-99 d,#0c0c0e,
+== snap step-lagoon grid=100x31 cursor=7,26
+== style step-lagoon grid=100x31
+|0: 0-70 #bbd7cb,#29443f, 71-99 d,#29443f,
+|1: 0-24 #c7e3d7,#34574d, 25-99 d,#34574d,
+|2: 0-1 #ffffff,#597e71, 2-58 #bbd7cb,#29443f, 59-99 d,#29443f,
+|3: 0-0 d,#72978a, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c,
+|4: 0-0 d,#72978a, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c,
+|5: 0-0 d,#72978a, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c,
+|6: 0-0 d,#72978a, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c,
+|7: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c,
+|8: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c,
+|9: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c,
+|10: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c,
+|11: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c,
+|12: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-13 #bac9ce,#34464c, 14-99 d,#34464c,
+|13: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-13 #bac9ce,#34464c, 14-99 d,#34464c,
+|14: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-13 #bac9ce,#34464c, 14-99 d,#34464c,
+|15: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-13 #bac9ce,#34464c, 14-99 d,#34464c,
+|16: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-13 #bac9ce,#34464c, 14-99 d,#34464c,
+|17: 0-1 #000000,#89c7b4, 2-60 #c7e3d7,#34574d, 61-99 d,#34574d,
+|18: 0-0 d,#72978a, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-21 #bac9ce,#34464c, 22-99 d,#34464c,
+|19: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-19 #bac9ce,#34464c, 20-99 d,#34464c,
+|20: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-16 #bac9ce,#34464c, 17-99 d,#34464c,
+|21: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-15 #bac9ce,#34464c, 16-99 d,#34464c,
+|22: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-17 #bac9ce,#34464c, 18-99 d,#34464c,
+|23: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-20 #bac9ce,#34464c, 21-99 d,#34464c,
+|24: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-19 #bac9ce,#34464c, 20-99 d,#34464c,
+|25: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-17 #bac9ce,#34464c, 18-99 d,#34464c,
+|26: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #83999c,#34464c,b 7-18 #bac9ce,#34464c, 19-99 d,#34464c,
+|27: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-20 #bac9ce,#34464c, 21-99 d,#34464c,
+|28: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-20 #bac9ce,#34464c, 21-99 d,#34464c,
+|29: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-19 #bac9ce,#34464c, 20-99 d,#34464c,
+|30: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-16 #bac9ce,#34464c, 17-99 d,#34464c,
+== snap step-solarium grid=100x31 cursor=7,27
+== style step-solarium grid=100x31
+|0: 0-70 #c7d4bd,#123f43, 71-99 d,#123f43,
+|1: 0-24 #d3e0c9,#214e50, 25-99 d,#214e50,
+|2: 0-1 #ffffff,#4c7972, 2-58 #c7d4bd,#123f43, 59-99 d,#123f43,
+|3: 0-0 d,#69938a, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45,
+|4: 0-0 d,#69938a, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45,
+|5: 0-0 d,#69938a, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45,
+|6: 0-0 d,#69938a, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45,
+|7: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45,
+|8: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45,
+|9: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45,
+|10: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45,
+|11: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45,
+|12: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-13 #a7b7ae,#173e45, 14-99 d,#173e45,
+|13: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-13 #a7b7ae,#173e45, 14-99 d,#173e45,
+|14: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-13 #a7b7ae,#173e45, 14-99 d,#173e45,
+|15: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-13 #a7b7ae,#173e45, 14-99 d,#173e45,
+|16: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-13 #a7b7ae,#173e45, 14-99 d,#173e45,
+|17: 0-1 #000000,#d5bc72, 2-60 #d3e0c9,#214e50, 61-99 d,#214e50,
+|18: 0-0 d,#69938a, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-21 #a7b7ae,#173e45, 22-99 d,#173e45,
+|19: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-19 #a7b7ae,#173e45, 20-99 d,#173e45,
+|20: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-16 #a7b7ae,#173e45, 17-99 d,#173e45,
+|21: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-15 #a7b7ae,#173e45, 16-99 d,#173e45,
+|22: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-17 #a7b7ae,#173e45, 18-99 d,#173e45,
+|23: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-20 #a7b7ae,#173e45, 21-99 d,#173e45,
+|24: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-19 #a7b7ae,#173e45, 20-99 d,#173e45,
+|25: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-17 #a7b7ae,#173e45, 18-99 d,#173e45,
+|26: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-18 #a7b7ae,#173e45, 19-99 d,#173e45,
+|27: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #6c8684,#173e45,b 7-20 #a7b7ae,#173e45, 21-99 d,#173e45,
+|28: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-20 #a7b7ae,#173e45, 21-99 d,#173e45,
+|29: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-19 #a7b7ae,#173e45, 20-99 d,#173e45,
+|30: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-16 #a7b7ae,#173e45, 17-99 d,#173e45,
+== snap step-spectrum grid=100x31 cursor=7,27
+|18: 2 Theme orchard
+|19: 3 Theme dusk
+|20: 4 Theme ink
+|21: 5 Theme paper
+|22: 6 Theme daybreak
+|23: 7 Theme atelier
+|24: 8 Theme forge
+|25: 9 Theme lagoon
+|26: 10 Theme solarium
+|27: 11 Theme spectrum
+|28: 12 Theme harvest
+|29: 13 Theme clay
+|30: 14 Theme forge_black
+== style step-spectrum grid=100x31
+|0: 0-70 #ddd8bb,#3b3830, 71-99 d,#3b3830,
+|1: 0-24 #e9e4c7,#4d4736, 25-99 d,#4d4736,
+|2: 0-1 #ffffff,#8b8056, 2-58 #ddd8bb,#3b3830, 59-99 d,#3b3830,
+|3: 0-0 d,#918b72, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11,
+|4: 0-0 d,#918b72, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11,
+|5: 0-0 d,#918b72, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11,
+|6: 0-0 d,#918b72, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11,
+|7: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11,
+|8: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11,
+|9: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11,
+|10: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11,
+|11: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11,
+|12: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-13 #fcfcfa,#100e11, 14-99 d,#100e11,
+|13: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-13 #fcfcfa,#100e11, 14-99 d,#100e11,
+|14: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-13 #fcfcfa,#100e11, 14-99 d,#100e11,
+|15: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-13 #fcfcfa,#100e11, 14-99 d,#100e11,
+|16: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-13 #fcfcfa,#100e11, 14-99 d,#100e11,
+|17: 0-1 #000000,#ffd866, 2-60 #e9e4c7,#4d4736, 61-99 d,#4d4736,
+|18: 0-0 d,#918b72, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-19 #fcfcfa,#100e11, 20-99 d,#100e11,
+|19: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-16 #fcfcfa,#100e11, 17-99 d,#100e11,
+|20: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-15 #fcfcfa,#100e11, 16-99 d,#100e11,
+|21: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-17 #fcfcfa,#100e11, 18-99 d,#100e11,
+|22: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-20 #fcfcfa,#100e11, 21-99 d,#100e11,
+|23: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-19 #fcfcfa,#100e11, 20-99 d,#100e11,
+|24: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-17 #fcfcfa,#100e11, 18-99 d,#100e11,
+|25: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-18 #fcfcfa,#100e11, 19-99 d,#100e11,
+|26: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-20 #fcfcfa,#100e11, 21-99 d,#100e11,
+|27: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #706973,#100e11,b 7-20 #fcfcfa,#100e11, 21-99 d,#100e11,
+|28: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-19 #fcfcfa,#100e11, 20-99 d,#100e11,
+|29: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-16 #fcfcfa,#100e11, 17-99 d,#100e11,
+|30: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-23 #fcfcfa,#100e11, 24-99 d,#100e11,
+== snap step-harvest grid=100x31 cursor=7,27
+|18: 3 Theme dusk
+|19: 4 Theme ink
+|20: 5 Theme paper
+|21: 6 Theme daybreak
+|22: 7 Theme atelier
+|23: 8 Theme forge
+|24: 9 Theme lagoon
+|25: 10 Theme solarium
+|26: 11 Theme spectrum
+|27: 12 Theme harvest
+|28: 13 Theme clay
+|29: 14 Theme forge_black
+|30: 15 Theme forge_soft
+== style step-harvest grid=100x31
+|0: 0-70 #d5d8b8,#343b2e, 71-99 d,#343b2e,
+|1: 0-24 #e1e4c4,#424d38, 25-99 d,#424d38,
+|2: 0-1 #ffffff,#777953, 2-58 #d5d8b8,#343b2e, 59-99 d,#343b2e,
+|3: 0-0 d,#858a62, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b,
+|4: 0-0 d,#858a62, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b,
+|5: 0-0 d,#858a62, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b,
+|6: 0-0 d,#858a62, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b,
+|7: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b,
+|8: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b,
+|9: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b,
+|10: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b,
+|11: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b,
+|12: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-13 #f3f2cc,#100e0b, 14-99 d,#100e0b,
+|13: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-13 #f3f2cc,#100e0b, 14-99 d,#100e0b,
+|14: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-13 #f3f2cc,#100e0b, 14-99 d,#100e0b,
+|15: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-13 #f3f2cc,#100e0b, 14-99 d,#100e0b,
+|16: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-13 #f3f2cc,#100e0b, 14-99 d,#100e0b,
+|17: 0-1 #000000,#cfba8b, 2-60 #e1e4c4,#424d38, 61-99 d,#424d38,
+|18: 0-0 d,#858a62, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-16 #f3f2cc,#100e0b, 17-99 d,#100e0b,
+|19: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-15 #f3f2cc,#100e0b, 16-99 d,#100e0b,
+|20: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-17 #f3f2cc,#100e0b, 18-99 d,#100e0b,
+|21: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-20 #f3f2cc,#100e0b, 21-99 d,#100e0b,
+|22: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-19 #f3f2cc,#100e0b, 20-99 d,#100e0b,
+|23: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-17 #f3f2cc,#100e0b, 18-99 d,#100e0b,
+|24: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-18 #f3f2cc,#100e0b, 19-99 d,#100e0b,
+|25: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-20 #f3f2cc,#100e0b, 21-99 d,#100e0b,
+|26: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-20 #f3f2cc,#100e0b, 21-99 d,#100e0b,
+|27: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #726c5e,#100e0b,b 7-19 #f3f2cc,#100e0b, 20-99 d,#100e0b,
+|28: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-16 #f3f2cc,#100e0b, 17-99 d,#100e0b,
+|29: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-23 #f3f2cc,#100e0b, 24-99 d,#100e0b,
+|30: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-22 #f3f2cc,#100e0b, 23-99 d,#100e0b,
+== snap step-clay grid=100x31 cursor=7,27
+|18: 4 Theme ink
+|19: 5 Theme paper
+|20: 6 Theme daybreak
+|21: 7 Theme atelier
+|22: 8 Theme forge
+|23: 9 Theme lagoon
+|24: 10 Theme solarium
+|25: 11 Theme spectrum
+|26: 12 Theme harvest
+|27: 13 Theme clay
+|28: 14 Theme forge_black
+|29: 15 Theme forge_soft
+|30: 16 Theme orchard_black
+== style step-clay grid=100x31
+|0: 0-70 #d7d6b6,#343f36, 71-99 d,#343f36,
+|1: 0-24 #e3e2c2,#424f40, 25-99 d,#424f40,
+|2: 0-1 #ffffff,#677752, 2-58 #d7d6b6,#343f36, 59-99 d,#343f36,
+|3: 0-0 d,#8a906b, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-12 #f3e5bc,#10100e, 13-99 d,#10100e,
+|4: 0-0 d,#8a906b, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-12 #f3e5bc,#10100e, 13-99 d,#10100e,
+|5: 0-0 d,#8a906b, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-12 #f3e5bc,#10100e, 13-99 d,#10100e,
+|6: 0-0 d,#8a906b, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-12 #f3e5bc,#10100e, 13-99 d,#10100e,
+|7: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-12 #f3e5bc,#10100e, 13-99 d,#10100e,
+|8: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-12 #f3e5bc,#10100e, 13-99 d,#10100e,
+|9: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-12 #f3e5bc,#10100e, 13-99 d,#10100e,
+|10: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-12 #f3e5bc,#10100e, 13-99 d,#10100e,
+|11: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-12 #f3e5bc,#10100e, 13-99 d,#10100e,
+|12: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-13 #f3e5bc,#10100e, 14-99 d,#10100e,
+|13: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-13 #f3e5bc,#10100e, 14-99 d,#10100e,
+|14: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-13 #f3e5bc,#10100e, 14-99 d,#10100e,
+|15: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-13 #f3e5bc,#10100e, 14-99 d,#10100e,
+|16: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-13 #f3e5bc,#10100e, 14-99 d,#10100e,
+|17: 0-1 #000000,#8ec07c, 2-60 #e3e2c2,#424f40, 61-99 d,#424f40,
+|18: 0-0 d,#8a906b, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-15 #f3e5bc,#10100e, 16-99 d,#10100e,
+|19: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-17 #f3e5bc,#10100e, 18-99 d,#10100e,
+|20: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-20 #f3e5bc,#10100e, 21-99 d,#10100e,
+|21: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-19 #f3e5bc,#10100e, 20-99 d,#10100e,
+|22: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-17 #f3e5bc,#10100e, 18-99 d,#10100e,
+|23: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-18 #f3e5bc,#10100e, 19-99 d,#10100e,
+|24: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-20 #f3e5bc,#10100e, 21-99 d,#10100e,
+|25: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-20 #f3e5bc,#10100e, 21-99 d,#10100e,
+|26: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-19 #f3e5bc,#10100e, 20-99 d,#10100e,
+|27: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #716c5d,#10100e,b 7-16 #f3e5bc,#10100e, 17-99 d,#10100e,
+|28: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-23 #f3e5bc,#10100e, 24-99 d,#10100e,
+|29: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-22 #f3e5bc,#10100e, 23-99 d,#10100e,
+|30: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-25 #f3e5bc,#10100e, 26-99 d,#10100e,
+== snap step-forge-black grid=100x31 cursor=7,27
+|18: 5 Theme paper
+|19: 6 Theme daybreak
+|20: 7 Theme atelier
+|21: 8 Theme forge
+|22: 9 Theme lagoon
+|23: 10 Theme solarium
+|24: 11 Theme spectrum
+|25: 12 Theme harvest
+|26: 13 Theme clay
+|27: 14 Theme forge_black
+|28: 15 Theme forge_soft
+|29: 16 Theme orchard_black
+|30: 17
+== style step-forge-black grid=100x31
+|0: 0-70 #c5c9d2,#22252b, 71-99 d,#22252b,
+|1: 0-24 #d1d5de,#2d3440, 25-99 d,#2d3440,
+|2: 0-1 #ffffff,#596577, 2-58 #c5c9d2,#22252b, 59-99 d,#22252b,
+|3: 0-0 d,#738092, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000,
+|4: 0-0 d,#738092, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000,
+|5: 0-0 d,#738092, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000,
+|6: 0-0 d,#738092, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000,
+|7: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000,
+|8: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000,
+|9: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000,
+|10: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000,
+|11: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000,
+|12: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-13 #f6f6f6,#000000, 14-99 d,#000000,
+|13: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-13 #f6f6f6,#000000, 14-99 d,#000000,
+|14: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-13 #f6f6f6,#000000, 14-99 d,#000000,
+|15: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-13 #f6f6f6,#000000, 14-99 d,#000000,
+|16: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-13 #f6f6f6,#000000, 14-99 d,#000000,
+|17: 0-1 #000000,#a5c4ee, 2-60 #d1d5de,#2d3440, 61-99 d,#2d3440,
+|18: 0-0 d,#738092, 1-1 d,#000000, 2-6 #62656c,#000000, 7-17 #f6f6f6,#000000, 18-99 d,#000000,
+|19: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-20 #f6f6f6,#000000, 21-99 d,#000000,
+|20: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-19 #f6f6f6,#000000, 20-99 d,#000000,
+|21: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-17 #f6f6f6,#000000, 18-99 d,#000000,
+|22: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-18 #f6f6f6,#000000, 19-99 d,#000000,
+|23: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-20 #f6f6f6,#000000, 21-99 d,#000000,
+|24: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-20 #f6f6f6,#000000, 21-99 d,#000000,
+|25: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-19 #f6f6f6,#000000, 20-99 d,#000000,
+|26: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-16 #f6f6f6,#000000, 17-99 d,#000000,
+|27: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #6a6d74,#000000,b 7-23 #f6f6f6,#000000, 24-99 d,#000000,
+|28: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-22 #f6f6f6,#000000, 23-99 d,#000000,
+|29: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-25 #f6f6f6,#000000, 26-99 d,#000000,
+|30: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-99 d,#000000,
+== snap step-forge-soft grid=100x31 cursor=7,27
+|18: 6 Theme daybreak
+|19: 7 Theme atelier
+|20: 8 Theme forge
+|21: 9 Theme lagoon
+|22: 10 Theme solarium
+|23: 11 Theme spectrum
+|24: 12 Theme harvest
+|25: 13 Theme clay
+|26: 14 Theme forge_black
+|27: 15 Theme forge_soft
+|28: 16 Theme orchard_black
+|29: 17
+|30: 18 # Legacy and imported themes
+== style step-forge-soft grid=100x31
+|0: 0-70 #c5c9d2,#2a2d34, 71-99 d,#2a2d34,
+|1: 0-24 #d1d5de,#373e49, 25-99 d,#373e49,
+|2: 0-1 #ffffff,#596577, 2-58 #c5c9d2,#2a2d34, 59-99 d,#2a2d34,
+|3: 0-0 d,#738092, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e,
+|4: 0-0 d,#738092, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e,
+|5: 0-0 d,#738092, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e,
+|6: 0-0 d,#738092, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e,
+|7: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e,
+|8: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e,
+|9: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e,
+|10: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e,
+|11: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e,
+|12: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-13 #bfc3cc,#35383e, 14-99 d,#35383e,
+|13: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-13 #bfc3cc,#35383e, 14-99 d,#35383e,
+|14: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-13 #bfc3cc,#35383e, 14-99 d,#35383e,
+|15: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-13 #bfc3cc,#35383e, 14-99 d,#35383e,
+|16: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-13 #bfc3cc,#35383e, 14-99 d,#35383e,
+|17: 0-1 #000000,#a5c4ee, 2-60 #d1d5de,#373e49, 61-99 d,#373e49,
+|18: 0-0 d,#738092, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-20 #bfc3cc,#35383e, 21-99 d,#35383e,
+|19: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-19 #bfc3cc,#35383e, 20-99 d,#35383e,
+|20: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-17 #bfc3cc,#35383e, 18-99 d,#35383e,
+|21: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-18 #bfc3cc,#35383e, 19-99 d,#35383e,
+|22: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-20 #bfc3cc,#35383e, 21-99 d,#35383e,
+|23: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-20 #bfc3cc,#35383e, 21-99 d,#35383e,
+|24: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-19 #bfc3cc,#35383e, 20-99 d,#35383e,
+|25: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-16 #bfc3cc,#35383e, 17-99 d,#35383e,
+|26: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-23 #bfc3cc,#35383e, 24-99 d,#35383e,
+|27: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #8e9199,#35383e,b 7-22 #bfc3cc,#35383e, 23-99 d,#35383e,
+|28: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-25 #bfc3cc,#35383e, 26-99 d,#35383e,
+|29: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-99 d,#35383e,
+|30: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-34 #bfc3cc,#35383e, 35-99 d,#35383e,
+== snap step-orchard-black grid=100x31 cursor=7,27
+|18: 7 Theme atelier
+|19: 8 Theme forge
+|20: 9 Theme lagoon
+|21: 10 Theme solarium
+|22: 11 Theme spectrum
+|23: 12 Theme harvest
+|24: 13 Theme clay
+|25: 14 Theme forge_black
+|26: 15 Theme forge_soft
+|27: 16 Theme orchard_black
+|28: 17
+|29: 18 # Legacy and imported themes
+|30: 19 Theme helix
+== style step-orchard-black grid=100x31
+|0: 0-70 #b2c3b8,#1d2824, 71-99 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-99 d,#26362d,
+|2: 0-1 #ffffff,#4c6356, 2-58 #b2c3b8,#1d2824, 59-99 d,#1d2824,
+|3: 0-0 d,#637f6a, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000,
+|4: 0-0 d,#637f6a, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000,
+|5: 0-0 d,#637f6a, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000,
+|6: 0-0 d,#637f6a, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000,
+|7: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000,
+|8: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000,
+|9: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000,
+|10: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000,
+|11: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000,
+|12: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-13 #f2f8ef,#000000, 14-99 d,#000000,
+|13: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-13 #f2f8ef,#000000, 14-99 d,#000000,
+|14: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-13 #f2f8ef,#000000, 14-99 d,#000000,
+|15: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-13 #f2f8ef,#000000, 14-99 d,#000000,
+|16: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-13 #f2f8ef,#000000, 14-99 d,#000000,
+|17: 0-1 #000000,#adcc91, 2-60 #becfc4,#26362d, 61-99 d,#26362d,
+|18: 0-0 d,#637f6a, 1-1 d,#000000, 2-6 #59675c,#000000, 7-19 #f2f8ef,#000000, 20-99 d,#000000,
+|19: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-17 #f2f8ef,#000000, 18-99 d,#000000,
+|20: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-18 #f2f8ef,#000000, 19-99 d,#000000,
+|21: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-20 #f2f8ef,#000000, 21-99 d,#000000,
+|22: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-20 #f2f8ef,#000000, 21-99 d,#000000,
+|23: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-19 #f2f8ef,#000000, 20-99 d,#000000,
+|24: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-16 #f2f8ef,#000000, 17-99 d,#000000,
+|25: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-23 #f2f8ef,#000000, 24-99 d,#000000,
+|26: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-22 #f2f8ef,#000000, 23-99 d,#000000,
+|27: 0-0 d,#111813, 1-1 d,#000000, 2-6 #616f64,#000000,b 7-25 #f2f8ef,#000000, 26-99 d,#000000,
+|28: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-99 d,#000000,
+|29: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-34 #f2f8ef,#000000, 35-99 d,#000000,
+|30: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-17 #f2f8ef,#000000, 18-99 d,#000000,
+== snap step-helix grid=100x31 cursor=7,27
+|18: 10 Theme solarium
+|19: 11 Theme spectrum
+|20: 12 Theme harvest
+|21: 13 Theme clay
+|22: 14 Theme forge_black
+|23: 15 Theme forge_soft
+|24: 16 Theme orchard_black
+|25: 17
+|26: 18 # Legacy and imported themes
+|27: 19 Theme helix
+|28: 20 Theme dark
+|29: 21 Theme acme
+|30: 22 Theme acid
+== style step-helix grid=100x31
+|0: 0-70 #949494,#121212, 71-99 d,#121212,
+|1: 0-24 #949494,#121212, 25-99 d,#121212,
+|2: 0-1 #ffffff,#262626, 2-58 #949494,#121212, 59-99 d,#121212,
|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808,
|4: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808,
|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808,
-|6: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808,
+|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808,
|7: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808,
|8: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808,
|9: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808,
|10: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808,
-|11: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-99 d,#080808,
+|11: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808,
|12: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-99 d,#080808,
|13: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-99 d,#080808,
|14: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-99 d,#080808,
|15: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-99 d,#080808,
-|16: 0-1 #ffffff,#626262, 2-79 #949494,#121212, 80-99 d,#121212,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-6 #949494,#121212, 7-17 #bdbdbd,#080808, 18-99 d,#080808,
-|18: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-16 #bdbdbd,#080808, 17-99 d,#080808,
-|19: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-16 #bdbdbd,#080808, 17-99 d,#080808,
-|20: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-16 #bdbdbd,#080808, 17-99 d,#080808,
-|21: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-22 #bdbdbd,#080808, 23-99 d,#080808,
-|22: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-24 #bdbdbd,#080808, 25-99 d,#080808,
-|23: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-25 #bdbdbd,#080808, 26-99 d,#080808,
-|24: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-22 #bdbdbd,#080808, 23-99 d,#080808,
-|25: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-23 #bdbdbd,#080808, 24-99 d,#080808,
-|26: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-21 #bdbdbd,#080808, 22-99 d,#080808,
-|27: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-21 #bdbdbd,#080808, 22-99 d,#080808,
-|28: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-14 #bdbdbd,#080808, 15-99 d,#080808,
-|29: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-17 #bdbdbd,#080808, 18-99 d,#080808,
-== snap step-dark grid=100x30 cursor=7,18
-== style step-dark grid=100x30
-|0: 0-74 #969696,#2c2a3e, 75-99 d,#2c2a3e,
-|1: 0-1 #ffffff,#383c54, 2-79 #969696,#2c2a3e, 80-99 d,#2c2a3e,
-|2: 0-0 d,#525252, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
+|16: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-99 d,#080808,
+|17: 0-1 #ffffff,#626262, 2-60 #949494,#121212, 61-99 d,#121212,
+|18: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-20 #bdbdbd,#080808, 21-99 d,#080808,
+|19: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-20 #bdbdbd,#080808, 21-99 d,#080808,
+|20: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-19 #bdbdbd,#080808, 20-99 d,#080808,
+|21: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-16 #bdbdbd,#080808, 17-99 d,#080808,
+|22: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-23 #bdbdbd,#080808, 24-99 d,#080808,
+|23: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-22 #bdbdbd,#080808, 23-99 d,#080808,
+|24: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-25 #bdbdbd,#080808, 26-99 d,#080808,
+|25: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808,
+|26: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-34 #bdbdbd,#080808, 35-99 d,#080808,
+|27: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808,b 7-17 #bdbdbd,#080808, 18-99 d,#080808,
+|28: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-16 #bdbdbd,#080808, 17-99 d,#080808,
+|29: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-16 #bdbdbd,#080808, 17-99 d,#080808,
+|30: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-16 #bdbdbd,#080808, 17-99 d,#080808,
+== snap step-dark grid=100x31 cursor=7,27
+|18: 11 Theme spectrum
+|19: 12 Theme harvest
+|20: 13 Theme clay
+|21: 14 Theme forge_black
+|22: 15 Theme forge_soft
+|23: 16 Theme orchard_black
+|24: 17
+|25: 18 # Legacy and imported themes
+|26: 19 Theme helix
+|27: 20 Theme dark
+|28: 21 Theme acme
+|29: 22 Theme acid
+|30: 23 Theme acme_helix
+== style step-dark grid=100x31
+|0: 0-70 #969696,#2c2a3e, 71-99 d,#2c2a3e,
+|1: 0-24 #969696,#2c2a3e, 25-99 d,#2c2a3e,
+|2: 0-1 #ffffff,#383c54, 2-58 #969696,#2c2a3e, 59-99 d,#2c2a3e,
|3: 0-0 d,#525252, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
|4: 0-0 d,#525252, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
|5: 0-0 d,#525252, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
-|6: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
+|6: 0-0 d,#525252, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
|7: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
|8: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
|9: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
@@ -94,9 +596,9 @@
|13: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
|14: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
|15: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
-|16: 0-1 #ffffff,#6e4fd0, 2-79 #969696,#2c2a3e, 80-99 d,#2c2a3e,
-|17: 0-0 d,#525252, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
-|18: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #969696,#2c2a3e, 7-99 d,d,
+|16: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
+|17: 0-1 #ffffff,#6e4fd0, 2-60 #969696,#2c2a3e, 61-99 d,#2c2a3e,
+|18: 0-0 d,#525252, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
|19: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
|20: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
|21: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
@@ -105,143 +607,172 @@
|24: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
|25: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
|26: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
-|27: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
+|27: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d,b 7-99 d,d,
|28: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
|29: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
-== snap step-acme grid=100x30 cursor=7,19
-== style step-acme grid=100x30
-|0: 0-74 #000000,#eaffff, 75-99 d,#eaffff,
-|1: 0-1 #ffffff,#383c54, 2-79 #000000,#eaffff, 80-99 d,#eaffff,
-|2: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
+|30: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d,
+== snap step-acme grid=100x31 cursor=7,27
+|18: 12 Theme harvest
+|19: 13 Theme clay
+|20: 14 Theme forge_black
+|21: 15 Theme forge_soft
+|22: 16 Theme orchard_black
+|23: 17
+|24: 18 # Legacy and imported themes
+|25: 19 Theme helix
+|26: 20 Theme dark
+|27: 21 Theme acme
+|28: 22 Theme acid
+|29: 23 Theme acme_helix
+|30: 24 Theme adwaita_dark
+== style step-acme grid=100x31
+|0: 0-70 #000000,#eaffff, 71-99 d,#eaffff,
+|1: 0-24 #000000,#eaffff, 25-99 d,#eaffff,
+|2: 0-1 #ffffff,#383c54, 2-58 #000000,#eaffff, 59-99 d,#eaffff,
|3: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
|4: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
|5: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
-|6: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
+|6: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
|7: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
|8: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
|9: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
|10: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
-|11: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
+|11: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
|12: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
|13: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
|14: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
|15: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
-|16: 0-1 #ffffff,#6e4fd0, 2-79 #000000,#eaffff, 80-99 d,#eaffff,
-|17: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-17 #000000,#ffffea, 18-99 d,#ffffea,
-|18: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-16 #000000,#ffffea, 17-99 d,#ffffea,
-|19: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #000000,#eaffff, 7-16 #000000,#ffffea, 17-99 d,#ffffea,
-|20: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-16 #000000,#ffffea, 17-99 d,#ffffea,
+|16: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
+|17: 0-1 #ffffff,#6e4fd0, 2-60 #000000,#eaffff, 61-99 d,#eaffff,
+|18: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-19 #000000,#ffffea, 20-99 d,#ffffea,
+|19: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-16 #000000,#ffffea, 17-99 d,#ffffea,
+|20: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-23 #000000,#ffffea, 24-99 d,#ffffea,
|21: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-22 #000000,#ffffea, 23-99 d,#ffffea,
-|22: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-24 #000000,#ffffea, 25-99 d,#ffffea,
-|23: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-25 #000000,#ffffea, 26-99 d,#ffffea,
-|24: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-22 #000000,#ffffea, 23-99 d,#ffffea,
-|25: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-23 #000000,#ffffea, 24-99 d,#ffffea,
-|26: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-21 #000000,#ffffea, 22-99 d,#ffffea,
-|27: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-21 #000000,#ffffea, 22-99 d,#ffffea,
-|28: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-14 #000000,#ffffea, 15-99 d,#ffffea,
-|29: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-17 #000000,#ffffea, 18-99 d,#ffffea,
-== snap step-generated grid=100x30 cursor=7,20
-== style step-generated grid=100x30
-|0: 0-74 #e0e0e0,#1e262e, 75-99 d,#1e262e,
-|1: 0-1 #ffffff,#303840, 2-79 #e0e0e0,#1e262e, 80-99 d,#1e262e,
-|2: 0-0 d,#303840, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26,
+|22: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-25 #000000,#ffffea, 26-99 d,#ffffea,
+|23: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-99 d,#ffffea,
+|24: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-34 #000000,#ffffea, 35-99 d,#ffffea,
+|25: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-17 #000000,#ffffea, 18-99 d,#ffffea,
+|26: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-16 #000000,#ffffea, 17-99 d,#ffffea,
+|27: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea,b 7-16 #000000,#ffffea, 17-99 d,#ffffea,
+|28: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-16 #000000,#ffffea, 17-99 d,#ffffea,
+|29: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-22 #000000,#ffffea, 23-99 d,#ffffea,
+|30: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-24 #000000,#ffffea, 25-99 d,#ffffea,
+== snap step-generated grid=100x31 cursor=7,27
+|18: 13 Theme clay
+|19: 14 Theme forge_black
+|20: 15 Theme forge_soft
+|21: 16 Theme orchard_black
+|22: 17
+|23: 18 # Legacy and imported themes
+|24: 19 Theme helix
+|25: 20 Theme dark
+|26: 21 Theme acme
+|27: 22 Theme acid
+|28: 23 Theme acme_helix
+|29: 24 Theme adwaita_dark
+|30: 25 Theme adwaita_light
+== style step-generated grid=100x31
+|0: 0-70 #e0e0e0,#1e262e, 71-99 d,#1e262e,
+|1: 0-24 #e0e0e0,#1e262e, 25-99 d,#1e262e,
+|2: 0-1 #ffffff,#303840, 2-58 #e0e0e0,#1e262e, 59-99 d,#1e262e,
|3: 0-0 d,#303840, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26,
|4: 0-0 d,#303840, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26,
|5: 0-0 d,#303840, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26,
-|6: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26,
+|6: 0-0 d,#303840, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26,
|7: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26,
|8: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26,
|9: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26,
|10: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26,
-|11: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-13 #e0e0e0,#161e26, 14-99 d,#161e26,
+|11: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26,
|12: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-13 #e0e0e0,#161e26, 14-99 d,#161e26,
|13: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-13 #e0e0e0,#161e26, 14-99 d,#161e26,
|14: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-13 #e0e0e0,#161e26, 14-99 d,#161e26,
|15: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-13 #e0e0e0,#161e26, 14-99 d,#161e26,
-|16: 0-1 #000000,#ffa060, 2-79 #e0e0e0,#1e262e, 80-99 d,#1e262e,
-|17: 0-0 d,#303840, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-17 #e0e0e0,#161e26, 18-99 d,#161e26,
-|18: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-16 #e0e0e0,#161e26, 17-99 d,#161e26,
-|19: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-16 #e0e0e0,#161e26, 17-99 d,#161e26,
-|20: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #e0e0e0,#1e262e, 7-16 #e0e0e0,#161e26, 17-99 d,#161e26,
-|21: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-22 #e0e0e0,#161e26, 23-99 d,#161e26,
-|22: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-24 #e0e0e0,#161e26, 25-99 d,#161e26,
-|23: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-25 #e0e0e0,#161e26, 26-99 d,#161e26,
-|24: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-22 #e0e0e0,#161e26, 23-99 d,#161e26,
-|25: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-23 #e0e0e0,#161e26, 24-99 d,#161e26,
-|26: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-21 #e0e0e0,#161e26, 22-99 d,#161e26,
-|27: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-21 #e0e0e0,#161e26, 22-99 d,#161e26,
-|28: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-14 #e0e0e0,#161e26, 15-99 d,#161e26,
-|29: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-17 #e0e0e0,#161e26, 18-99 d,#161e26,
-== snap step-back grid=100x30 cursor=7,19
-== style step-back grid=100x30
-|0: 0-74 #000000,#eaffff, 75-99 d,#eaffff,
-|1: 0-1 #ffffff,#383c54, 2-79 #000000,#eaffff, 80-99 d,#eaffff,
-|2: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
+|16: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-13 #e0e0e0,#161e26, 14-99 d,#161e26,
+|17: 0-1 #000000,#ffa060, 2-60 #e0e0e0,#1e262e, 61-99 d,#1e262e,
+|18: 0-0 d,#303840, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-16 #e0e0e0,#161e26, 17-99 d,#161e26,
+|19: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-23 #e0e0e0,#161e26, 24-99 d,#161e26,
+|20: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-22 #e0e0e0,#161e26, 23-99 d,#161e26,
+|21: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-25 #e0e0e0,#161e26, 26-99 d,#161e26,
+|22: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-99 d,#161e26,
+|23: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-34 #e0e0e0,#161e26, 35-99 d,#161e26,
+|24: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-17 #e0e0e0,#161e26, 18-99 d,#161e26,
+|25: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-16 #e0e0e0,#161e26, 17-99 d,#161e26,
+|26: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-16 #e0e0e0,#161e26, 17-99 d,#161e26,
+|27: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26,b 7-16 #e0e0e0,#161e26, 17-99 d,#161e26,
+|28: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-22 #e0e0e0,#161e26, 23-99 d,#161e26,
+|29: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-24 #e0e0e0,#161e26, 25-99 d,#161e26,
+|30: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-25 #e0e0e0,#161e26, 26-99 d,#161e26,
+== snap step-back grid=100x31 cursor=7,26
+== style step-back grid=100x31
+|0: 0-70 #000000,#eaffff, 71-99 d,#eaffff,
+|1: 0-24 #000000,#eaffff, 25-99 d,#eaffff,
+|2: 0-1 #ffffff,#383c54, 2-58 #000000,#eaffff, 59-99 d,#eaffff,
|3: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
|4: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
|5: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
-|6: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
+|6: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
|7: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
|8: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
|9: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
|10: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
-|11: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
+|11: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
|12: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
|13: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
|14: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
|15: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
-|16: 0-1 #ffffff,#6e4fd0, 2-79 #000000,#eaffff, 80-99 d,#eaffff,
-|17: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-17 #000000,#ffffea, 18-99 d,#ffffea,
-|18: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-16 #000000,#ffffea, 17-99 d,#ffffea,
-|19: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #000000,#eaffff, 7-16 #000000,#ffffea, 17-99 d,#ffffea,
-|20: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-16 #000000,#ffffea, 17-99 d,#ffffea,
-|21: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-22 #000000,#ffffea, 23-99 d,#ffffea,
-|22: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-24 #000000,#ffffea, 25-99 d,#ffffea,
-|23: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-25 #000000,#ffffea, 26-99 d,#ffffea,
-|24: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-22 #000000,#ffffea, 23-99 d,#ffffea,
-|25: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-23 #000000,#ffffea, 24-99 d,#ffffea,
-|26: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-21 #000000,#ffffea, 22-99 d,#ffffea,
-|27: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-21 #000000,#ffffea, 22-99 d,#ffffea,
-|28: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-14 #000000,#ffffea, 15-99 d,#ffffea,
-|29: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-17 #000000,#ffffea, 18-99 d,#ffffea,
-== snap tail grid=100x30 cursor=7,28
-|17: 217 Theme wolf_alabaster_dark_bg
-|18: 218 Theme wolf_alabaster_dark_mono
-|19: 219 Theme wolf_alabaster_light
-|20: 220 Theme wolf_alabaster_light_bg
-|21: 221 Theme wolf_alabaster_light_mono
-|22: 222 Theme yellowed
-|23: 223 Theme yo
-|24: 224 Theme yo_berry
-|25: 225 Theme yo_light
-|26: 226 Theme zed_onedark
-|27: 227 Theme zed_onelight
-|28: 228 Theme zenburn
-|29: 229
-== snap picked grid=100x30 cursor=7,2
-|16: 15 line 15
-|17: 16 line 16
-|18: 17 line 17
-|19: 18 line 18
-|20: 19 line 19
-|21: 20 line 20
-|22: 21 line 21
-|23: 22 line 22
-|24: 23 line 23
-|25: 24 line 24
-|26: 25 line 25
-|27: 26 line 26
-|28: 27 line 27
-|29: 28 line 28
-== style picked grid=100x30
-|1: 0-1 #ffffff,#6e4fd0, 2-79 #000000,#eaffff, 80-99 d,#eaffff,
-|2: 0-1 d,#ffffea, 2-6 #000000,#eaffff, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
-|6: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
+|16: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
+|17: 0-1 #ffffff,#6e4fd0, 2-60 #000000,#eaffff, 61-99 d,#eaffff,
+|18: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-16 #000000,#ffffea, 17-99 d,#ffffea,
+|19: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-23 #000000,#ffffea, 24-99 d,#ffffea,
+|20: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-22 #000000,#ffffea, 23-99 d,#ffffea,
+|21: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-25 #000000,#ffffea, 26-99 d,#ffffea,
+|22: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-99 d,#ffffea,
+|23: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-34 #000000,#ffffea, 35-99 d,#ffffea,
+|24: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-17 #000000,#ffffea, 18-99 d,#ffffea,
+|25: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-16 #000000,#ffffea, 17-99 d,#ffffea,
+|26: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea,b 7-16 #000000,#ffffea, 17-99 d,#ffffea,
+|27: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-16 #000000,#ffffea, 17-99 d,#ffffea,
+|28: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-22 #000000,#ffffea, 23-99 d,#ffffea,
+|29: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-24 #000000,#ffffea, 25-99 d,#ffffea,
+|30: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-25 #000000,#ffffea, 26-99 d,#ffffea,
+== snap tail grid=100x31 cursor=7,29
+|18: 235 Theme wolf_alabaster_dark_bg
+|19: 236 Theme wolf_alabaster_dark_mono
+|20: 237 Theme wolf_alabaster_light
+|21: 238 Theme wolf_alabaster_light_bg
+|22: 239 Theme wolf_alabaster_light_mono
+|23: 240 Theme yellowed
+|24: 241 Theme yo
+|25: 242 Theme yo_berry
+|26: 243 Theme yo_light
+|27: 244 Theme zed_onedark
+|28: 245 Theme zed_onelight
+|29: 246 Theme zenburn
+|30: 247
+== snap picked grid=100x31 cursor=7,3
+|17: 15 line 15
+|18: 16 line 16
+|19: 17 line 17
+|20: 18 line 18
+|21: 19 line 19
+|22: 20 line 20
+|23: 21 line 21
+|24: 22 line 22
+|25: 23 line 23
+|26: 24 line 24
+|27: 25 line 25
+|28: 26 line 26
+|29: 27 line 27
+|30: 28 line 28
+== style picked grid=100x31
+|2: 0-1 #ffffff,#6e4fd0, 2-58 #000000,#eaffff, 59-99 d,#eaffff,
+|3: 0-1 d,#ffffea, 2-6 #999980,#ffffea,b 7-12 #000000,#ffffea, 13-99 d,#ffffea,
|7: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
|8: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
|9: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
|10: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
-|11: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
+|11: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea,
|12: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
|13: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
|14: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
@@ -251,7 +782,7 @@
|18: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
|19: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
|20: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
-|21: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
+|21: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
|22: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
|23: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
|24: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
@@ -260,3 +791,4 @@
|27: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
|28: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
|29: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
+|30: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea,
diff --git a/test/snapshots/themesel.snap b/test/snapshots/themesel.snap
index cff136f1..04a95d23 100644
--- a/test/snapshots/themesel.snap
+++ b/test/snapshots/themesel.snap
@@ -10,13 +10,13 @@
# running it and stopping. There is still no preview state, nothing to confirm
# and nothing to cancel: the row you ran is the theme you have.
#
-# Both halves of the ring are in the buffer: the three pardes ships with come
-# first (helix, dark, acme), then everything tools/gen_themes.zig exported from
+# Both halves of the ring are in the buffer: the fifteen native themes come
+# first, then the retained helix, dark and acme, then everything exported from
# the vendored helix .toml and zed .json files, sorted. The colors below are
# read with snapstyle, so this proves the generated themes are real data and
# not just names in a list.
lines t.txt 40
-start 30 100 t.txt
+start 31 100 t.txt
wait 8000 t.txt
stable 700 20000
snap boot
@@ -24,18 +24,85 @@ snap boot
# fresh output buffer is where the walk's ring starts, so the first n goes
# into the list and every one after it carries on down it.
key space t t
-wait 10000 Theme helix
+wait 10000 Theme orchard
stable 700 15000
snap list
-# n selects row 1 whole and Tab runs it: `Theme helix`, which is already the
+# n selects row 1 whole and Tab runs it: `Theme orchard`, which is already the
# boot theme, so only the selection moves. That is the honest first step — an
# idempotent command has to be safe to run.
key n
key tab
stable 700 15000
+snap step-orchard
+snapstyle step-orchard
+# ...and now the theme really does change under the cursor, one row at a time
+key n
+key tab
+stable 700 15000
+snap step-dusk
+snapstyle step-dusk
+# Selection alone can skip rows without previewing or applying their themes.
+# Four steps reach atelier, the Acme homage; Tab then applies it.
+key n
+key n
+key n
+key n
+key tab
+stable 700 15000
+snap step-atelier
+snapstyle step-atelier
+key n
+key tab
+stable 700 15000
+snap step-forge
+snapstyle step-forge
+key n
+key tab
+stable 700 15000
+snap step-lagoon
+snapstyle step-lagoon
+key n
+key tab
+stable 700 15000
+snap step-solarium
+snapstyle step-solarium
+key n
+key tab
+stable 700 15000
+snap step-spectrum
+snapstyle step-spectrum
+key n
+key tab
+stable 700 15000
+snap step-harvest
+snapstyle step-harvest
+key n
+key tab
+stable 700 15000
+snap step-clay
+snapstyle step-clay
+# The three native contrast variants precede the legacy section. Its heading
+# and blank separator are not stops in the n/N command walk.
+key n
+key tab
+stable 700 15000
+snap step-forge-black
+snapstyle step-forge-black
+key n
+key tab
+stable 700 15000
+snap step-forge-soft
+snapstyle step-forge-soft
+key n
+key tab
+stable 700 15000
+snap step-orchard-black
+snapstyle step-orchard-black
+key n
+key tab
+stable 700 15000
snap step-helix
snapstyle step-helix
-# ...and now the theme really does change under the cursor, one row at a time
key n
key tab
stable 700 15000
@@ -46,8 +113,8 @@ key tab
stable 700 15000
snap step-acme
snapstyle step-acme
-# past the curated three and into the generated half, which is 225 themes
-# sorted by name — so the fourth row is whatever sorts first, not whatever was
+# past the curated eighteen and into the generated half, which is sorted by name
+# — so the next command is whatever sorts first, not whatever was
# vendored first. That is the point of sorting: the ring is the same everywhere
# whatever order the directory read handed the files over in.
key n
@@ -67,7 +134,7 @@ snapstyle step-back
# the walk lands IN the pane it steps, so the cursor has been in the list
# since the first n. Body-normal Esc is Last, so it deliberately leaves this
# document-like output buffer open.
-# ...and the WHOLE ring is in there, all 228 rows: `ge` to the last line, which
+# ...and the WHOLE ring is in there: `ge` to the last line, which
# only reaches `Theme zenburn` if nothing truncated the buffer on the way in. It
# is an ordinary file pane, so it scrolls like one; a motion runs nothing and
# neither does a step, so no theme changes here and the one the last Tab chose
diff --git a/test/snapshots/tinywin.golden b/test/snapshots/tinywin.golden
index 0be29acb..dcbc63d8 100644
--- a/test/snapshots/tinywin.golden
+++ b/test/snapshots/tinywin.golden
@@ -1,36 +1,40 @@
-== snap stacked grid=100x30 cursor=4,14
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|$ /tmp/pardes-snap/tinywin/cwd Save New Newtty Del Filter
+== snap stacked grid=100x31 cursor=4,15
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+|$ /tmp/pardes-snap/tinywin/cwd Save Tty Del Togglettymode Filter Collapse
| $
-| /tmp/pardes-snap/tinywin/cwd Save New Newtty Del Filter
+| /tmp/pardes-snap/tinywin/cwd Save Tty Del Togglettymode Filter Collapse
| ls
|
-| /tmp/pardes-snap/tinywin/cwd Save New Newtty Del Filter
+| /tmp/pardes-snap/tinywin/cwd Save Tty Del Togglettymode Filter Collapse
| ls
|
-| /tmp/pardes-snap/tinywin/cwd Save New Newtty Del Filter
+| /tmp/pardes-snap/tinywin/cwd Save Tty Del Togglettymode Filter Collapse
| ls
|
-| /tmp/pardes-snap/tinywin/cwd Save New Newtty Del Filter
+| /tmp/pardes-snap/tinywin/cwd Save Tty Del Togglettymode Filter Collapse
| ls
-== snap shrunk grid=60x3 cursor=59,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextC
-|$ /tmp/pardes-snap/tinywin/cwd Save New Newtty Del Filter
-| /tmp/pardes-snap/tinywin/cwd Save New Newtty Del Filter
-== snap columns grid=100x30 cursor=95,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|$ /tmp/pardes-snap/tinywin/cwd Save New Newtty Del /tmp/pardes-snap/tinywi /tmp/pardes /tmp/parde
+== snap shrunk grid=60x4 cursor=59,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor
+|New Tty Find Grep Joincol
+|$ /tmp/pardes-snap/tinywin/cwd Save Tty Del Togglettymode Fi
+| /tmp/pardes-snap/tinywin/cwd Save Tty Del Togglettymode Fi
+== snap columns grid=100x31 cursor=95,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep JoincolNew Tty Find New Tty Find
+|$ /tmp/pardes-snap/tinywin/cwd Save Tty Del Toggle /tmp/pardes-snap/tinywi /tmp/pardes /tmp/parde
| $ 1 1 1
-| /tmp/pardes-snap/tinywin/cwd Save New Newtty Del
+| /tmp/pardes-snap/tinywin/cwd Save Tty Del Toggle
| ls
|
-| /tmp/pardes-snap/tinywin/cwd Save New Newtty Del
+| /tmp/pardes-snap/tinywin/cwd Save Tty Del Toggle
| ls
|
-| /tmp/pardes-snap/tinywin/cwd Save New Newtty Del
+| /tmp/pardes-snap/tinywin/cwd Save Tty Del Toggle
| ls
|
-| /tmp/pardes-snap/tinywin/cwd Save New Newtty Del
+| /tmp/pardes-snap/tinywin/cwd Save Tty Del Toggle
| ls
-== snap narrow grid=4x30 cursor=3,29
-|New
+== snap narrow grid=4x31 cursor=3,30
+|Newc
+|NeNN
diff --git a/test/snapshots/tinywin.snap b/test/snapshots/tinywin.snap
index 95050301..3d22d583 100644
--- a/test/snapshots/tinywin.snap
+++ b/test/snapshots/tinywin.snap
@@ -2,7 +2,7 @@
# every pane in a column at least one row, so `y` walked off the bottom and
# renderPane got a rect outside the surface (assert). Panes that no longer fit
# now get h = 0 and simply do not render until the window grows back.
-start 30 100
+start 31 100
wait 8000 $
key a-n
stable 400 8000
@@ -13,11 +13,11 @@ stable 400 8000
key a-n
stable 700 15000
snap stacked
-resize 3 60
+resize 4 60
stable 700 10000
snap shrunk
# ...and the same sideways: more columns than the window is wide
-resize 30 100
+resize 31 100
stable 700 10000
key space c n
stable 600 8000
@@ -26,6 +26,6 @@ stable 600 8000
key space c n
stable 700 15000
snap columns
-resize 30 4
+resize 31 4
stable 700 10000
snap narrow
diff --git a/test/snapshots/topbarexec.golden b/test/snapshots/topbarexec.golden
index 4ab55473..bb0be27b 100644
--- a/test/snapshots/topbarexec.golden
+++ b/test/snapshots/topbarexec.golden
@@ -1,6 +1,7 @@
-== snap selected grid=90x20 cursor=14,3
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/topbarexec/cwd Save New Ne /tmp/pardes-snap/topbarexec/cwd Save New Ne
+== snap selected grid=90x21 cursor=14,4
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/topbarexec/cwd Save Tty De /tmp/pardes-snap/topbarexec/cwd Save Tty De
| ls ls
| zmarkfile.txt zmarkfile.txt
|
@@ -10,28 +11,29 @@
|
|
|
-| /tmp/pardes-snap/topbarexec/cwd Save New Ne
+| /tmp/pardes-snap/topbarexec/cwd Save Tty De
| ls
| zmarkfile.txt
-== snap noarg-runs grid=90x20 cursor=14,3
-|1: /tmp/pardes-snap/topbarexec/cwd Save New Ne /tmp/╭────────────────────────────────────╮
-|2: ls ls │pardes resizes=1 │
-|3: zmarkfile.txt zmark│theme helix │
-|4: │font default │
+== snap noarg-runs grid=90x21 cursor=14,4
+|1: New Tty Find Grep Joincol New Tty╭────────────────────────────────────╮
+|2: /tmp/pardes-snap/topbarexec/cwd Save Tty De /tmp/│pardes resizes=1 │
+|3: ls ls │theme orchard │
+|4: zmarkfile.txt zmark│font default │
|5: │terms 3 cols 2 │
|6: │active #0 43x9 │
|7: │scroll 0/9 │
|8: │pinch 1.0000 │
|9: │tscroll 0.0000 │
|10: ╰────────────────────────────────────╯
-== snap arg-still-spliced grid=90x20 cursor=14,3
-|1: /tmp/pardes-snap/topbarexec/cwd Save New Ne /tmp/pardes-snap/topbarexec/cwd Save New Ne
-|2: ls ls
-|3: zmarkfile.txt zmarkfile.txt
-|4:
+== snap arg-still-spliced grid=90x21 cursor=14,4
+|1: New Tty Find Grep Joincol New Tty Find Grep Joincol
+|2: /tmp/pardes-snap/topbarexec/cwd Save Tty De /tmp/pardes-snap/topbarexec/cwd Save Tty De
+|3: ls ls
+|4: zmarkfile.txt zmarkfile.txt
|5:
|6:
|7:
|8:
-|9: /tmp/pardes-snap/topbarexec/cwd/+Search Sav
-|10: 1 zmarkfile.txt
+|9:
+|10: /tmp/pardes-snap/topbarexec/cwd/+Search Sav
+|11: 1 zmarkfile.txt
diff --git a/test/snapshots/topbarexec.snap b/test/snapshots/topbarexec.snap
index f1661da4..f5f09a08 100644
--- a/test/snapshots/topbarexec.snap
+++ b/test/snapshots/topbarexec.snap
@@ -14,14 +14,14 @@
# So both halves are pinned here, against the same live selection: the no-arg
# builtin runs, and the arg-taking one still gets the word.
file zmarkfile.txt hay ZQNEEDLE stack
-start 20 90 -n 3
+start 21 90 -n 3
wait 8000 zmarkfile.txt
stable 700 20000
# sweep `zmarkfile.txt` out of the shell's own greeting: an ordinary left drag,
# and the kind of stale highlight that is simply lying around in real use
-press left 3 4
-drag left 15 4
-release left 15 4
+press left 3 5
+drag left 15 5
+release left 15 5
stable 700 15000
snap selected
# Debug takes NO argument. Middle-clicked with that sweep live it must open the
diff --git a/test/snapshots/tty.golden b/test/snapshots/tty.golden
index f4781349..fa8144ef 100644
--- a/test/snapshots/tty.golden
+++ b/test/snapshots/tty.golden
@@ -1,6 +1,7 @@
-== snap tty-on grid=100x30 cursor=4,4
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|$ /tmp/pardes-snap/tty/cwd Save New Newtty Del Fil /tmp/pardes-snap/tty/cwd Save New Newtty Del Fil
+== snap tty-on grid=100x31 cursor=4,5
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+|$ /tmp/pardes-snap/tty/cwd Save Tty Del Togglettym /tmp/pardes-snap/tty/cwd Save Tty Del Togglettym
| $ ls ls
| m.txt m.txt
| $
@@ -15,26 +16,26 @@
|
|
|
-| /tmp/pardes-snap/tty/cwd Save New Newtty Del Fil
+| /tmp/pardes-snap/tty/cwd Save Tty Del Togglettym
| ls
| m.txt
-== snap tty-echo grid=100x30 cursor=4,6
-|4: $ echo SNAP''OK
-|5: SNAPOK
-|6: $
-== snap tty-off grid=100x30 cursor=4,6
-|1: /tmp/pardes-snap/tty/cwd Save New Newtty Del Fil /tmp/pardes-snap/tty/cwd Save New Newtty Del Fil
-|2: ls ls
-|4: echo SNAP''OK
-|6:
-== snap shift-esc-on grid=100x30 cursor=4,6
-|1: $ /tmp/pardes-snap/tty/cwd Save New Newtty Del Fil /tmp/pardes-snap/tty/cwd Save New Newtty Del Fil
-|2: $ ls ls
-|4: $ echo SNAP''OK
-|6: $
-== snap shift-esc-nodoc grid=100x30 cursor=4,6
-== snap ctrl-b-off grid=100x30 cursor=4,6
-|1: /tmp/pardes-snap/tty/cwd Save New Newtty Del Fil /tmp/pardes-snap/tty/cwd Save New Newtty Del Fil
-|2: ls ls
-|4: echo SNAP''OK
-|6:
+== snap tty-echo grid=100x31 cursor=4,7
+|5: $ echo SNAP''OK
+|6: SNAPOK
+|7: $
+== snap tty-off grid=100x31 cursor=4,7
+|2: /tmp/pardes-snap/tty/cwd Save Tty Del Togglettym /tmp/pardes-snap/tty/cwd Save Tty Del Togglettym
+|3: ls ls
+|5: echo SNAP''OK
+|7:
+== snap shift-esc-on grid=100x31 cursor=4,7
+|2: $ /tmp/pardes-snap/tty/cwd Save Tty Del Togglettym /tmp/pardes-snap/tty/cwd Save Tty Del Togglettym
+|3: $ ls ls
+|5: $ echo SNAP''OK
+|7: $
+== snap shift-esc-nodoc grid=100x31 cursor=4,7
+== snap ctrl-b-off grid=100x31 cursor=4,7
+|2: /tmp/pardes-snap/tty/cwd Save Tty Del Togglettym /tmp/pardes-snap/tty/cwd Save Tty Del Togglettym
+|3: ls ls
+|5: echo SNAP''OK
+|7:
diff --git a/test/snapshots/tty.snap b/test/snapshots/tty.snap
index 58f4c1ee..6ce0d5ba 100644
--- a/test/snapshots/tty.snap
+++ b/test/snapshots/tty.snap
@@ -7,7 +7,7 @@
# in tty so coming back lands in the program you left. The hop itself is
# covered by a unit test in pardes.zig.
file m.txt marker
-start 30 100 -n 3
+start 31 100 -n 3
wait 8000 m.txt
stable 700 20000
key c-b
diff --git a/test/snapshots/ttyclick.golden b/test/snapshots/ttyclick.golden
index 2224be82..c32fa2e7 100644
--- a/test/snapshots/ttyclick.golden
+++ b/test/snapshots/ttyclick.golden
@@ -1,6 +1,7 @@
-== snap tty-bodyclick grid=100x30 cursor=4,4
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|$ /tmp/pardes-snap/ttyclick/cwd Save New Newtty De /tmp/pardes-snap/ttyclick/cwd Save New Newtty De
+== snap tty-bodyclick grid=100x31 cursor=4,5
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+|$ /tmp/pardes-snap/ttyclick/cwd Save Tty Del Toggl /tmp/pardes-snap/ttyclick/cwd Save Tty Del Toggl
| $ ls ls
| probe.txt probe.txt
| $
@@ -15,16 +16,16 @@
|
|
|
-| /tmp/pardes-snap/ttyclick/cwd Save New Newtty De
+| /tmp/pardes-snap/ttyclick/cwd Save Tty Del Toggl
| ls
| probe.txt
-== snap tty-tagedit grid=100x30 cursor=37,1
-|2: ls ls
-|4:
-== snap tty-tagexit grid=100x30 cursor=4,4
-|2: $ ls ls
-|4: $
-== snap ins-bodyclick grid=100x30 cursor=11,3
-|1: ^ /tmp/pardes-snap/ttyclick/cwd Save New Newtty De /tmp/pardes-snap/ttyclick/cwd Save New Newtty De
-|2: ls ls
-|4:
+== snap tty-tagedit grid=100x31 cursor=37,2
+|3: ls ls
+|5:
+== snap tty-tagexit grid=100x31 cursor=4,5
+|3: $ ls ls
+|5: $
+== snap ins-bodyclick grid=100x31 cursor=11,4
+|2: ^ /tmp/pardes-snap/ttyclick/cwd Save Tty Del Toggl /tmp/pardes-snap/ttyclick/cwd Save Tty Del Toggl
+|3: ls ls
+|5:
diff --git a/test/snapshots/ttyclick.snap b/test/snapshots/ttyclick.snap
index ca32568b..89ed5300 100644
--- a/test/snapshots/ttyclick.snap
+++ b/test/snapshots/ttyclick.snap
@@ -5,21 +5,21 @@
# The mode is the character in each pane's layout box: `•` normal, `^` insert,
# `$` tty.
file probe.txt marker
-start 30 100 -n 3
+start 31 100 -n 3
wait 8000 probe.txt
stable 700 20000
key c-b
stable 600 8000
# body click in raw tty: focus/selection only, the box stays `$`
-press left 10 4
-release left 10 4
+press left 10 5
+release left 10 5
stable 400 5000
snap tty-bodyclick
# tag edit from tty: the box still reads `$` while the tag is being edited (the
# body mode is PARKED, which is the invariant), and Esc hands it back — a bug
# that lost it would show `•` in one snap or the other
-press left @New 2
-release left @New 2
+press left @Tty 3
+release left @Tty 3
stable 400 5000
snap tty-tagedit
key esc
@@ -30,7 +30,7 @@ key c-b
stable 600 8000
key i
stable 400 5000
-press left 12 4
-release left 12 4
+press left 12 5
+release left 12 5
stable 400 5000
snap ins-bodyclick
diff --git a/test/snapshots/ttyedit.golden b/test/snapshots/ttyedit.golden
index 0fe295ff..ad0cddc0 100644
--- a/test/snapshots/ttyedit.golden
+++ b/test/snapshots/ttyedit.golden
@@ -1,6 +1,7 @@
-== snap before grid=100x30 cursor=7,6
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/ttyedit/cwd Save New Newtty Del /tmp/pardes-snap/ttyedit/cwd Save New Newtty Del
+== snap before grid=100x31 cursor=7,7
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/ttyedit/cwd Save Tty Del Toggle /tmp/pardes-snap/ttyedit/cwd Save Tty Del Toggle
| ls ls
| words.txt words.txt
| printf 'one two three\nfour five six\nseven ei
@@ -15,27 +16,27 @@
|
|
|
-| /tmp/pardes-snap/ttyedit/cwd Save New Newtty Del
+| /tmp/pardes-snap/ttyedit/cwd Save Tty Del Toggle
| ls
| words.txt
-== snap split grid=100x30 cursor=2,7
-|1: ^ /tmp/pardes-snap/ttyedit/cwd Save New Newtty Del /tmp/pardes-snap/ttyedit/cwd Save New Newtty Del
-|6: one t
-|7: wo three
-|8: four five six
-|9: seven eight nine
-== snap opened grid=100x30 cursor=6,8
-|1: /tmp/pardes-snap/ttyedit/cwd Save New Newtty Del /tmp/pardes-snap/ttyedit/cwd Save New Newtty Del
-|8: OPEN
+== snap split grid=100x31 cursor=2,8
+|2: ^ /tmp/pardes-snap/ttyedit/cwd Save Tty Del Toggle /tmp/pardes-snap/ttyedit/cwd Save Tty Del Toggle
+|7: one t
+|8: wo three
+|9: four five six
+|10: seven eight nine
+== snap opened grid=100x31 cursor=6,9
+|2: /tmp/pardes-snap/ttyedit/cwd Save Tty Del Toggle /tmp/pardes-snap/ttyedit/cwd Save Tty Del Toggle
+|9: OPEN
+|10: four five six
+|11: seven eight nine
+== snap joined grid=100x31 cursor=10,8
+|8: wo threeOPEN
|9: four five six
|10: seven eight nine
-== snap joined grid=100x30 cursor=10,7
-|7: wo threeOPEN
+|11:
+== snap undone grid=100x31 cursor=7,7
+|7: one two three
|8: four five six
|9: seven eight nine
|10:
-== snap undone grid=100x30 cursor=7,6
-|6: one two three
-|7: four five six
-|8: seven eight nine
-|9:
diff --git a/test/snapshots/ttyedit.snap b/test/snapshots/ttyedit.snap
index 18872ce4..c453d230 100644
--- a/test/snapshots/ttyedit.snap
+++ b/test/snapshots/ttyedit.snap
@@ -5,7 +5,7 @@
# expressible. test/hxcases/parity.jsonl pins the keystroke-level equivalence
# with a file pane case for case; this is the end-to-end pty proof.
file words.txt alpha beta
-start 30 100 -n 3
+start 31 100 -n 3
wait 8000 words.txt
stable 700 20000
key c-b
@@ -17,8 +17,8 @@ stable 700 10000
key c-b
stable 600 8000
# click into the middle of the first output row
-press left 8 7
-release left 8 7
+press left 8 8
+release left 8 8
stable 400 5000
snap before
# Enter splits the row there: "one t" stays, "wo three" becomes a real line
diff --git a/test/snapshots/ttyfollow.golden b/test/snapshots/ttyfollow.golden
index 8849c3d2..1b6a9fd0 100644
--- a/test/snapshots/ttyfollow.golden
+++ b/test/snapshots/ttyfollow.golden
@@ -1,6 +1,7 @@
-== snap held-pre grid=100x30 cursor=4,15
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/ttyfollow/cwd Save New Newtty D /tmp/pardes-snap/ttyfollow/cwd Save New Newtty D
+== snap held-pre grid=100x31 cursor=4,16
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/ttyfollow/cwd Save Tty Del Togg /tmp/pardes-snap/ttyfollow/cwd Save Tty Del Togg
| 185 ls
| 186 s.txt
| 187
@@ -15,29 +16,29 @@
| 196
| 197
| 198
-| /tmp/pardes-snap/ttyfollow/cwd Save New Newtty D
+| /tmp/pardes-snap/ttyfollow/cwd Save Tty Del Togg
| ls
| s.txt
-== snap held-post grid=100x30 cursor=54,7
-|1: /tmp/pardes-snap/ttyfollow/cwd Save New Newtty D$ /tmp/pardes-snap/ttyfollow/cwd Save New Newtty D
-|2: 185 $ ls
-|4: 187 $ touch go; until test -f done1; do sleep 0.05;
-|5: 188 done; echo SYN''CED
-|6: 189 SYNCED
-|7: 190 $
-== snap tty-follows grid=100x30 cursor=4,15
-|1: $ /tmp/pardes-snap/ttyfollow/cwd Save New Newtty D$ /tmp/pardes-snap/ttyfollow/cwd Save New Newtty D
-|2: 288 $ ls
-|3: 289 s.txt
-|4: 290 $ touch go; until test -f done1; do sleep 0.05;
-|5: 291 done; echo SYN''CED
-|6: 292 SYNCED
-|7: 293 $
-|8: 294
-|9: 295
-|10: 296
-|11: 297
-|12: 298
-|13: 299
-|14: 300
-|15: $
+== snap held-post grid=100x31 cursor=54,8
+|2: /tmp/pardes-snap/ttyfollow/cwd Save Tty Del Togg$ /tmp/pardes-snap/ttyfollow/cwd Save Tty Del Togg
+|3: 185 $ ls
+|5: 187 $ touch go; until test -f done1; do sleep 0.05;
+|6: 188 done; echo SYN''CED
+|7: 189 SYNCED
+|8: 190 $
+== snap tty-follows grid=100x31 cursor=4,16
+|2: $ /tmp/pardes-snap/ttyfollow/cwd Save Tty Del Togg$ /tmp/pardes-snap/ttyfollow/cwd Save Tty Del Togg
+|3: 288 $ ls
+|4: 289 s.txt
+|5: 290 $ touch go; until test -f done1; do sleep 0.05;
+|6: 291 done; echo SYN''CED
+|7: 292 SYNCED
+|8: 293 $
+|9: 294
+|10: 295
+|11: 296
+|12: 297
+|13: 298
+|14: 299
+|15: 300
+|16: $
diff --git a/test/snapshots/ttyfollow.snap b/test/snapshots/ttyfollow.snap
index e7303b4b..94af40aa 100644
--- a/test/snapshots/ttyfollow.snap
+++ b/test/snapshots/ttyfollow.snap
@@ -3,7 +3,7 @@
# back in tty mode output follows to the bottom again. Pane A parks a
# background job blocked on file `go`, pane B triggers it and syncs on `done1`.
file s.txt x
-start 30 100 -n 3
+start 31 100 -n 3
wait 8000 s.txt
stable 700 20000
key c-b
@@ -24,8 +24,8 @@ stable 500 8000
snap held-pre
# focus pane B (right column), trigger A's job, sync on completion: A is now a
# NON-active normal-mode pane receiving output — its view must not move
-press left 60 5
-release left 60 5
+press left 60 6
+release left 60 6
stable 400 5000
key c-b
stable 600 8000
@@ -35,8 +35,8 @@ wait 8000 SYNCED
stable 700 15000
snap held-post
# back in A, re-enter tty: the echoed keystrokes pull the view to the bottom
-press left 10 8
-release left 10 8
+press left 10 9
+release left 10 9
stable 400 5000
key c-b
stable 600 8000
diff --git a/test/snapshots/ttyhelp.golden b/test/snapshots/ttyhelp.golden
index 340346af..1c16852f 100644
--- a/test/snapshots/ttyhelp.golden
+++ b/test/snapshots/ttyhelp.golden
@@ -1,33 +1,34 @@
-== snap boot grid=100x30 cursor=4,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|$ /tmp/pardes-snap/ttyhelp/cwd Save New Newtty Del Filter
+== snap boot grid=100x31 cursor=4,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+|$ /tmp/pardes-snap/ttyhelp/cwd Save Tty Del Togglettymode Filter Collapse
| $
-== snap helped grid=100x30 cursor=7,4
-|3: /tmp/pardes-snap/ttyhelp/cwd/+Help Save New Newtty Del
-|4: 1 pardes builtins, and how to run each:
-|5: 2 SPC and its keys, a chord, a button, the
-|6: 3 topbar - or the name, executed anywhere.
-|7: 4
-|8: 5 SPC ? Help topbar
-|9: 6 SPC P ClipPasteBefore
-|10: 7 SPC R ClipReplace
-|11: 8 SPC Y ClipYankMain
-|12: 9 SPC a a PanelAscii
-|13: 10 SPC a c PanelCurtain
-|14: 11 SPC a d PanelDissolve
-|15: 12 SPC a e PanelEdges
-|16: 13 SPC a f PanelFall
-|17: 14 SPC a r PanelScramble
-|18: 15 SPC a s PanelSlide
-|19: 16 SPC a t PanelType
-|20: 17 SPC a v PanelVertical
-|21: 18 SPC a w PanelWave
-|22: 19 SPC a z PanelZoom
-|23: 20 SPC c d Delcol
-|24: 21 SPC c j Joincol topbar
-|25: 22 SPC c n Newcol topbar
-|26: 23 SPC d Del
-|27: 24 SPC f c Config
-|28: 25 SPC f f Find topbar
-|29: 26 SPC f g Grep topbar
-== snap leaderworks grid=100x30 cursor=7,4
+== snap helped grid=100x31 cursor=7,5
+|4: /tmp/pardes-snap/ttyhelp/cwd/+Help Save Tty Del Collapse
+|5: 1 pardes builtins, and how to run each:
+|6: 2 SPC and its keys, a chord, a button, the
+|7: 3 topbar - or the name, executed anywhere.
+|8: 4
+|9: 5 SPC ? Help topbar
+|10: 6 SPC P ClipPasteBefore
+|11: 7 SPC R ClipReplace
+|12: 8 SPC Y ClipYankMain
+|13: 9 SPC a a PanelAscii
+|14: 10 SPC a c PanelCurtain
+|15: 11 SPC a d PanelDissolve
+|16: 12 SPC a e PanelEdges
+|17: 13 SPC a f PanelFall
+|18: 14 SPC a r PanelScramble
+|19: 15 SPC a s PanelSlide
+|20: 16 SPC a t PanelType
+|21: 17 SPC a v PanelVertical
+|22: 18 SPC a w PanelWave
+|23: 19 SPC a z PanelZoom
+|24: 20 SPC c d Delcol
+|25: 21 SPC c j Joincol topbar
+|26: 22 SPC c n Newcol topbar
+|27: 23 SPC d Del
+|28: 24 SPC f c Config
+|29: 25 SPC f f Find topbar
+|30: 26 SPC f g Grep topbar
+== snap leaderworks grid=100x31 cursor=7,5
diff --git a/test/snapshots/ttyhelp.snap b/test/snapshots/ttyhelp.snap
index 42efd565..e5f77a68 100644
--- a/test/snapshots/ttyhelp.snap
+++ b/test/snapshots/ttyhelp.snap
@@ -1,8 +1,8 @@
# bare boot = tty mode: SPC belongs to the shell, so the topbar Help word is
# the only route to the command list. Row 0 is not a pane, so a middle-click
# there is dispatched before any pane's mode is consulted.
-start 30 100
-wait 8000 New Newcol
+start 31 100
+wait 8000 Newcol Joincol
stable 700 20000
snap boot
press middle @Help 1
diff --git a/test/snapshots/ttylook.golden b/test/snapshots/ttylook.golden
index 6a01c892..6b29e089 100644
--- a/test/snapshots/ttylook.golden
+++ b/test/snapshots/ttylook.golden
@@ -1,6 +1,7 @@
-== snap tok1 grid=120x30 cursor=2,3
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/ttylook/cwd Save New Newtty Del Filter /tmp/pardes-snap/ttylook/cwd Save New Newtty Del Filter
+== snap tok1 grid=120x31 cursor=2,4
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/ttylook/cwd Save Tty Del Togglettymode Fi /tmp/pardes-snap/ttylook/cwd Save Tty Del Togglettymode Fi
| ls ls
| big.txt plain.txt sub big.txt plain.txt sub
|
@@ -15,53 +16,57 @@
|
|
|
-| /tmp/pardes-snap/ttylook/cwd Save New Newtty Del Filter
+| /tmp/pardes-snap/ttylook/cwd Save Tty Del Togglettymode Fi
| ls
| big.txt plain.txt sub
-== style tok1 grid=120x30
-|0: 0-74 #949494,#121212, 75-119 d,#121212,
-|1: 0-1 #ffffff,#626262, 2-56 #949494,#121212, 57-59 d,#121212, 60-61 #ffffff,#262626, 62-116 #949494,#121212, 117-119 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-8 #080808,#80a0ff, 9-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|4: 0-0 d,#444444, 1-59 d,#080808, 60-60 d,#444444, 61-119 d,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|8: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|11: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|16: 0-1 #ffffff,#262626, 2-56 #949494,#121212, 57-59 d,#121212, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|19: 0-0 d,#444444, 1-59 d,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-|29: 0-0 d,#444444, 1-1 d,#080808, 2-59 #bdbdbd,#080808, 60-60 d,#444444, 61-61 d,#080808, 62-119 #bdbdbd,#080808,
-== snap tok2 grid=120x30 cursor=11,3
-== snap tokback grid=120x30 cursor=2,3
-== snap insert grid=120x30 cursor=4,3
-|3: nnbig.txt plain.txt sub big.txt plain.txt sub
-== snap tok3 grid=120x30 cursor=22,3
-|3: big.txt plain.txt sub big.txt plain.txt sub
-== snap diropen grid=120x30 cursor=4,7
-|1: /tmp/pardes-snap/ttylook/cwd Save New Newtty Del Filter /tmp/pardes-snap/ttylook/cwd Save New Newtty Del Filter
-|5: /tmp/pardes-snap/ttylook/cwd/sub Save New Newtty Del Filte
-|6: ls
-|16: /tmp/pardes-snap/ttylook/cwd Save New Newtty Del Filter
-== snap noop grid=120x30 cursor=2,3
-== snap fileopen grid=120x30 cursor=7,2
-|1: /tmp/pardes-snap/ttylook/cwd/big.txt Save New Newtty Del /tmp/pardes-snap/ttylook/cwd Save New Newtty Del Filter
-|2: 1 line 1 ls
-|3: /tmp/pardes-snap/ttylook/cwd Save New Newtty Del Filter big.txt plain.txt sub
+== style tok1 grid=120x31
+|0: 0-70 #b2c3b8,#1d2824, 71-119 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-59 d,#26362d, 60-84 #b2c3b8,#1d2824, 85-119 d,#1d2824,
+|2: 0-1 #000000,#adcc91, 2-59 #becfc4,#26362d, 60-61 #ffffff,#4c6356, 62-119 #b2c3b8,#1d2824,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-8 #f5f7ee,#405d4b, 9-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|5: 0-0 d,#637f6a, 1-59 d,#0d1410, 60-60 d,#637f6a, 61-119 d,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|17: 0-1 #ffffff,#4c6356, 2-59 #b2c3b8,#1d2824, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|20: 0-0 d,#637f6a, 1-59 d,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 d,#637f6a, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
+== snap tok2 grid=120x31 cursor=11,4
+== snap tokback grid=120x31 cursor=2,4
+== snap insert grid=120x31 cursor=4,4
+|4: nnbig.txt plain.txt sub big.txt plain.txt sub
+== snap tok3 grid=120x31 cursor=22,4
+|4: big.txt plain.txt sub big.txt plain.txt sub
+== snap diropen grid=120x31 cursor=4,8
+|6: /tmp/pardes-snap/ttylook/cwd/sub Save Tty Del Togglettymod
+|7: ls
+== snap noop grid=120x31 cursor=2,4
+== snap fileopen grid=120x31 cursor=7,10
+|9: /tmp/pardes-snap/ttylook/cwd/big.txt Save Tty Del Collapse
+|10: 1 line 1
+|11: 2 line 2
+|12: 3 line 3
+|13: 4 line 4
+|14: 5 line 5
+|15: 6 line 6
+|16: 7 line 7
diff --git a/test/snapshots/ttylook.snap b/test/snapshots/ttylook.snap
index 66b178d7..5b82bd89 100644
--- a/test/snapshots/ttylook.snap
+++ b/test/snapshots/ttylook.snap
@@ -9,7 +9,7 @@
lines big.txt 40
file plain.txt just text
dirmk sub
-start 30 120 -n 3
+start 31 120 -n 3
wait 8000 big.txt
stable 700 20000
# first n: cursor sits at the shell prompt below the output — wrap lands on
@@ -54,8 +54,8 @@ stable 400 5000
snap noop
# back in the first pane, Enter with the cursor ON a token looks it (no
# selection: the cursor word expands) — big.txt opens as a file pane
-press left 4 4
-release left 4 4
+press left 4 5
+release left 4 5
stable 400 5000
key enter
stable 700 15000
diff --git a/test/snapshots/ttyonly.golden b/test/snapshots/ttyonly.golden
index b2beabae..64c956d5 100644
--- a/test/snapshots/ttyonly.golden
+++ b/test/snapshots/ttyonly.golden
@@ -1,37 +1,39 @@
-== snap ttyonly grid=100x30 cursor=4,4
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|$ /tmp/pardes-snap/ttyonly/cwd Save New Newtty Del Filter
+== snap ttyonly grid=100x31 cursor=4,5
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+|$ /tmp/pardes-snap/ttyonly/cwd Save Tty Del Togglettymode Filter Collapse
| $ echo TTY''ONLY
| TTYONLY
| $
-== style ttyonly grid=100x30
-|0: 0-74 #949494,#121212, 75-99 d,#121212,
-|1: 0-1 #ffffff,#626262, 2-79 #949494,#121212, 80-99 d,#121212,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|4: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|8: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|11: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|12: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|15: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|16: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|19: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
-|29: 0-0 d,#444444, 1-1 d,#080808, 2-99 #bdbdbd,#080808,
+== style ttyonly grid=100x31
+|0: 0-70 #b2c3b8,#1d2824, 71-99 d,#1d2824,
+|1: 0-24 #becfc4,#26362d, 25-99 d,#26362d,
+|2: 0-1 #000000,#adcc91, 2-72 #becfc4,#26362d, 73-99 d,#26362d,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|5: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|13: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|16: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|17: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|20: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-99 #e5eee5,#0d1410,
diff --git a/test/snapshots/ttyonly.snap b/test/snapshots/ttyonly.snap
index c3d44063..1008e084 100644
--- a/test/snapshots/ttyonly.snap
+++ b/test/snapshots/ttyonly.snap
@@ -1,6 +1,6 @@
# --tty: a single fullscreen shell already in raw tty mode, prompts visible
file t.txt x
-start 30 100 --tty
+start 31 100 --tty
wait 8000 $
stable 700 20000
text echo TTY''ONLY
diff --git a/test/snapshots/ttypaste.golden b/test/snapshots/ttypaste.golden
index 3ab6a246..3a2f629a 100644
--- a/test/snapshots/ttypaste.golden
+++ b/test/snapshots/ttypaste.golden
@@ -1,6 +1,7 @@
-== snap bracketed-paste-reached-the-shell grid=100x30 cursor=18,4
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|$ /tmp/pardes-snap/ttypaste/cwd Save New Newtty De /tmp/pardes-snap/ttypaste/cwd Save New Newtty De
+== snap bracketed-paste-reached-the-shell grid=100x31 cursor=18,5
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+|$ /tmp/pardes-snap/ttypaste/cwd Save Tty Del Toggl /tmp/pardes-snap/ttypaste/cwd Save Tty Del Toggl
| $ ls ls
| src.txt src.txt
| $ echo BRACKETED
@@ -15,7 +16,7 @@
|
|
|
-| /tmp/pardes-snap/ttypaste/cwd Save New Newtty De
+| /tmp/pardes-snap/ttypaste/cwd Save Tty Del Toggl
| ls
| src.txt
-== snap ctrl-v-with-empty-register-is-inert grid=100x30 cursor=18,4
+== snap ctrl-v-with-empty-register-is-inert grid=100x31 cursor=18,5
diff --git a/test/snapshots/ttypaste.snap b/test/snapshots/ttypaste.snap
index d59a0b3e..1591c8c4 100644
--- a/test/snapshots/ttypaste.snap
+++ b/test/snapshots/ttypaste.snap
@@ -10,7 +10,7 @@
# bracketed paste the outer terminal's own paste, or a desktop one relayed
# by a GUI host, which used to land in an overlay instead
file src.txt PASTED-PAYLOAD
-start 30 100 -n 3
+start 31 100 -n 3
wait 8000 src.txt
stable 700 20000
# fill the default register from a file pane: sweep the word and yank it
diff --git a/test/snapshots/ttyprompt.golden b/test/snapshots/ttyprompt.golden
index 7428e913..733cd776 100644
--- a/test/snapshots/ttyprompt.golden
+++ b/test/snapshots/ttyprompt.golden
@@ -1,6 +1,7 @@
-== snap greeted grid=100x30 cursor=4,4
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/ttyprompt/cwd Save New Newtty D /tmp/pardes-snap/ttyprompt/cwd Save New Newtty D
+== snap greeted grid=100x31 cursor=4,5
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/ttyprompt/cwd Save Tty Del Togg /tmp/pardes-snap/ttyprompt/cwd Save Tty Del Togg
| ls ls
| probe.txt probe.txt
|
@@ -15,14 +16,14 @@
|
|
|
-| /tmp/pardes-snap/ttyprompt/cwd Save New Newtty D
+| /tmp/pardes-snap/ttyprompt/cwd Save Tty Del Togg
| ls
| probe.txt
-== snap in-tty grid=100x30 cursor=17,4
-|1: $ /tmp/pardes-snap/ttyprompt/cwd Save New Newtty D /tmp/pardes-snap/ttyprompt/cwd Save New Newtty D
-|2: $ ls ls
-|4: $ echo ABCDEFGH
-== snap out-of-tty grid=100x30 cursor=17,4
-|1: /tmp/pardes-snap/ttyprompt/cwd Save New Newtty D /tmp/pardes-snap/ttyprompt/cwd Save New Newtty D
-|2: ls ls
-|4: echo ABCDEFGH
+== snap in-tty grid=100x31 cursor=17,5
+|2: $ /tmp/pardes-snap/ttyprompt/cwd Save Tty Del Togg /tmp/pardes-snap/ttyprompt/cwd Save Tty Del Togg
+|3: $ ls ls
+|5: $ echo ABCDEFGH
+== snap out-of-tty grid=100x31 cursor=17,5
+|2: /tmp/pardes-snap/ttyprompt/cwd Save Tty Del Togg /tmp/pardes-snap/ttyprompt/cwd Save Tty Del Togg
+|3: ls ls
+|5: echo ABCDEFGH
diff --git a/test/snapshots/ttyprompt.snap b/test/snapshots/ttyprompt.snap
index 9cb377bf..843ffe7c 100644
--- a/test/snapshots/ttyprompt.snap
+++ b/test/snapshots/ttyprompt.snap
@@ -9,7 +9,7 @@
# `.prompt_and_input` is the old behaviour and blanks the whole row; it is a
# comptime choice, so what THIS script pins is the default.
file probe.txt marker
-start 30 100 -n 3
+start 31 100 -n 3
wait 8000 probe.txt
stable 700 20000
# the greeting `ls` was typed at a prompt and already shows the rule: the
diff --git a/test/snapshots/ttytaken.golden b/test/snapshots/ttytaken.golden
index 4bb28c2b..e50c1f8c 100644
--- a/test/snapshots/ttytaken.golden
+++ b/test/snapshots/ttytaken.golden
@@ -1,44 +1,45 @@
-== snap opened grid=210x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/ttytaken/cwd/cmd.txt Save New Newtty Del /tmp/pardes-snap/ttytaken/cwd Save New Newtty Del Filter
+== snap opened grid=210x31 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/ttytaken/cwd/cmd.txt Save Tty Del Collapse /tmp/pardes-snap/ttytaken/cwd Save Tty Del Togglettymode Filter Collapse
| 1 echo TAKEN''ONE ls
| 2 echo TAKEN''TWO big.txt cmd.txt
-== snap at-prompt grid=210x30 cursor=7,2
-|4: echo TAKEN''ONE
-|5: TAKENONE
-== snap paging grid=210x30 cursor=114,29
-|1: /tmp/pardes-snap/ttytaken/cwd/cmd.txt Save New Newtty Del $ /tmp/pardes-snap/ttytaken/cwd Save New Newtty Del Filter
-|2: 1 echo TAKEN''ONE line 1
-|3: 2 echo TAKEN''TWO line 2
-|4: line 3
-|5: line 4
-|6: line 5
-|7: line 6
-|8: line 7
-|9: line 8
-|10: line 9
-|11: line 10
-|12: line 11
-|13: line 12
-|14: line 13
-|15: line 14
-|16: line 15
-|17: line 16
-|18: line 17
-|19: line 18
-|20: line 19
-|21: line 20
-|22: line 21
-|23: line 22
-|24: line 23
-|25: line 24
-|26: line 25
-|27: line 26
-|28: line 27
-|29: big.txt
-== snap spawned grid=210x30 cursor=108,25
-|25: :
-|26: /tmp/pardes-snap/ttytaken/cwd Save New Newtty Del Filter
-|27: echo TAKEN''TWO
-|28: TAKENTWO
-|29:
+== snap at-prompt grid=210x31 cursor=7,3
+|5: echo TAKEN''ONE
+|6: TAKENONE
+== snap paging grid=210x31 cursor=114,30
+|2: /tmp/pardes-snap/ttytaken/cwd/cmd.txt Save Tty Del Collapse $ /tmp/pardes-snap/ttytaken/cwd Save Tty Del Togglettymode Filter Collapse
+|3: 1 echo TAKEN''ONE line 1
+|4: 2 echo TAKEN''TWO line 2
+|5: line 3
+|6: line 4
+|7: line 5
+|8: line 6
+|9: line 7
+|10: line 8
+|11: line 9
+|12: line 10
+|13: line 11
+|14: line 12
+|15: line 13
+|16: line 14
+|17: line 15
+|18: line 16
+|19: line 17
+|20: line 18
+|21: line 19
+|22: line 20
+|23: line 21
+|24: line 22
+|25: line 23
+|26: line 24
+|27: line 25
+|28: line 26
+|29: line 27
+|30: big.txt
+== snap spawned grid=210x31 cursor=108,26
+|26: :
+|27: /tmp/pardes-snap/ttytaken/cwd Save Tty Del Togglettymode Filter Collapse
+|28: echo TAKEN''TWO
+|29: TAKENTWO
+|30:
diff --git a/test/snapshots/ttytaken.snap b/test/snapshots/ttytaken.snap
index 2ef574d0..47554876 100644
--- a/test/snapshots/ttytaken.snap
+++ b/test/snapshots/ttytaken.snap
@@ -5,27 +5,27 @@
# keystrokes the pager would eat. Nothing about the pager's screen changes.
file cmd.txt echo TAKEN''ONE\necho TAKEN''TWO
lines big.txt 40
-start 30 210 -n 1
+start 31 210 -n 1
wait 8000 cmd.txt
stable 700 20000
# open the command file by looking its name in the greeting `ls`
-press right 14 4
-release right 14 4
+press right 14 5
+release right 14 5
wait 10000 echo TAKEN
stable 700 20000
snap opened
# at the prompt: the drag runs in the shell that is already on this directory
-press middle 8 3
-drag middle 22 3
-release middle 22 3
+press middle 8 4
+drag middle 22 4
+release middle 22 4
wait 10000 TAKENONE
stable 700 20000
snap at-prompt
# ...and now a pager owns that terminal. Ctrl-b is raw tty (config.tty_toggle),
# which is how a script types AT the shell instead of into the pane's own edit
# buffer — the same way exec.snap runs a command line.
-press left 150 8
-release left 150 8
+press left 150 9
+release left 150 9
stable 400 5000
key c-b
stable 400 5000
@@ -35,9 +35,9 @@ wait 10000 line 1
stable 700 20000
snap paging
# the same gesture on the second line: a new shell, not `less` keystrokes
-press middle 8 4
-drag middle 22 4
-release middle 22 4
+press middle 8 5
+drag middle 22 5
+release middle 22 5
wait 10000 TAKENTWO
stable 700 20000
snap spawned
diff --git a/test/snapshots/tutor.golden b/test/snapshots/tutor.golden
index 6d105401..afea38e9 100644
--- a/test/snapshots/tutor.golden
+++ b/test/snapshots/tutor.golden
@@ -1,19 +1,20 @@
-== snap tutor grid=150x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /Tutor Save New Newtty Del /tmp/pardes-snap/tutor/cwd Save New Newtty Del Filter
-| 1 ls
+== snap tutor grid=150x31 cursor=7,6
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/tutor/cwd Save Tty Del Togglettymode Filter Collapse /tmp/pardes-snap/tutor/cwd Save Tty Del Togglettymode Filter Collapse
+| ls ls
+|
+| /Tutor Save Tty Del Collapse
+| 1
| 2 PARDES TUTOR
| 3 tmux + vi + acme, from scratch.
| 4
| 5 The model is acme's: EVERYTHING is text, editable and execu↩
| table
-| /tmp/pardes-snap/tutor/cwd Save New Newtty Del Filter
-| ls
-|
-|
-|
-|
-|
-|
-| /tmp/pardes-snap/tutor/cwd Save New Newtty Del Filter
+| 6 the same way. Modal editing (helix-style) lives on top of t↩
+| hat.
+| 7 Press j until you reach the introduction.
+| 8
+| 9
+| /tmp/pardes-snap/tutor/cwd Save Tty Del Togglettymode Filter Collapse
| ls
diff --git a/test/snapshots/tutor.snap b/test/snapshots/tutor.snap
index e177e6d0..ab9cf8e0 100644
--- a/test/snapshots/tutor.snap
+++ b/test/snapshots/tutor.snap
@@ -1,6 +1,6 @@
-# topbar middle-click Tutor opens the embedded tutor as a file pane top-left
-start 30 150 -n 3
-wait 8000 New Newcol
+# topbar middle-click Tutor opens the embedded tutor below its source shell
+start 31 150 -n 3
+wait 8000 Newcol Joincol
stable 700 20000
press middle @Tutor 1
release middle @Tutor 1
diff --git a/test/snapshots/wheeldrift.golden b/test/snapshots/wheeldrift.golden
index a3337e83..e5237fa9 100644
--- a/test/snapshots/wheeldrift.golden
+++ b/test/snapshots/wheeldrift.golden
@@ -1,6 +1,7 @@
-== snap home grid=70x16 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug
-| /tmp/pardes-snap/wheeldrift/cwd/drift.txt Save New Newtty Del
+== snap home grid=70x17 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kil
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/wheeldrift/cwd/drift.txt Save Tty Del Collapse
| 1 line 1_0123456789_abcdefghij_ZEND
| 2 line 2_0123456789_abcdefghij_ZEND
| 3 line 3_0123456789_abcdefghij_ZEND
@@ -15,39 +16,23 @@
| 12 line 12_0123456789_abcdefghij_ZEND
| 13 line 13_0123456789_abcdefghij_ZEND
| 14 line 14_0123456789_abcdefghij_ZEND
-== snap drifted grid=70x16 cursor=7,2
-|2: 6 line 6_0123456789_abcdefghij_ZEND
-|3: 7 line 7_0123456789_abcdefghij_ZEND
-|4: 8 line 8_0123456789_abcdefghij_ZEND
-|5: 9 line 9_0123456789_abcdefghij_ZEND
-|6: 10 line 10_0123456789_abcdefghij_ZEND
-|7: 11 line 11_0123456789_abcdefghij_ZEND
-|8: 12 line 12_0123456789_abcdefghij_ZEND
-|9: 13 line 13_0123456789_abcdefghij_ZEND
-|10: 14 line 14_0123456789_abcdefghij_ZEND
-|11: 15 line 15_0123456789_abcdefghij_ZEND
-|12: 16 line 16_0123456789_abcdefghij_ZEND
-|13: 17 line 17_0123456789_abcdefghij_ZEND
-|14: 18 line 18_0123456789_abcdefghij_ZEND
-|15: 19 line 19_0123456789_abcdefghij_ZEND
-== snap paying grid=70x16 cursor=7,2
-== snap moved grid=70x16 cursor=7,2
-|2: 6 123456789_abcdefghij_ZEND
-|3: 7 123456789_abcdefghij_ZEND
-|4: 8 123456789_abcdefghij_ZEND
-|5: 9 123456789_abcdefghij_ZEND
-|6: 10 0123456789_abcdefghij_ZEND
-|7: 11 0123456789_abcdefghij_ZEND
-|8: 12 0123456789_abcdefghij_ZEND
-|9: 13 0123456789_abcdefghij_ZEND
-|10: 14 0123456789_abcdefghij_ZEND
-|11: 15 0123456789_abcdefghij_ZEND
-|12: 16 0123456789_abcdefghij_ZEND
-|13: 17 0123456789_abcdefghij_ZEND
-|14: 18 0123456789_abcdefghij_ZEND
-|15: 19 0123456789_abcdefghij_ZEND
-== snap rearmed grid=70x16 cursor=7,2
-|2: 5 123456789_abcdefghij_ZEND
+== snap drifted grid=70x17 cursor=7,3
+|3: 6 line 6_0123456789_abcdefghij_ZEND
+|4: 7 line 7_0123456789_abcdefghij_ZEND
+|5: 8 line 8_0123456789_abcdefghij_ZEND
+|6: 9 line 9_0123456789_abcdefghij_ZEND
+|7: 10 line 10_0123456789_abcdefghij_ZEND
+|8: 11 line 11_0123456789_abcdefghij_ZEND
+|9: 12 line 12_0123456789_abcdefghij_ZEND
+|10: 13 line 13_0123456789_abcdefghij_ZEND
+|11: 14 line 14_0123456789_abcdefghij_ZEND
+|12: 15 line 15_0123456789_abcdefghij_ZEND
+|13: 16 line 16_0123456789_abcdefghij_ZEND
+|14: 17 line 17_0123456789_abcdefghij_ZEND
+|15: 18 line 18_0123456789_abcdefghij_ZEND
+|16: 19 line 19_0123456789_abcdefghij_ZEND
+== snap paying grid=70x17 cursor=7,3
+== snap moved grid=70x17 cursor=7,3
|3: 6 123456789_abcdefghij_ZEND
|4: 7 123456789_abcdefghij_ZEND
|5: 8 123456789_abcdefghij_ZEND
@@ -61,3 +46,19 @@
|13: 16 0123456789_abcdefghij_ZEND
|14: 17 0123456789_abcdefghij_ZEND
|15: 18 0123456789_abcdefghij_ZEND
+|16: 19 0123456789_abcdefghij_ZEND
+== snap rearmed grid=70x17 cursor=7,3
+|3: 5 123456789_abcdefghij_ZEND
+|4: 6 123456789_abcdefghij_ZEND
+|5: 7 123456789_abcdefghij_ZEND
+|6: 8 123456789_abcdefghij_ZEND
+|7: 9 123456789_abcdefghij_ZEND
+|8: 10 0123456789_abcdefghij_ZEND
+|9: 11 0123456789_abcdefghij_ZEND
+|10: 12 0123456789_abcdefghij_ZEND
+|11: 13 0123456789_abcdefghij_ZEND
+|12: 14 0123456789_abcdefghij_ZEND
+|13: 15 0123456789_abcdefghij_ZEND
+|14: 16 0123456789_abcdefghij_ZEND
+|15: 17 0123456789_abcdefghij_ZEND
+|16: 18 0123456789_abcdefghij_ZEND
diff --git a/test/snapshots/wheeldrift.snap b/test/snapshots/wheeldrift.snap
index 5122c949..48d3c627 100644
--- a/test/snapshots/wheeldrift.snap
+++ b/test/snapshots/wheeldrift.snap
@@ -7,7 +7,7 @@
# The drift ticks here are all rightward on purpose: leftward drift at column 0
# is clamped away and would prove nothing.
lines drift.txt 20 _0123456789_abcdefghij_ZEND
-start 16 70 drift.txt
+start 17 70 drift.txt
wait 8000 drift.txt
stable 700 20000
# the guard protects HSCROLL, and hscroll only exists with soft wrap off (a
@@ -20,10 +20,10 @@ snap home
# view scrolls DOWN five lines and does not move one column sideways.
wheel down 10 5
wheel down 10 5
-send \x1b[<66;10;5M
+send \x1b[<66;10;6M
wheel down 10 5
-send \x1b[<66;10;5M
-send \x1b[<66;10;5M
+send \x1b[<66;10;6M
+send \x1b[<66;10;6M
wheel down 10 5
wheel down 10 5
stable 400 5000
@@ -31,20 +31,20 @@ snap drifted
# the guard is armed at 3 now, so a DELIBERATE horizontal swipe pays it off
# first: these three ticks still move nothing (without the guard they would
# have shifted the text 12 columns)
-send \x1b[<66;10;5M
-send \x1b[<66;10;5M
-send \x1b[<66;10;5M
+send \x1b[<66;10;6M
+send \x1b[<66;10;6M
+send \x1b[<66;10;6M
stable 400 5000
snap paying
# ...and from the fourth tick on it scrolls freely: two ticks, 8 columns
-send \x1b[<66;10;5M
-send \x1b[<66;10;5M
+send \x1b[<66;10;6M
+send \x1b[<66;10;6M
stable 400 5000
snap moved
# vertical again re-arms the guard, so drift is swallowed once more even
# though horizontal was just running
wheel up 10 5
-send \x1b[<66;10;5M
-send \x1b[<66;10;5M
+send \x1b[<66;10;6M
+send \x1b[<66;10;6M
stable 400 5000
snap rearmed
diff --git a/test/snapshots/winch.golden b/test/snapshots/winch.golden
index c40f278b..6fc444d6 100644
--- a/test/snapshots/winch.golden
+++ b/test/snapshots/winch.golden
@@ -1,6 +1,7 @@
-== snap storm grid=100x30 cursor=4,6
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|$ /tmp/pardes-snap/winch/cwd Save New Newtty Del F /tmp/pardes-snap/winch/cwd Save New Newtty Del F
+== snap storm grid=100x31 cursor=4,7
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+|$ /tmp/pardes-snap/winch/cwd Save Tty Del Togglett /tmp/pardes-snap/winch/cwd Save Tty Del Togglett
| $ ls ls
| $ for i in $(seq 600); do kill -WINCH $PPID; don
| e; echo SUR''VIVED
@@ -15,11 +16,12 @@
|
|
|
-| /tmp/pardes-snap/winch/cwd Save New Newtty Del F
+| /tmp/pardes-snap/winch/cwd Save Tty Del Togglett
| ls
-== snap resized grid=106x34 cursor=4,6
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-|$ /tmp/pardes-snap/winch/cwd Save New Newtty Del Filt /tmp/pardes-snap/winch/cwd Save New Newtty Del Filt
+== snap resized grid=106x35 cursor=4,7
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+|$ /tmp/pardes-snap/winch/cwd Save Tty Del Togglettymo /tmp/pardes-snap/winch/cwd Save Tty Del Togglettymo
| $ ls ls
| $ for i in $(seq 600); do kill -WINCH $PPID; done;
| echo SUR''VIVED
@@ -36,5 +38,5 @@
|
|
|
-| /tmp/pardes-snap/winch/cwd Save New Newtty Del Filt
+| /tmp/pardes-snap/winch/cwd Save Tty Del Togglettymo
| ls
diff --git a/test/snapshots/winch.snap b/test/snapshots/winch.snap
index b1376ab3..d8cbb30a 100644
--- a/test/snapshots/winch.snap
+++ b/test/snapshots/winch.snap
@@ -5,7 +5,7 @@
# machinery and killed pardes. Now every thread blocks SIGWINCH and a sigwait
# watcher consumes it. The in-pane kill storm below crashed pardes before the
# fix; the resize after proves the watcher still reflows the grid.
-start 30 100 -n 3
+start 31 100 -n 3
stable 700 20000
key c-b
stable 600 8000
@@ -14,6 +14,6 @@ key enter
wait 15000 SURVIVED
stable 700 15000
snap storm
-resize 34 106
+resize 35 106
stable 700 15000
snap resized
diff --git a/test/snapshots/windownav.golden b/test/snapshots/windownav.golden
index 4ad47da5..c2d385cb 100644
--- a/test/snapshots/windownav.golden
+++ b/test/snapshots/windownav.golden
@@ -1,20 +1,21 @@
-== snap start grid=100x30 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/windownav/cwd/w.txt Save New Ne /tmp/pardes-snap/windownav/cwd Save New Newtty D
+== snap start grid=100x31 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol New Tty Find Grep Joincol
+| /tmp/pardes-snap/windownav/cwd/w.txt Save Tty De /tmp/pardes-snap/windownav/cwd Save Tty Del Togg
| 1 alpha ls
| 2 beta w.txt
| 3 gamma
-== snap to-term grid=100x30 cursor=54,4
-== snap back-to-file grid=100x30 cursor=7,2
-== snap esc-to-term grid=100x30 cursor=54,4
-== snap esc-back-to-file grid=100x30 cursor=7,2
-== snap altn grid=100x30 cursor=4,19
-|16: /tmp/pardes-snap/windownav/cwd Save New Newtty D
-|17: ls
-|18: w.txt
-== snap up grid=100x30 cursor=7,2
-== snap right grid=100x30 cursor=54,4
-== snap left grid=100x30 cursor=7,2
-== snap down grid=100x30 cursor=4,19
-== snap toggle-doc grid=100x30 cursor=7,2
-== snap toggle-back grid=100x30 cursor=4,19
+== snap to-term grid=100x31 cursor=54,5
+== snap back-to-file grid=100x31 cursor=7,3
+== snap esc-to-term grid=100x31 cursor=54,5
+== snap esc-back-to-file grid=100x31 cursor=7,3
+== snap altn grid=100x31 cursor=4,20
+|17: /tmp/pardes-snap/windownav/cwd Save Tty Del Togg
+|18: ls
+|19: w.txt
+== snap up grid=100x31 cursor=7,3
+== snap right grid=100x31 cursor=54,5
+== snap left grid=100x31 cursor=7,3
+== snap down grid=100x31 cursor=4,20
+== snap toggle-doc grid=100x31 cursor=7,3
+== snap toggle-back grid=100x31 cursor=4,20
diff --git a/test/snapshots/windownav.snap b/test/snapshots/windownav.snap
index 43dc9839..66509e11 100644
--- a/test/snapshots/windownav.snap
+++ b/test/snapshots/windownav.snap
@@ -8,8 +8,8 @@
# `cursor=` header: that is the
# ACTIVE pane's cursor, so each snap is named by the pane it should land in.
file w.txt alpha\nbeta\ngamma
-start 30 100 w.txt
-wait 8000 New Newcol
+start 31 100 w.txt
+wait 8000 Newcol Joincol
wait 8000 w.txt
stable 700 20000
# A FILE boots alone now, so the terminal every hop below needs is opened here:
diff --git a/test/snapshots/windowops.golden b/test/snapshots/windowops.golden
index 7c294d9b..4fd4b165 100644
--- a/test/snapshots/windowops.golden
+++ b/test/snapshots/windowops.golden
@@ -1,6 +1,7 @@
-== snap hover-v grid=100x30 cursor=4,4
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/windowops/cwd Save New Newtty ╎ /tmp/pardes-snap/windowops/cwd Save New Newtty D
+== snap hover-v grid=100x31 cursor=4,5
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol ╎New Tty Find Grep Joincol
+| /tmp/pardes-snap/windowops/cwd Save Tty Del Tog╎ /tmp/pardes-snap/windowops/cwd Save Tty Del Togg
| ls ╎ ls
| w.txt ╎ w.txt
| ╎
@@ -15,7 +16,7 @@
| ╎
| ╎
| ╎
-| /tmp/pardes-snap/windowops/cwd Save New Newtty ╎
+| /tmp/pardes-snap/windowops/cwd Save Tty Del Tog╎
| ls ╎
| w.txt ╎
| ╎
@@ -29,11 +30,11 @@
| ╎
| ╎
| ╎
-== snap hover-h grid=100x30 cursor=4,4
-|1: /tmp/pardes-snap/windowops/cwd Save New Newtty D /tmp/pardes-snap/windowops/cwd Save New Newtty D
-|2: ls ls
-|3: w.txt w.txt
-|4:
+== snap hover-h grid=100x31 cursor=4,5
+|1: New Tty Find Grep Joincol New Tty Find Grep Joincol
+|2: /tmp/pardes-snap/windowops/cwd Save Tty Del Togg /tmp/pardes-snap/windowops/cwd Save Tty Del Togg
+|3: ls ls
+|4: w.txt w.txt
|5:
|6:
|7:
@@ -44,11 +45,11 @@
|12:
|13:
|14:
-|15: ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
-|16: /tmp/pardes-snap/windowops/cwd Save New Newtty D
-|17: ls
-|18: w.txt
-|19:
+|15:
+|16:
+|17: /tmp/pardes-snap/windowops/cwd Save Tty Del Togg
+|18: ls
+|19: w.txt
|20:
|21:
|22:
@@ -59,11 +60,12 @@
|27:
|28:
|29:
-== snap border-drag grid=100x30 cursor=4,4
-|1: /tmp/pardes-snap/windowops/cwd Save N╎w Newtty D /tmp/pardes-snap/windowops/cwd Save New Newtty D
-|2: ls ╎ ls
-|3: w.txt ╎ w.txt
-|4: ╎
+|30:
+== snap border-drag grid=100x31 cursor=4,5
+|1: New Tty Find Grep Joincol ╎ New Tty Find Grep Joincol
+|2: /tmp/pardes-snap/windowops/cwd Save T╎y Del Togg /tmp/pardes-snap/windowops/cwd Save Tty Del Togg
+|3: ls ╎ ls
+|4: w.txt ╎ w.txt
|5: ╎
|6: ╎
|7: ╎
@@ -75,10 +77,10 @@
|13: ╎
|14: ╎
|15: ╎
-|16: /tmp/pardes-snap/windowops/cwd Save N╎w Newtty D
-|17: ls ╎
-|18: w.txt ╎
-|19: ╎
+|16: ╎
+|17: /tmp/pardes-snap/windowops/cwd Save T╎y Del Togg
+|18: ls ╎
+|19: w.txt ╎
|20: ╎
|21: ╎
|22: ╎
@@ -89,27 +91,29 @@
|27: ╎
|28: ╎
|29: ╎
-== snap border-done grid=100x30 cursor=4,4
-|1: /tmp/pardes-snap/windowops/cwd Save N╎ /tmp/pardes-snap/windowops/cwd Save New Newtty Del Filter
-|2: ls ╎ ls
-|3: w.txt ╎ w.txt
-|16: /tmp/pardes-snap/windowops/cwd Save N╎
-== snap hborder-done grid=100x30 cursor=4,4
-|1: /tmp/pardes-snap/windowops/cwd Save Ne /tmp/pardes-snap/windowops/cwd Save New Newtty Del Filter
-|2: ls ls
-|3: w.txt w.txt
-|4:
+|30: ╎
+== snap border-done grid=100x31 cursor=4,5
+|1: New Tty Find Grep Joincol ╎New Tty Find Grep Joincol
+|2: /tmp/pardes-snap/windowops/cwd Save T╎ /tmp/pardes-snap/windowops/cwd Save Tty Del Togglettymode
+|3: ls ╎ ls
+|4: w.txt ╎ w.txt
+|17: /tmp/pardes-snap/windowops/cwd Save T╎
+== snap hborder-done grid=100x31 cursor=4,5
+|1: New Tty Find Grep Joincol New Tty Find Grep Joincol
+|2: /tmp/pardes-snap/windowops/cwd Save Tt /tmp/pardes-snap/windowops/cwd Save Tty Del Togglettymode
+|3: ls ls
+|4: w.txt w.txt
|5:
|6:
|7:
|8:
|9:
|10:
-|11: ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
-|12: /tmp/pardes-snap/windowops/cwd Save Ne
-|13: ls
-|14: w.txt
-|15:
+|11:
+|12: ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
+|13: /tmp/pardes-snap/windowops/cwd Save Tt
+|14: ls
+|15: w.txt
|16:
|17:
|18:
@@ -124,61 +128,63 @@
|27:
|28:
|29:
-== snap move-preview grid=100x30 cursor=4,15
-|11:
-== snap moved grid=100x30 cursor=4,15
-== snap altn grid=100x30 cursor=4,19
-|16: /tmp/pardes-snap/windowops/cwd Save Ne
-|17: ls
-|18: w.txt
-== snap focus-right grid=100x30 cursor=44,4
-== snap debug-on grid=100x30 cursor=44,4
-|1: /tmp/pardes-snap/windowops/cwd Save Ne /tmp/pardes-snap/win╭────────────────────────────────────╮
-|2: ls ls │pardes resizes=1 │
-|3: w.txt w.txt │theme helix │
-|4: │font default │
+|30:
+== snap move-preview grid=100x31 cursor=4,16
+|12:
+== snap moved grid=100x31 cursor=4,16
+== snap altn grid=100x31 cursor=4,20
+|17: /tmp/pardes-snap/windowops/cwd Save Tt
+|18: ls
+|19: w.txt
+== snap focus-right grid=100x31 cursor=44,5
+== snap debug-on grid=100x31 cursor=44,5
+|1: New Tty Find Grep Joincol New Tty Find Grep Join╭────────────────────────────────────╮
+|2: /tmp/pardes-snap/windowops/cwd Save Tt /tmp/pardes-snap/win│pardes resizes=1 │
+|3: ls ls │theme orchard │
+|4: w.txt w.txt │font default │
|5: │terms 4 cols 2 │
|6: │active #2 58x28 │
|7: │scroll 0/28 │
|8: │pinch 1.0000 │
|9: │tscroll 0.0000 │
|10: ╰────────────────────────────────────╯
-== style debug-on grid=100x30
-|0: 0-64 #949494,#121212, 65-69 #080808,#80a0ff, 70-74 #949494,#121212, 75-99 d,#121212,
-|1: 0-1 #ffffff,#262626, 2-39 #949494,#121212, 40-41 #ffffff,#626262, 42-61 #949494,#121212, 62-99 d,d,
-|2: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-61 #bdbdbd,#080808, 62-62 d,d, 63-79 #949494,d, 80-98 d,#121212, 99-99 d,d,
-|3: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-61 #bdbdbd,#080808, 62-62 d,d, 63-74 #949494,d, 75-98 d,#121212, 99-99 d,d,
-|4: 0-0 d,#444444, 1-39 d,#080808, 40-40 d,#444444, 41-61 d,#080808, 62-62 d,d, 63-76 #949494,d, 77-98 d,#121212, 99-99 d,d,
-|5: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-61 #bdbdbd,#080808, 62-62 d,d, 63-77 #949494,d, 78-98 d,#121212, 99-99 d,d,
-|6: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-61 #bdbdbd,#080808, 62-62 d,d, 63-78 #949494,d, 79-98 d,#121212, 99-99 d,d,
-|7: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-61 #bdbdbd,#080808, 62-62 d,d, 63-73 #949494,d, 74-98 d,#121212, 99-99 d,d,
-|8: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-61 #bdbdbd,#080808, 62-62 d,d, 63-75 #949494,d, 76-98 d,#121212, 99-99 d,d,
-|9: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-61 #bdbdbd,#080808, 62-62 d,d, 63-77 #949494,d, 78-98 d,#121212, 99-99 d,d,
-|10: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-61 #bdbdbd,#080808, 62-99 d,d,
-|11: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-99 #bdbdbd,#080808,
-|12: 0-1 #ffffff,#262626, 2-39 #949494,#121212, 40-40 d,#444444, 41-41 d,#080808, 42-99 #bdbdbd,#080808,
-|13: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-99 #bdbdbd,#080808,
-|14: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-99 #bdbdbd,#080808,
-|15: 0-0 d,#444444, 1-39 d,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-99 #bdbdbd,#080808,
-|16: 0-1 #ffffff,#262626, 2-39 #949494,#121212, 40-40 d,#444444, 41-41 d,#080808, 42-99 #bdbdbd,#080808,
-|17: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-99 #bdbdbd,#080808,
-|18: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-99 #bdbdbd,#080808,
-|19: 0-0 d,#444444, 1-39 d,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-99 #bdbdbd,#080808,
-|20: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-99 #bdbdbd,#080808,
-|21: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-99 #bdbdbd,#080808,
-|22: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-99 #bdbdbd,#080808,
-|23: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-99 #bdbdbd,#080808,
-|24: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-99 #bdbdbd,#080808,
-|25: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-99 #bdbdbd,#080808,
-|26: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-99 #bdbdbd,#080808,
-|27: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-99 #bdbdbd,#080808,
-|28: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-99 #bdbdbd,#080808,
-|29: 0-0 d,#444444, 1-1 d,#080808, 2-39 #bdbdbd,#080808, 40-40 d,#444444, 41-41 d,#080808, 42-99 #bdbdbd,#080808,
-== snap debug-off grid=100x30 cursor=44,4
-|1: /tmp/pardes-snap/windowops/cwd Save Ne /tmp/pardes-snap/windowops/cwd Save New Newtty Del Filter
-|2: ls ls
-|3: w.txt w.txt
-|4:
+== style debug-on grid=100x31
+|0: 0-60 #b2c3b8,#1d2824, 61-65 #f5f7ee,#405d4b, 66-70 #b2c3b8,#1d2824, 71-99 d,#1d2824,
+|1: 0-24 #b2c3b8,#1d2824, 25-39 d,#1d2824, 40-61 #becfc4,#26362d, 62-99 d,d,
+|2: 0-1 #ffffff,#4c6356, 2-39 #b2c3b8,#1d2824, 40-41 #000000,#adcc91, 42-61 #becfc4,#26362d, 62-62 d,d, 63-79 #b2c3b8,d, 80-98 d,#152019, 99-99 d,d,
+|3: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-61 #e5eee5,#0d1410, 62-62 d,d, 63-76 #b2c3b8,d, 77-98 d,#152019, 99-99 d,d,
+|4: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-61 #e5eee5,#0d1410, 62-62 d,d, 63-76 #b2c3b8,d, 77-98 d,#152019, 99-99 d,d,
+|5: 0-0 d,#637f6a, 1-39 d,#0d1410, 40-40 d,#637f6a, 41-61 d,#0d1410, 62-62 d,d, 63-77 #b2c3b8,d, 78-98 d,#152019, 99-99 d,d,
+|6: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-61 #e5eee5,#0d1410, 62-62 d,d, 63-78 #b2c3b8,d, 79-98 d,#152019, 99-99 d,d,
+|7: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-61 #e5eee5,#0d1410, 62-62 d,d, 63-73 #b2c3b8,d, 74-98 d,#152019, 99-99 d,d,
+|8: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-61 #e5eee5,#0d1410, 62-62 d,d, 63-75 #b2c3b8,d, 76-98 d,#152019, 99-99 d,d,
+|9: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-61 #e5eee5,#0d1410, 62-62 d,d, 63-77 #b2c3b8,d, 78-98 d,#152019, 99-99 d,d,
+|10: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-61 #e5eee5,#0d1410, 62-99 d,d,
+|11: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-99 #e5eee5,#0d1410,
+|12: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-99 #e5eee5,#0d1410,
+|13: 0-1 #ffffff,#4c6356, 2-39 #b2c3b8,#1d2824, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-99 #e5eee5,#0d1410,
+|14: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-99 #e5eee5,#0d1410,
+|15: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-99 #e5eee5,#0d1410,
+|16: 0-0 d,#637f6a, 1-39 d,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-99 #e5eee5,#0d1410,
+|17: 0-1 #ffffff,#4c6356, 2-39 #b2c3b8,#1d2824, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-99 #e5eee5,#0d1410,
+|18: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-99 #e5eee5,#0d1410,
+|19: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-99 #e5eee5,#0d1410,
+|20: 0-0 d,#637f6a, 1-39 d,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-99 #e5eee5,#0d1410,
+|21: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-99 #e5eee5,#0d1410,
+|22: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-99 #e5eee5,#0d1410,
+|23: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-99 #e5eee5,#0d1410,
+|24: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-99 #e5eee5,#0d1410,
+|25: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-99 #e5eee5,#0d1410,
+|26: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-99 #e5eee5,#0d1410,
+|27: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-99 #e5eee5,#0d1410,
+|28: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-99 #e5eee5,#0d1410,
+|29: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-99 #e5eee5,#0d1410,
+|30: 0-0 d,#637f6a, 1-1 d,#0d1410, 2-39 #e5eee5,#0d1410, 40-40 d,#637f6a, 41-41 d,#0d1410, 42-99 #e5eee5,#0d1410,
+== snap debug-off grid=100x31 cursor=44,5
+|1: New Tty Find Grep Joincol New Tty Find Grep Joincol
+|2: /tmp/pardes-snap/windowops/cwd Save Tt /tmp/pardes-snap/windowops/cwd Save Tty Del Togglettymode
+|3: ls ls
+|4: w.txt w.txt
|5:
|6:
|7:
diff --git a/test/snapshots/windowops.snap b/test/snapshots/windowops.snap
index 709cfa02..32d8c83b 100644
--- a/test/snapshots/windowops.snap
+++ b/test/snapshots/windowops.snap
@@ -1,6 +1,6 @@
# hover resize hints, border drags, move drag, Alt-n, Ctrl-w focus (routed through the Right builtin), Debug box
file w.txt x
-start 30 100 -n 3
+start 31 100 -n 3
wait 8000 w.txt
stable 700 20000
# hover over the left column's last col: vertical dash hint
@@ -12,25 +12,25 @@ motion 20 16
stable 400 5000
snap hover-h
# drag the vertical border 10 cols left
-press left 50 10
-drag left 40 10
+press left 50 11
+drag left 40 11
stable 400 5000
snap border-drag
-release left 40 10
+release left 40 11
stable 500 8000
snap border-done
# drag the horizontal border up 4 rows (pane 0's new last row)
-press left 20 16
-drag left 20 12
-release left 20 12
+press left 20 17
+drag left 20 13
+release left 20 13
stable 500 8000
snap hborder-done
# move pane 1 (its gutter box) into the right column
-press left 1 17
-drag left 70 8
+press left 1 18
+drag left 70 9
stable 400 5000
snap move-preview
-release left 70 8
+release left 70 9
stable 500 8000
snap moved
# Alt-n: a new shell below the active pane
diff --git a/test/snapshots/wrap.golden b/test/snapshots/wrap.golden
index 0dc4e770..813d7a44 100644
--- a/test/snapshots/wrap.golden
+++ b/test/snapshots/wrap.golden
@@ -1,6 +1,7 @@
-== snap on-narrow grid=48x14 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tuto
-| /tmp/pardes-snap/wrap/cwd/long.txt Save New Ne
+== snap on-narrow grid=48x15 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Du
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/wrap/cwd/long.txt Save Tty De
| 1 0---------1---------2---------3---------↩
| 4---------5---------6---------7---------↩
| 8---------9---------A---------B---------↩
@@ -9,33 +10,34 @@
| 2 second line
| 3 third line
| 4
-== snap clicked grid=48x14 cursor=17,3
-== snap logical-j grid=48x14 cursor=18,7
-== snap visual-gj grid=48x14 cursor=10,3
-== snap visual-gj-again grid=48x14 cursor=10,4
-== snap visual-gk grid=48x14 cursor=10,3
-== snap visual-count-gj grid=48x14 cursor=10,5
-== snap off grid=48x14 cursor=10,5
-|2: 1 0---------1---------2---------3---------4
-|3: 2 second line
-|4: 3 third line
-|5: 4
-|6:
+== snap clicked grid=48x15 cursor=17,4
+== snap logical-j grid=48x15 cursor=18,8
+== snap visual-gj grid=48x15 cursor=10,4
+== snap visual-gj-again grid=48x15 cursor=10,5
+== snap visual-gk grid=48x15 cursor=10,4
+== snap visual-count-gj grid=48x15 cursor=10,6
+== snap off grid=48x15 cursor=10,6
+|3: 1 0---------1---------2---------3---------4
+|4: 2 second line
+|5: 3 third line
+|6: 4
|7:
|8:
|9:
-== snap on-again grid=48x14 cursor=10,5
-|2: 1 0---------1---------2---------3---------↩
-|3: 4---------5---------6---------7---------↩
-|4: 8---------9---------A---------B---------↩
-|5: C---------D---------E---------F---------↩
-|6: G---------H---------I---------J---------
-|7: 2 second line
-|8: 3 third line
-|9: 4
-== snap on-wide grid=128x14 cursor=7,2
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/wrap/cwd/long.txt Save New Newtty Del
+|10:
+== snap on-again grid=48x15 cursor=10,6
+|3: 1 0---------1---------2---------3---------↩
+|4: 4---------5---------6---------7---------↩
+|5: 8---------9---------A---------B---------↩
+|6: C---------D---------E---------F---------↩
+|7: G---------H---------I---------J---------
+|8: 2 second line
+|9: 3 third line
+|10: 4
+== snap on-wide grid=128x15 cursor=7,3
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/wrap/cwd/long.txt Save Tty Del Collapse
| 1 0---------1---------2---------3---------4---------5---------6---------7---------8---------9---------A---------B---------↩
| C---------D---------E---------F---------G---------H---------I---------J---------
| 2 second line
diff --git a/test/snapshots/wrap.snap b/test/snapshots/wrap.snap
index 51ad6f82..a818bc5f 100644
--- a/test/snapshots/wrap.snap
+++ b/test/snapshots/wrap.snap
@@ -18,8 +18,8 @@
file long.txt 0---------1---------2---------3---------4---------5---------6---------7---------8---------9---------A---------B---------C---------D---------E---------F---------G---------H---------I---------J---------\nsecond line\nthird line\n
# 48 columns: the 2-column chrome gutter, the 5-column line-number gutter and
# the 1 column the `↩` sits in leave 40 for content.
-start 14 48 long.txt
-wait 8000 New Newcol
+start 15 48 long.txt
+wait 8000 Newcol Joincol
stable 700 20000
# the default: five rows for line 1 (200 bytes / 40), the four continuations
# gutterless and starting at `4` `8` `C` `G` — the columns 40, 80, 120, 160 —
@@ -29,8 +29,8 @@ snap on-narrow
# cursor must come back to the cell that was clicked (grid 17,3): the click
# resolved to line 1 column 50, and the render put line 1 column 50 back where
# the finger was. Off by one row and it would land in line 2.
-press left 18 4
-release left 18 4
+press left 18 5
+release left 18 5
stable 400 5000
snap clicked
# motions stay LOGICAL: one `j` from line 1 leaves the whole wrapped line
@@ -74,7 +74,7 @@ stable 400 5000
snap on-again
# 128 columns: 120 for content, and the break is at the `C` — column 120, the
# window's own width. The old 100-column cap would have broken at the `A`.
-start 14 128 long.txt
-wait 8000 New Newcol
+start 15 128 long.txt
+wait 8000 Newcol Joincol
stable 700 20000
snap on-wide
diff --git a/test/snapshots/yankpaste.golden b/test/snapshots/yankpaste.golden
index 87f99294..c3b01b80 100644
--- a/test/snapshots/yankpaste.golden
+++ b/test/snapshots/yankpaste.golden
@@ -1,6 +1,7 @@
-== snap linewise-below grid=100x30 cursor=13,5
-|New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
-| /tmp/pardes-snap/yankpaste/cwd/f.txt * Save New Newtty Del
+== snap linewise-below grid=100x31 cursor=13,6
+|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Kill
+|New Tty Find Grep Joincol
+| /tmp/pardes-snap/yankpaste/cwd/f.txt * Save Tty Del Collapse
| 1 line 1
| 2 line 2
| 3 line 3
@@ -8,18 +9,18 @@
| 5 line 4
| 6 line 5
| 7
-== snap linewise-above grid=100x30 cursor=13,6
-|7: 6 line 2
-|8: 7 line 4
-|9: 8 line 5
-|10: 9
-== snap charwise-inline grid=100x30 cursor=10,2
-|2: 1 liline 1
-== snap blankline grid=100x30 cursor=7,4
-|3: 2
-|4: 3
-|6: 5 line 3
-|9: 8 line 2
-|10: 9 line 4
-|11: 10 line 5
-|12: 11
+== snap linewise-above grid=100x31 cursor=13,7
+|8: 6 line 2
+|9: 7 line 4
+|10: 8 line 5
+|11: 9
+== snap charwise-inline grid=100x31 cursor=10,3
+|3: 1 liline 1
+== snap blankline grid=100x31 cursor=7,5
+|4: 2
+|5: 3
+|7: 5 line 3
+|10: 8 line 2
+|11: 9 line 4
+|12: 10 line 5
+|13: 11
diff --git a/test/snapshots/yankpaste.snap b/test/snapshots/yankpaste.snap
index dc7e2648..ec0f8ca3 100644
--- a/test/snapshots/yankpaste.snap
+++ b/test/snapshots/yankpaste.snap
@@ -4,13 +4,13 @@
# a linewise yank (x) pastes as whole lines below (p) / above (P), a charwise
# yank (v) splices inline after the selection.
lines f.txt 5
-start 30 100 f.txt
-wait 8000 New Newcol
+start 31 100 f.txt
+wait 8000 Newcol Joincol
wait 8000 line 5
stable 700 20000
# linewise: x-select line 2, yank, move down, paste below line 3
-press left 8 4
-release left 8 4
+press left 8 5
+release left 8 5
stable 400 5000
key x y j p
stable 400 5000
@@ -20,8 +20,8 @@ key x y P
stable 400 5000
snap linewise-above
# charwise: v-select two chars of line 1, yank, paste splices after them
-press left 8 3
-release left 8 3
+press left 8 4
+release left 8 4
stable 400 5000
key v l y p
stable 400 5000
diff --git a/test/tag_cleanup.py b/test/tag_cleanup.py
new file mode 100644
index 00000000..81b15ad8
--- /dev/null
+++ b/test/tag_cleanup.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python3
+"""Check compact PDF tags and Togglettymode/Ctrl-B parity in an isolated 9P session."""
+import argparse
+from pathlib import Path
+
+from fs import session, new_pane, execute
+from column_tags import Input as HostInput
+from ui_review import capture, panes, require, wait_for
+
+
+def run(args):
+ root = args.output.resolve()
+ root.mkdir(parents=True, mode=0o700, exist_ok=True)
+ root.chmod(0o700)
+ name = 'tag-cleanup'
+ binary = str(args.binary.resolve())
+ source = Path('docs/design.pdf').resolve()
+ original = source.read_bytes()
+ inherited = {} if args.tty else {
+ 'PARDES_TEST': '1', 'PARDES_TEST_CAPTURE_DIR': str(root),
+ 'PARDES_TEST_COLS': '150', 'PARDES_TEST_ROWS': '48',
+ 'SDL_VIDEODRIVER': 'x11',
+ }
+ launch = ['-c', 'stty cols 150 rows 48; exec "$@"', name, binary,
+ '--9p=' + name, str(source)]
+ terminal = {}
+ with session('/bin/sh', root, name, socket_name=name, tty=True,
+ launch=launch, inherited=inherited, terminal=terminal) as (client, _):
+ keys = HostInput(terminal['input_fd'])
+ pdf = next(serial for serial, tag in panes(client).items() if str(source) in tag)
+ pdf_tag = client.read(f'/self/pane/{pdf}/tag').decode().strip()
+ require(pdf_tag.startswith(str(source) + ' [1/'), 'PDF name/page prefix missing')
+ require(pdf_tag.endswith('] Tty Del PdfSections PdfTint Collapse'), 'PDF commands missing')
+ require(all(word not in pdf_tag for word in ['PdfFit', 'filtered', 'full', 'disabled']), 'PDF tag contains fit or tint-state clutter')
+ control = new_pane(client, b'')
+ before = set(panes(client))
+ execute(client, control, 'Tty')
+ tty = require(wait_for(lambda: next((s for s in panes(client) if s not in before), None)), 'terminal missing')
+ client.write(f'/self/pane/{control}/ctl', b'delete\n') # owned command-only scratch
+
+ def tag_position():
+ frame = client.screen()
+ for row in range(frame['rows']):
+ text = ''.join(c[0] for c in frame['cells'][row * frame['cols']:(row + 1) * frame['cols']])
+ if ' Togglettymode Filter' in text:
+ return text.index(' Togglettymode Filter') + 1, row, text[0]
+ return None
+
+ require(wait_for(lambda: (p := tag_position()) and p[2] == '$'), 'new terminal not in raw mode')
+ x, y, _ = tag_position()
+ keys.click(x, y, button=1)
+ require(wait_for(lambda: (p := tag_position()) and p[2] == ' '), 'Togglettymode click did not enter normal mode')
+ keys.send(b'\x02')
+ require(wait_for(lambda: (p := tag_position()) and p[2] == '$'), 'Ctrl-B did not restore raw mode')
+ x, y, _ = tag_position()
+ keys.click(x, y)
+ keys.send(b'\t')
+ require(wait_for(lambda: (p := tag_position()) and p[2] == ' '), 'Togglettymode from edited tag ignored parked raw mode')
+ keys.send(b'\x02')
+ client.write(f'/self/pane/{tty}/pty/data', b"printf 'Togglettymode toggle ready\\n'\r")
+ require(wait_for(lambda: b'Togglettymode toggle ready' in client.read(f'/self/pane/{tty}/body')), 'terminal input failed')
+ capture(client, root, 'pdf-and-tty-tags', not args.tty)
+ require(source.read_bytes() == original, 'PDF file changed')
+ client.write(f'/self/pane/{tty}/pty/data', b'exit\r')
+ print('PDF tag, Togglettymode click, Ctrl-B, edited-tag execution and source preservation passed')
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('binary', type=Path)
+ parser.add_argument('output', type=Path)
+ parser.add_argument('--tty', action='store_true')
+ run(parser.parse_args())
diff --git a/test/ui_review.py b/test/ui_review.py
new file mode 100644
index 00000000..df492eac
--- /dev/null
+++ b/test/ui_review.py
@@ -0,0 +1,195 @@
+#!/usr/bin/env python3
+"""Capture a read-only Agave review in an isolated SDL or TTY session.
+
+python3 test/ui_review.py zig-out/bin/pardes-gui /tmp/pardes-review \\
+ --project /path/to/agave --theme orchard
+
+Requires rust-analyzer for LSP, an X11 display and ImageMagick for SDL PNGs.
+The project files are never written. Cargo build output stays in --cargo-target
+(or OUTPUT/cargo-target). Use --skip-lsp when reviewing additional themes.
+TTY captures are the actual core grid and styles, not emulator screenshots.
+"""
+import argparse
+import json
+import os
+from pathlib import Path
+import shutil
+import subprocess
+import time
+
+from fs import session
+
+def panes(client):
+ return {int(row.split(maxsplit=5)[0]): row.split(maxsplit=5)[5]
+ for row in client.read('/self/index').decode().splitlines()}
+
+def wait_for(fn, seconds=12):
+ deadline = time.monotonic() + seconds
+ while time.monotonic() < deadline:
+ result = fn()
+ if result:
+ return result
+ time.sleep(.1)
+ return None
+
+def command(client, serial, text):
+ """Execute a temporary tag command without changing source contents."""
+ tag = f'/self/pane/{serial}/tag'
+ before = client.read(tag).rstrip(b'\n')
+ tail_start = before.index(b'Save Tty Del')
+ while tail_start and before[tail_start - 1:tail_start] == b' ':
+ tail_start -= 1
+ client.write(tag, b' ' + text.encode())
+ current = client.read(tag)
+ start = current.rfind(text.encode())
+ client.write(f'/self/pane/{serial}/event', f'Mx{start} {start + len(text.encode())}\n'.encode())
+ client.write(f'/self/pane/{serial}/ctl', b'cleartag\n')
+ client.write(tag, before[tail_start:])
+
+def new_output(client, before):
+ return next((serial for serial in panes(client) if serial not in before and
+ client.read(f'/self/pane/{serial}/body').strip()), None)
+
+def require(value, description):
+ if not value:
+ raise AssertionError(description)
+ return value
+
+def capture(client, root, label, gui):
+ time.sleep(.4)
+ screen = client.screen()
+ (root / (label + '.json')).write_text(json.dumps(screen))
+ cols = screen['cols']
+ text = '\n'.join(''.join(cell[0] for cell in screen['cells'][at:at+cols])
+ for at in range(0, len(screen['cells']), cols))
+ (root / (label + '.txt')).write_text(text)
+ (root / (label + '-index.txt')).write_text(client.read('/self/index').decode())
+ if gui:
+ require(wait_for(lambda: (root / 'latest.ppm').exists(), 8), 'GPU capture missing')
+ def convert_frame():
+ shutil.copyfile(root / 'latest.ppm', root / (label + '.ppm'))
+ return subprocess.run(['magick', str(root / (label + '.ppm')), str(root / (label + '.png'))],
+ stderr=subprocess.DEVNULL).returncode == 0
+ if not wait_for(convert_frame, 8):
+ raise RuntimeError('GPU capture did not contain a complete image')
+ print(label, flush=True)
+
+def run(args):
+ project = args.project.resolve()
+ source_path = project / 'gossip/src/crds_value.rs'
+ original = source_path.read_bytes()
+ root = args.output.resolve()
+ root.mkdir(parents=True, exist_ok=True, mode=0o700)
+ root.chmod(0o700)
+ report = {'find': False, 'grep': False, 'terminal': False, 'source_unchanged': False,
+ 'lsp': 'skipped' if args.skip_lsp else 'requested'}
+ config = root / 'config/pardes'
+ config.mkdir(parents=True, exist_ok=True)
+ (config / 'init').write_text('Shell /bin/sh\n' + (f'Theme {args.theme}\n' if args.theme else ''))
+ name = 'ui-review-' + str(os.getpid())
+ rust = (str(args.rust_analyzer.resolve()) if args.rust_analyzer else
+ subprocess.check_output(['rustup', 'which', 'rust-analyzer'], text=True).strip()) if not args.skip_lsp else ''
+ launch = ['PARDES_LSP_RS=' + rust, 'CARGO_HOME=' + os.path.expanduser('~/.cargo'),
+ 'RUSTUP_HOME=' + os.path.expanduser('~/.rustup'),
+ 'CARGO_TARGET_DIR=' + str((args.cargo_target or root / 'cargo-target').resolve()), 'CARGO_NET_OFFLINE=true',
+ str(args.binary.resolve()), '--9p=' + name, str(source_path)]
+ inherited = {'PARDES_TEST': '1', 'PARDES_TEST_CAPTURE_DIR': str(root),
+ 'PARDES_TEST_COLS': '150', 'PARDES_TEST_ROWS': '48',
+ 'SDL_VIDEODRIVER': 'x11'} if not args.tty else {}
+ launch = ['-c', 'stty cols 150 rows 48; exec "$@"', 'ui-review', '/usr/bin/env', *launch]
+ terminal_handle = {}
+ with session('/bin/sh', root, name, socket_name=name, tty=True,
+ launch=launch, inherited=inherited, terminal=terminal_handle) as (client, address):
+ print('socket', address, flush=True)
+ capture(client, root, '01-source', not args.tty)
+ source = next(serial for serial, tag in panes(client).items() if 'crds_value.rs' in tag)
+ before = panes(client)
+ command(client, source, 'Find crds_value')
+ find_pane = require(wait_for(lambda: new_output(client, before)), 'Find did not return results')
+ require(b'crds_value.rs' in client.read(f'/self/pane/{find_pane}/body'), 'Find result missing source')
+ report['find'] = True
+ capture(client, root, '02-find', not args.tty)
+ if find_pane:
+ (root / 'find-results.txt').write_bytes(client.read(f'/self/pane/{find_pane}/body'))
+ client.write(f'/self/pane/{find_pane}/ctl', b'del\n')
+ before = panes(client)
+ command(client, source, 'Grep CrdsValueLabel')
+ grep_pane = require(wait_for(lambda: new_output(client, before)), 'Grep did not return results')
+ require(b'CrdsValueLabel' in client.read(f'/self/pane/{grep_pane}/body'), 'Grep result missing match')
+ report['grep'] = True
+ if grep_pane:
+ (root / 'grep-results.txt').write_bytes(client.read(f'/self/pane/{grep_pane}/body'))
+ capture(client, root, '03-grep', not args.tty)
+ command(client, source, 'Tty')
+ terminal = require(wait_for(lambda: next((serial for serial in panes(client)
+ if 'pty' in client.list(f'/self/pane/{serial}')), None)),
+ 'Tty did not create a terminal')
+ if terminal:
+ client.write(f'/self/pane/{terminal}/pty/data', b"printf '\\033[1;36mAgave workspace\\033[0m\\n'; pwd; printf '\\033[32mRead-only UI review ready\\033[0m\\n'\r")
+ require(wait_for(lambda: b'\nRead-only UI review ready\n' in
+ client.read(f'/self/pane/{terminal}/body').replace(b'\r', b'')),
+ 'Terminal command output was not observed')
+ report['terminal'] = True
+ capture(client, root, '04-terminal', not args.tty)
+ if not args.skip_lsp:
+ before = panes(client)
+ command(client, source, 'Symbols')
+ symbols = wait_for(lambda: new_output(client, before), args.lsp_wait)
+ report['symbols'] = 'returned results' if symbols else 'no output before deadline'
+ if symbols:
+ (root / 'symbols-results.txt').write_bytes(client.read(f'/self/pane/{symbols}/body'))
+ capture(client, root, '05-symbols', not args.tty)
+ if symbols:
+ client.write(f'/self/pane/{symbols}/ctl', b'del\n')
+ offset = original.index(b'CrdsValue {')
+ client.write(f'/self/pane/{source}/addr', f'#{offset},#{offset}'.encode())
+ client.write(f'/self/pane/{source}/ctl', b'dot=addr\nshow\n')
+ before = panes(client)
+ command(client, source, 'Hover')
+ hover = wait_for(lambda: new_output(client, before), args.lsp_wait)
+ report['hover'] = 'returned results' if hover else 'no output before deadline'
+ if hover:
+ (root / 'hover-results.txt').write_bytes(client.read(f'/self/pane/{hover}/body'))
+ capture(client, root, '06-hover', not args.tty)
+ # Look focuses the source without changing it; gd then travels through
+ # the host's real input parser, unlike tag builtin dispatch above.
+ line = original[:original.index(b'impl Sanitize for CrdsValue')].count(b'\n') + 1
+ client.write(f'/self/pane/{source}/ctl', f'look {source_path}:{line}:19\n'.encode())
+ os.write(terminal_handle['input_fd'], b'gd')
+ time.sleep(1)
+ capture(client, root, '07-definition', not args.tty)
+ command(client, source, 'Lspinfo')
+ lsp = wait_for(lambda: next((serial for serial, tag in panes(client).items() if '+Lsp' in tag), None))
+ if lsp:
+ info = client.read(f'/self/pane/{lsp}/body')
+ (root / 'lsp-info.txt').write_bytes(info)
+ report['lsp'] = info.decode()
+ capture(client, root, '08-lsp-info', not args.tty)
+ if lsp:
+ client.write(f'/self/pane/{lsp}/ctl', b'del\n')
+ for theme in args.themes:
+ command(client, source, 'Theme ' + theme)
+ capture(client, root, 'theme-' + theme, not args.tty)
+ for serial, tag in panes(client).items():
+ if any(word in tag for word in ['+Hover', '+Search']):
+ (root / f'pane-{serial}.txt').write_bytes(client.read(f'/self/pane/{serial}/body'))
+ assert client.read(f'/self/pane/{source}/body') == original == source_path.read_bytes()
+ report['source_unchanged'] = True
+ if terminal:
+ client.write(f'/self/pane/{terminal}/pty/data', b'exit\r')
+ (root / 'report.json').write_text(json.dumps(report, indent=2))
+ print('artifacts', root, flush=True)
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser()
+ parser.add_argument('binary', type=Path)
+ parser.add_argument('output', type=Path)
+ parser.add_argument('--project', required=True, type=Path, help='Agave checkout (read only)')
+ parser.add_argument('--cargo-target', type=Path, help='reuse an isolated cargo target directory')
+ parser.add_argument('--rust-analyzer', type=Path, help='server executable; defaults to rustup which')
+ parser.add_argument('--tty', action='store_true')
+ parser.add_argument('--theme')
+ parser.add_argument('--themes', nargs='*', default=[], help='capture each theme after exercising the workspace')
+ parser.add_argument('--skip-lsp', action='store_true')
+ parser.add_argument('--lsp-wait', type=float, default=25)
+ run(parser.parse_args())
diff --git a/test/web_harness.mjs b/test/web_harness.mjs
index 7bfc2d60..aa6730e9 100644
--- a/test/web_harness.mjs
+++ b/test/web_harness.mjs
@@ -110,7 +110,7 @@ async function main() {
const looked = draw();
assert.match(
looked.cells.map((cell) => cell.text).join(""),
- /build\.zig\s+Save New Newtty Del/,
+ /build\.zig\s+Save Tty Del/,
"right-click LOOK did not open the embedded source",
);
const sourceRows = Array.from({ length: looked.rows }, (_, row) =>