Skip to content

fix(graphics): move the cursor past an image as the declared terminal does - #615

Merged
vyncint merged 2 commits into
mainfrom
fix/image-cursor-movement
Oct 27, 2026
Merged

vyncint merged 2 commits into
mainfrom
fix/image-cursor-movement

Conversation

@vyncint

@vyncint vyncint commented Oct 27, 2026

Copy link
Copy Markdown
Owner

A terminal that speaks kitty or sixel graphics moves the cursor past an image it places. termlens left the cursor where the image began, so text an application wrote after an image landed on top of it. docs/DESIGN.md also said that neither protocol moves the cursor.

The emulator now follows the terminal the test declared with graphics() and cell_size():

  • kitty moves the cursor onto the placement's last row, one column past its right edge. It wraps past the screen's edge and scrolls past the bottom margin, unless C=1, U=1 or P= says otherwise. The size in cells comes from c=/r=. Without them it comes from kitty's own update_dest_rect arithmetic over the source rectangle and the cell size. a=p looks up its image's size by id in the payload log.
  • sixel moves the cursor down to the image's last text row and keeps the column, as xterm does with sixel scrolling on. The height is the larger of the raster height and the painted height, measured before a payload past the capture bound is dropped.
  • Graphics::None, the default, still moves nothing, as a terminal without the protocol ignores the escape.

The facts the move needs (a crate-internal Placement) travel beside the payload, not inside it, so the JSON shape is unchanged.

A kitty transmission that names no action is now a=t (transmit only), which is the protocol's default. It used to be reported as placed, which would also have moved the cursor for images kitty never shows.

LIMITATIONS.md says what is not modelled: sixel display mode ?80, xterm's extra scroll for a trailing -, ?8452, and a PNG placed without c=/r=.

Tests

  • Unit tests in emu/vt100.rs:
    • kitty last row / one column past
    • wrap and scroll
    • pixel-sized placement via the cell size
    • sixel last text row with the column kept
  • Unit tests in graphics.rs:
    • placement facts recorded
    • kitty_cells against kitty's arithmetic
    • sixel painted height
  • PTY test a_declared_kitty_terminal_moves_the_cursor_past_a_placement in tests/graphics.rs. It adds a PTY test, so stress is needed.

Closes #588

Signed-off-by: Vyncint Ng 115854244+vyncint@users.noreply.github.com

… does

A terminal that speaks kitty or sixel graphics moves the cursor past an
image it places; termlens left it where the image began, and DESIGN.md
said neither protocol moves it. The emulator now follows the terminal the
test declared with graphics() and cell_size():

- kitty: onto the placement's last row, one column past its right edge,
  wrapping past the screen's edge and scrolling past the bottom margin,
  unless C=1, U=1 or P= says otherwise. The size in cells is c= and r=,
  or kitty's own arithmetic (update_dest_rect) over the source rectangle
  and the cell size; a=p finds its image's size by id in the payload log.
- sixel: to the image's last text row, the column kept, as xterm does
  with sixel scrolling on; the height is the larger of the raster's and
  the painted one, measured before a payload past the capture bound is
  dropped.
- Graphics::None, the default, moves nothing, as a terminal without the
  protocol ignores the escape.

The facts the move needs travel beside the payload, not in it, so the
JSON shape is unchanged. A kitty transmission naming no action is now
a=t, transmit only, the protocol's default; it was reported as placed,
which would also have moved the cursor for images kitty never shows.

Signed-off-by: Vyncint Ng <115854244+vyncint@users.noreply.github.com>
Signed-off-by: Vyncint Ng <115854244+vyncint@users.noreply.github.com>
@vyncint
vyncint merged commit bc92022 into main Oct 27, 2026
31 checks passed
@vyncint
vyncint deleted the fix/image-cursor-movement branch October 27, 2026 10:08
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.

Image escapes never move the cursor, but kitty and xterm both do

1 participant