feat: forward application OSC 52 clipboard writes through boo ui#95
Merged
Conversation
boo ui renders each session from a client-side libghostty terminal instead of passing output through raw, and libghostty-vt exposes no clipboard effect, so an application's own OSC 52 clipboard write is parsed and dropped. A copy made inside a mouse-driven TUI never reaches the user's clipboard, even though boo ui's own selection already copies via OSC 52. Add a split-safe OSC 52 scanner (src/osc52.zig) that the focused view runs over the session output stream, forwarding each clipboard write verbatim to the real terminal, the same path copySelection uses. Read requests (a "?" payload) are not forwarded, so a remote session cannot read the user's local clipboard. Plain boo attach already forwards OSC 52 as raw passthrough and is unchanged.
In the OSC 52 forwarder, skip non-ESC bytes to the next ESC with indexOfScalar in the ground state, and accumulate a clipboard body up to its BEL/ST terminator with a single appendSlice instead of a per-byte append. Both replace per-byte work on the output hot path the view-canvas already walks once; behavior is unchanged. Also force-import osc52.zig in main.zig's test block, so its unit tests run by the same convention as the sibling filters rather than only because ui.zig happens to reference the module.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
boo uirenders each session from a client-side libghostty terminal and repaints the viewport from its state, rather than passing session output through raw (see theui.zigheader). libghostty-vt parses OSC 52 but exposes no clipboard effect, so when an application inside a session copies text itself (an editor yank, a mouse-driven TUI's selection, anything emittingESC ] 52 ; c ; <base64> BEL), the sequence is parsed and dropped. The copy never reaches the user's clipboard, even over SSH.This is specific to
boo ui:boo ui's own mouse selection already copies via OSC 52 (copySelection), but only when the focused app has not grabbed the mouse.boo uiforwards the mouse to the app, the app does its own copy, and that OSC 52 is swallowed.boo attachis raw passthrough and already forwards an app's OSC 52 unchanged.Fix
Add
src/osc52.zig: a split-safe incremental scanner (modeled onoscquery.zig) that recognizes OSC 52 clipboard writes in a byte stream. The focusedViewruns it over session output infeedOutputand forwards each complete write verbatim to the real terminal (fd 1), the same destination ascopySelection, before the view-canvas parses and drops it.Only writes are forwarded. A read request (
ESC ] 52 ; c ; ? ST) asks the terminal to hand the clipboard back to the application; forwarding it would let a remote session read the user's local clipboard, so a?payload is recognized and ignored. Oversized writes (over 2 MiB) are dropped rather than buffered without bound.Test plan
src/osc52.zig: BEL and ST terminators, read-request rejection, empty/clear payloads, split-across-feeds, OSC 520 and other-OSC near-misses, back-to-back writes, and a long under-cap payload.ui: an application's own OSC 52 clipboard write reaches the real terminal. Confirmed it fails withtimeout: waiting for outputwhen thefeedOutputforwarding line is removed, and passes with it.zig build test-all(163 unit + 81 integration) andzig build test-all -Doptimize=ReleaseSafe: 244/244 pass.zig fmt --checkclean.Decision log
oscquery.Filter(OSC 11 queries) noraltscreen.Filter(screen toggles) strips it. The loss happens in theboo uiclient, wherefeedOutputpipes bytes into the clipboard-less view-canvas. So the fix is client-side, inView.write_pty,bell,color_scheme,device_attributes,enquiry,size,title/pwd,xtversion) has no clipboard callback, so there is nothing to hook. A small passthrough filter matches how OSC 11 and alt-screen toggles are already handled.boo attach.protocol.max_payloadis 1 MiB, so a clipboard write can span multiple.outputframes; the scanner carries candidate state across feeds.Opened by Coder Agents on behalf of @kylecarbs.