Repository navigation
fix(tui): copy through tmux to the client showing the pane - #63578
Blandinium wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
The fix works. With real tmux 3.5a at its defaults (set-clipboard external, allow-passthrough off) and an attached client recording what reaches the outer terminal, a write() through a real OpenTUI renderer sent nothing out of tmux on the base branch. With this change, the OSC 52 carrying the copied text reaches the client. With several clients attached, it picks the client of the pane's own session, and set-clipboard off is respected. The clipboard tests pass.
The public API is unchanged: the new env parameter on createClipboardAdapter is internal to the TUI package.
One concern, inline: when tmux doesn't think the outer terminal supports clipboard writes, load-buffer -w still exits 0 but sends nothing. The adapter then skips the existing OSC 52 route, which can break copying for people who use the allow-passthrough on workaround.
| // OpenTUI rejects NUL before any destination; host clipboard text cannot contain it. | ||
| const result = await clipboard.writeText(text.replaceAll("\0", ""), { | ||
| const clean = text.replaceAll("\0", "") | ||
| if (await writeTmux(clean, env)) { |
There was a problem hiding this comment.
load-buffer -w exits 0 even when tmux sends nothing to the client. That happens whenever tmux doesn't think the outer terminal supports clipboard writes. I saw it with an outer TERM=screen-256color, as in nested tmux/screen or terminals not matched by tmux's default xterm*:clipboard feature. In that case this branch writes to the host clipboard only and drops the OpenTUI OSC 52 route. Users who relied on allow-passthrough on (the workaround from #59134) had working copies before and now silently lose them. Keeping destination: "all-available" here would avoid that, at the cost of a harmless duplicate write when passthrough is also on.
There was a problem hiding this comment.
Good catch, thanks. The OpenTUI routes now always run alongside the tmux route, so the allow-passthrough on workaround keeps working; with passthrough on the terminal just gets the same OSC 52 twice.
There was a problem hiding this comment.
Thanks, I checked 4f07d63d0: the OpenTUI routes now run alongside the tmux route, so a terminal tmux doesn't treat as clipboard-capable no longer loses copying when allow-passthrough is on. The updated test passes here with tmux 3.5a (6/6 in clipboard.test.ts). This resolves my concern.
There was a problem hiding this comment.
My earlier point is addressed: the OpenTUI copy routes now run alongside the tmux route, so tmux exiting 0 without forwarding anything no longer drops them. I checked this with an outer TERM=screen-256color client. With tmux 3.5a at its defaults, a copy still reaches the attached client as an OSC 52 escape sequence, and the clipboard tests pass. The public API is unchanged. No new concerns.
Issue for this PR
Closes #50208
Type of change
What does this PR do?
Inside tmux, OpenTUI sends OSC 52 wrapped in a DCS passthrough. tmux drops it unless
allow-passthroughis on, which is not the default, so copying in the TUI never reaches the local clipboard over SSH. A plain OSC 52 would not help either:set-clipboard external, the default, ignores clipboard writes from programs inside tmux.When
$TMUXis set, the TUI now asks tmux which client shows its pane and hands the text totmux load-buffer -w -t <client> -. tmux then forwards it to that client's terminal as its ownset-clipboardsetting allows. The-tmatters: without it, tmux may pick another attached client. The existing OpenTUI routes still run alongside it, becauseload-buffer -wexits 0 even when tmux forwards nothing (for example when it doesn't think the outer terminal supports clipboard writes).How did you verify your code works?
set-clipboard external,allow-passthrough off): selecting text now reaches the local clipboard. Before the change it did not.packages/tui/test/clipboard.test.tsstarts a private tmux server, attaches a client in a PTY, and checks that the OSC 52 with the copied text reaches that client; with no client attached the old route is used.bun run checkpasses.Screenshots / recordings
Not a visual change.
Checklist
Added by the opencode bot (AI-generated).
Related: #59664, #59052