Summary
Selecting text in a Wave terminal block and copying it returns the xterm.js grid view rather than the underlying logical content. For any output that's been visually wrapped at the terminal width, or laid out via cursor-positioning escape codes (TUIs, agent CLIs, progress trackers, tabular output), the copied text comes out with embedded padding spaces, mid-paragraph linebreaks at column boundaries, and other grid-row artifacts that the trim doesn't (and can't) fix.
This makes Wave's terminal copy effectively unusable for capturing prose-y or structured output to paste anywhere else (issue templates, Slack, docs, AI tools).
Where it falls down
frontend/app/view/term/termutil.ts:13-18 is the entire trim:
export function trimTerminalSelection(text: string): string {
return text
.split("\n")
.map((line) => line.trimEnd())
.join("\n");
}
That handles trailing-whitespace-on-each-line. It does not handle:
- Logical lines that were visually wrapped to multiple grid rows. xterm.js's
getSelection() returns text with newlines at each visual row boundary, so a single 600-character paragraph rendered across three 200-column rows comes out as three lines with newlines in the middle of words / mid-sentence.
- Cursor-positioned layouts. TUIs and CLI agents that use
\r + cursor moves to lay out content (Claude Code, npm progress, htop-style refreshes, table renderers) leave the terminal grid full of cells whose layout isn't separated by logical newlines. Copying selects rows of grid cells and joins them — so what looked like "header on its own line, content below" comes out as header[200 spaces]content on one line.
The combination produces things like:
content-length: 142 content-type: text/html; charset=UTF-8
(Real example pasted from a Wave terminal block while drafting an unrelated bug report. The original output had content-length: 142\ncontent-type: ... on two lines; xterm's grid had them on different rows but selection-and-copy collapsed them into one logical line with the visual padding embedded.)
Why this is especially bad for Windows + WSL users
I suspect this hasn't gotten attention because it's most painful for the Windows-host + WSL-distro workflow:
- WSL terminal output frequently runs through long lines that wrap at the Wave window's column count
- Many of the popular Linux-native CLI tools that Windows devs run via WSL (Claude Code, GitHub CLI, kubectl describe, helm output, modern test runners) use cursor-positioned layouts heavily
- The clean workaround on Linux is "select in another terminal emulator that handles this better" — Windows users don't have that fallback handy and Wave is presumably the terminal they want to use
The (clunky) workaround that actually does work: pipe to Windows clipboard directly, bypassing the xterm.js grid:
some-command | clip.exe # WSL → Windows clipboard
cat file.txt | clip.exe # entire file → clipboard
This works because it skips terminal selection entirely. But it's a manual flow, only useful for output you can re-emit, and most users aren't going to know about it.
Request
At minimum a term:smartcopy (or term:logicalcopy) setting that, when enabled, does some combination of:
- Detect visual wraps and unwrap them. If a line ends mid-content (no sentence terminator, no trailing punctuation, no clear EOL marker) and the next line's first non-space char has the same column position as the previous line's left edge, treat as a wrapped continuation and join.
- Collapse runs of 4+ spaces inside a line to a single space. Heuristic, with the obvious risk of breaking aligned-column output (
ls -l, table dumps), so should be opt-in / off-by-default.
- Expose xterm.js's logical-line API if/when xterm.js gains one — there's been intermittent discussion upstream about this. Even today,
Buffer.getLine().isWrapped is available and could drive the unwrap heuristic accurately.
Even shipping #1 alone behind a setting would cover the dominant pain (long-paragraph wrap from CLI agent output) without breaking aligned output.
Filed in venting solidarity with every Windows + WSL Wave user who's pasted a block of output into a ticket and watched it explode into a wall of run-on grid sludge.
Summary
Selecting text in a Wave terminal block and copying it returns the xterm.js grid view rather than the underlying logical content. For any output that's been visually wrapped at the terminal width, or laid out via cursor-positioning escape codes (TUIs, agent CLIs, progress trackers, tabular output), the copied text comes out with embedded padding spaces, mid-paragraph linebreaks at column boundaries, and other grid-row artifacts that the trim doesn't (and can't) fix.
This makes Wave's terminal copy effectively unusable for capturing prose-y or structured output to paste anywhere else (issue templates, Slack, docs, AI tools).
Where it falls down
frontend/app/view/term/termutil.ts:13-18is the entire trim:That handles trailing-whitespace-on-each-line. It does not handle:
getSelection()returns text with newlines at each visual row boundary, so a single 600-character paragraph rendered across three 200-column rows comes out as three lines with newlines in the middle of words / mid-sentence.\r+ cursor moves to lay out content (Claude Code, npm progress, htop-style refreshes, table renderers) leave the terminal grid full of cells whose layout isn't separated by logical newlines. Copying selects rows of grid cells and joins them — so what looked like "header on its own line, content below" comes out asheader[200 spaces]contenton one line.The combination produces things like:
(Real example pasted from a Wave terminal block while drafting an unrelated bug report. The original output had
content-length: 142\ncontent-type: ...on two lines; xterm's grid had them on different rows but selection-and-copy collapsed them into one logical line with the visual padding embedded.)Why this is especially bad for Windows + WSL users
I suspect this hasn't gotten attention because it's most painful for the Windows-host + WSL-distro workflow:
The (clunky) workaround that actually does work: pipe to Windows clipboard directly, bypassing the xterm.js grid:
This works because it skips terminal selection entirely. But it's a manual flow, only useful for output you can re-emit, and most users aren't going to know about it.
Request
At minimum a
term:smartcopy(orterm:logicalcopy) setting that, when enabled, does some combination of:ls -l, table dumps), so should be opt-in / off-by-default.Buffer.getLine().isWrappedis available and could drive the unwrap heuristic accurately.Even shipping #1 alone behind a setting would cover the dominant pain (long-paragraph wrap from CLI agent output) without breaking aligned output.
Filed in venting solidarity with every Windows + WSL Wave user who's pasted a block of output into a ticket and watched it explode into a wall of run-on grid sludge.