Skip to content

Emit kitty virtual placements per placeholder run from the viewport - #685

Merged
dakra merged 3 commits into
mainfrom
fix/kitty-virtual-viewport-scan
Sep 15, 2026
Merged

dakra merged 3 commits into
mainfrom
fix/kitty-virtual-viewport-scan

Conversation

@dakra

@dakra dakra commented Sep 13, 2026

Copy link
Copy Markdown
Owner

Closes #673.

Once any kitty virtual placement (unicode placeholders, as used by yazi and kitten icat --unicode-placeholder) had been shown, the Elisp side scanned the whole buffer for U+10EEEE on every redraw and sized the image by counting placeholders per line. Large scrollback, such as rg output over long JSON lines, made every prompt repaint pay for that scan. The slice row also came from buffer line order rather than the placeholder's diacritics.

The native side now walks the active area with libghostty's placement iterator and calls ghostel--kitty-display-virtual once per placeholder run with the image row, column and run width. The grid size comes from the placement's c=/r= or the image size, matching libghostty's own resolution. The Elisp tags exactly that run's placeholders plus their combining marks, so two images on one row, or text between two runs, each get their own slice.

Scrollback rows are not revisited: they keep the slices they received while visible, and rows that scrolled out before a redraw get none, the same as pinned placements.

Tests: native tests feed a real 2x2 PNG and placeholder rows through ghostel--write-vt and check one callback per row with the row taken from the diacritics, the screen-row offset once lines have scrolled into scrollback, and no callback for a placement whose placeholders left the active area. Elisp tests cover a single run and two runs on one row with gap text.

Adapt to the ghostty-vt module API since ab0b9da9e:

- Terminal.Options.max_scrollback is max_scrollback_bytes
- DynamicPalette.changeDefault takes an allocator and can fail
- Stream.initAlloc is gone; use Stream.init with an options struct
- the write_pty effect receives a plain slice
- kitty Image.data is a union; read it through renderData().bytes()
- kitty Placement.Location gained a relative variant, drawn via the
  resolved parent chain when it roots at a pin, clipped on all four
  edges like upstream, with pruned anchor pins skipped

Stored kitty images are never PNG anymore (the decode hook converts
them at transmit time), so the PNG pass-through and the is-png
parameter of the Elisp display functions are removed.
Two plain-ghostel (evil-free) regression scenarios plus their shared
setup helper. kitty-ghostel.json (GUI) covers pinned and relative
placements, deletion, the overlay path, virtual placeholders, and
placement eviction; scrollback-ghostel.json (TTY) covers eviction,
a DECSTBM region scroll, wrapped-line rejoin on a widening resize,
and a DECCOLM round trip.
The Elisp side scanned the whole buffer for U+10EEEE on every redraw and sized
the image by counting placeholders per line, so a stale virtual placement taxed
every redraw and the slice row came from buffer line order rather than the
placeholder's diacritics.  The walk starts from the previous redraw's active top
with libghostty's placement iterator instead and hand Elisp one run at a time
with its image row, column and width; the grid size comes from the placement's
c=/r= or the image size.

Closes #673
@dakra
dakra force-pushed the fix/kitty-virtual-viewport-scan branch from f59f1da to fab456e Compare September 15, 2026 05:42
@dakra
dakra merged commit fab456e into main Sep 15, 2026
59 of 60 checks passed
@dakra
dakra deleted the fix/kitty-virtual-viewport-scan branch September 15, 2026 06:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

performance problems, how to measure?

1 participant