Skip to content

feat(image): add image_quiet option to set the kitty graphics q flag#349

Open
vantroy wants to merge 1 commit into
rockorager:mainfrom
vantroy:image-quiet-option
Open

feat(image): add image_quiet option to set the kitty graphics q flag#349
vantroy wants to merge 1 commit into
rockorager:mainfrom
vantroy:image-quiet-option

Conversation

@vantroy

@vantroy vantroy commented Jun 29, 2026

Copy link
Copy Markdown

Summary

Adds an opt-in Vaxis.Options.image_quiet field that sets the Kitty graphics
quietness (q) flag
on the image transmit, placement, and delete commands. Default is .off, so
existing behavior is byte-for-byte unchanged.

var vx = try vaxis.init(io, alloc, &env_map, .{ .image_quiet = .silent });
value q terminal behavior
.off none reports successes and failures (current default)
.no_ok 1 suppresses success reports, still reports failures
.silent 2 suppresses both

Motivation

When a cell holds an image, vaxis re-emits its placement every frame (image
cells are exempt from the render diff), and the terminal acknowledges each one
with _Gi=N;OK. Transmit and delete are acked too. During a session the reader
thread consumes these, but an application that tears down without draining the
tty (for example, restoring the terminal and exit()ing while a final ack or a
mid-upload transmit ack is still round-tripping) leaks the ack onto the shell
prompt as visible garbage (^[_Gi=1;OK^[\). It is most reproducible over
batched/high-latency links (tmux, SSH), where a backlog of acks arrives after
the app is gone.

Nothing in vaxis depends on these responses: the parser routes every _G APC
to the capability-detection path, which is a no-op after the first one. So
suppressing them is purely removing noise. Doing it unconditionally would change
wire behavior for every consumer, so it is gated behind the option and defaults
off. .no_ok is offered for callers who still want to observe graphics failures
while silencing the success chatter.

Coverage

The flag is applied at every image-command emission: transmitLocalImagePath
(rgb/rgba/png), transmitPreEncodedImage (chunked and non-chunked; the quiet
flag is set on the first chunk, per the protocol), the render and prettyPrint
placements, freeImage, and the bulk delete-all on the hard-reset path. The
capability query (a=q) is intentionally left untouched; its response is the one
vaxis reads for capability detection.

Tests

Four tests assert the wire output: .silent emits ,q=2 on transmit and on
freeImage, .no_ok emits ,q=1 on transmit, and .off emits no q=
(confirming the non-breaking default).

Open question (happy to adjust)

The q=1 variant is named .no_ok, mirroring the protocol's "suppress OK
responses" wording; .errors_only is an alternative if you'd prefer it read
without protocol context. Likewise I went with a tri-state enum to expose the
q=1/q=2 distinction (error visibility), but a plain bool for q=2 is easy
if you'd rather keep the surface minimal.

Suppresses the terminal's responses to image transmit, placement, and delete commands so they cannot leak to the shell when an app exits before its reader drains them. Defaults to .off (behavior unchanged).
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.

1 participant