Description
Description
When selecting text with the mouse that spans multiple paragraphs (i.e., text separated by blank lines / \n\n), the copied text has all blank lines collapsed to single newlines. For example, if an assistant response contains:
First paragraph.
Second paragraph.
Third paragraph.
Mouse-selecting and pasting produces:
First paragraph.
Second paragraph.
Third paragraph.
The <leader>y keybinding (which copies raw part.text) works correctly and preserves blank lines. Only the mouse selection path is affected.
Probable root cause
The bug is probably in opentui's Zig native code, in packages/core/src/zig/text-buffer-iterators.zig, function extractTextBetweenOffsets. The line_end_callback at line 472 only emits a \n when line_had_content is true:
Working patch
I'm not sure if it's entirely correct, but it works on my system:
--- a/node_modules/.bun/@[email protected]+8e67d58793ed4a15/node_modules/@opentui/core/index.js
+++ b/node_modules/.bun/@[email protected]+8e67d58793ed4a15/node_modules/@opentui/core/index.js
@@ -237,13 +237,32 @@
}
getSelectedText() {
this.guard();
- const byteSize = this.textBuffer.byteSize;
- if (byteSize === 0)
- return "";
- const selectedBytes = this.lib.textBufferViewGetSelectedTextBytes(this.viewPtr, byteSize);
- if (!selectedBytes)
- return "";
- return this.lib.decoder.decode(selectedBytes);
+ const sel = this.getSelection();
+ if (!sel) return "";
+ const plain = this.getPlainText();
+ if (!plain) return "";
+ let offset = 0;
+ let startIdx = -1;
+ let endIdx = plain.length;
+ for (let i = 0; i < plain.length; i++) {
+ if (offset >= sel.end) { endIdx = i; break; }
+ if (offset >= sel.start && startIdx < 0) startIdx = i;
+ const ch = plain.charCodeAt(i);
+ if (ch === 10) { offset += 1; }
+ else if (ch === 9) { offset += 4; }
+ else if (ch >= 0x1100 && (
+ (ch >= 0x1100 && ch <= 0x115F) ||
+ (ch >= 0x2E80 && ch <= 0xA4CF && ch !== 0x303F) ||
+ (ch >= 0xAC00 && ch <= 0xD7A3) ||
+ (ch >= 0xF900 && ch <= 0xFAFF) ||
+ (ch >= 0xFE10 && ch <= 0xFE6F) ||
+ (ch >= 0xFF01 && ch <= 0xFF60) ||
+ (ch >= 0xFFE0 && ch <= 0xFFE6)
+ )) { offset += 2; }
+ else { offset += 1; }
+ }
+ if (startIdx < 0) return "";
+ return plain.slice(startIdx, endIdx);
}
getPlainText() {
this.guard();Plugins
none
OpenCode version
1.2.17
Steps to reproduce
- Start
opencodeTUI and send a prompt that will produce a response with multiple paragraphs separated by blank lines (e.g., "Write three short paragraphs separated by blank lines") - Use the mouse to click-and-drag to select text spanning across one or more blank lines
- Paste the selection into any editor or terminal
- Observe that all blank lines (
\n\n) have been collapsed to single newlines (\n)
Screenshot and/or share link
N/A — the bug is in the clipboard content, not visible on screen.
Operating System
NixOS 25.11 (Linux x86_64), but the bug is platform-independent (it's in the Zig/JS layer of opentui).
Terminal
Alacritty
Activity
github-actions commentedon Mar 7, 2026
This issue might be a duplicate of existing issues. Please check:
\n\nto\n)benkoppe commentedon Jun 2, 2026
Fixed by anomalyco/opentui#1103
michalrus commentedon Jun 14, 2026
Yup, I confirm that – thanks!