Summary
When text wraps due to terminal width in the TUI, selecting and copying it with the terminal's native selection (mouse drag, etc.) includes artificial line breaks at each wrap boundary. The copied text is fragmented with \n characters that don't exist in the original content. Users should be able to copy the actual text as it is, without these wrap-induced breaks.
Current Behavior
- The TUI wraps text via
wrapTextWithAnsi() in packages/tui/src/utils.ts to fit the viewport width
- When a user selects wrapped text in their terminal emulator and copies it, the clipboard receives the text with line breaks inserted at every wrap point
- The only existing copy mechanism is the
/copy command (handleCopyCommand() in interactive-mode.ts), which copies the last assistant message's original text — but this doesn't help when the user wants to copy any arbitrary text (user messages, code blocks, status text, etc.)
Proposed Behavior
Provide a way to copy displayed text from the TUI that preserves the original unwrapped content, without terminal-width line breaks.
Acceptance Criteria
Context
- Text wrapping implementation:
packages/tui/src/utils.ts (wrapTextWithAnsi, wrapSingleLine)
- TUI Text component:
packages/tui/src/components/text.ts
- Current copy command:
packages/coding-agent/src/modes/interactive/interactive-mode.ts (handleCopyCommand)
Technical Notes
Possible approaches to explore:
- TUI text selection mode — Allow keyboard/mouse navigation to select a region of the TUI; the selection logic maps back to the original
Text component's source string and copies that via copyToClipboard()
- Per-message copy commands — Extend
/copy or add keybindings to copy specific messages (e.g., copy the message under cursor)
- Terminal soft-wrap hints — Some terminals support distinguishing soft wraps from hard wraps via escape sequences, but this is not universal enough to be the primary solution
The Text component already caches the original this.text separately from the wrapped cachedLines, which could help map rendered lines back to source text.
Research note: During assessment, look up how other TUI tools (e.g., tmux, vim, neovim, kakoune, helix, lazygit) handle text selection and copying without capturing wrap-induced line breaks. Some may use internal selection buffers, OSC 52 sequences, or terminal soft-wrap signaling.
Summary
When text wraps due to terminal width in the TUI, selecting and copying it with the terminal's native selection (mouse drag, etc.) includes artificial line breaks at each wrap boundary. The copied text is fragmented with
\ncharacters that don't exist in the original content. Users should be able to copy the actual text as it is, without these wrap-induced breaks.Current Behavior
wrapTextWithAnsi()inpackages/tui/src/utils.tsto fit the viewport width/copycommand (handleCopyCommand()ininteractive-mode.ts), which copies the last assistant message's original text — but this doesn't help when the user wants to copy any arbitrary text (user messages, code blocks, status text, etc.)Proposed Behavior
Provide a way to copy displayed text from the TUI that preserves the original unwrapped content, without terminal-width line breaks.
Acceptance Criteria
\ncharacterswrapTextWithAnsiwas applied)Context
packages/tui/src/utils.ts(wrapTextWithAnsi,wrapSingleLine)packages/tui/src/components/text.tspackages/coding-agent/src/modes/interactive/interactive-mode.ts(handleCopyCommand)Technical Notes
Possible approaches to explore:
Textcomponent's source string and copies that viacopyToClipboard()/copyor add keybindings to copy specific messages (e.g., copy the message under cursor)The
Textcomponent already caches the originalthis.textseparately from the wrappedcachedLines, which could help map rendered lines back to source text.