Skip to main content

unwrap-terminal-text

Fixes copy-paste from Claude Code, Codex CLI, and other terminal AI assistants.

Text copied out of a terminal UI arrives broken. Every line carries the interface's left margin, and long lines contain hard newlines at the wrap column rather than soft wraps — so paragraphs paste as ragged fragments, URLs break in half, and code loses its indentation.

This cleans it up. A command-line filter that works anywhere, plus a GTK4 desktop app for Linux where you pick region by region what gets rejoined.

It is not specific to any one assistant — it works on output from any TUI that hard-wraps, including plain less, journalctl, and SSH sessions. The problem is reported repeatedly against Claude Code (#26016, #48768) and Codex CLI (#12200, #8306). Other assistants that render a left gutter are likely affected the same way, though I have only verified those two.

  ▎ Write down what you'd build before running the command, then check
  ▎ whether the brief changed what you'd build first. If it only changed
  ▎ things you weren't going to act on, the questions aren't earning it.

becomes

Write down what you'd build before running the command, then check whether the brief changed what you'd build first. If it only changed things you weren't going to act on, the questions aren't earning it.

Why a tool instead of a regex

Stripping the margin is easy. Deciding which line breaks were real is not — the terminal destroyed that information on the way to your clipboard. A paragraph wrapped at column 80 and a deliberately short line look identical afterwards.

So the transforms are conservative, and the GUI hands the ambiguous call back to you: select the prose, rejoin it; select the code, leave its line breaks alone.

Install

The CLI is pure standard library — no dependencies, any OS with Python 3.9+:

pipx install git+https://github.com/Bishop81/unwrap-terminal-text

or from a clone:

git clone https://github.com/Bishop81/unwrap-terminal-text
cd unwrap-terminal-text
pip install --user .

Not on PyPI yet, so install from the repository for now.

Desktop app (Linux)

The GUI additionally needs GTK4, libadwaita and PyGObject, which come from your distribution rather than pip:

sudo apt install python3-gi gir1.2-gtk-4.0 gir1.2-adw-1     # Debian/Ubuntu
sudo dnf install python3-gobject gtk4 libadwaita            # Fedora

Then ./install-desktop.sh to register the launcher and icon.

libadwaita targets GNOME, so the GUI is effectively Linux-only. The CLI has no such constraint.

Command line

clipclean notes.txt                 # unwrap a file
clipclean -s code.txt               # keep line breaks, drop the margin
clipclean -b notes.txt              # re-bold lead-in labels

xclip -o | clipclean | xclip -i     # X11 clipboard round trip
wl-paste  | clipclean | wl-copy     # Wayland
pbpaste   | clipclean | pbcopy      # macOS
Flag Effect
-u, --unwrap Drop the margin and rejoin wrapped lines (default)
-s, --strip Drop the margin, keep line breaks — use for code
-b, --bold Re-bold lead-in labels before : or an em dash
--no-markers Keep tool glyphs and blockquote rules
--no-linenos Keep line-number prefixes

Desktop app

Opens with your clipboard already loaded. Operations act on the selected lines, or the whole buffer if nothing is selected.

Key Action
Ctrl+U Unwrap — drop the margin, rejoin wrapped lines
Ctrl+K Strip only — drop the margin, keep line breaks
Ctrl+B Bold leads
Ctrl+Return Copy everything back to the clipboard
Ctrl+R Reload from the clipboard
Ctrl+Z Undo

It also takes a file path, and opens it in the running window.

What it cleans

  • Left margin — removes the common leading indent, so relative indentation inside a code block survives.
  • Hard wraps — rejoins wrapped lines into paragraphs. Blank lines, bullet lists, numbered lists and table rows stay put.
  • Split URLs — a line ending in a hyphen joins with no gap, so …/claude- + code/issues/1 reassembles correctly.
  • Tool glyphs and blockquote rules⏺ ⎿ ▎ │ and friends at line start.
  • Line-number prefixes1⇥, 1 | , 1→, but only when most lines carry one, so a genuine numbered list is never eaten.
  • ANSI escape codes — always.

Bold leads

Terminals render **bold** as styling and discard the syntax, so it never reaches your clipboard. This puts it back on lead-in labels:

Why: because the terminal ate it.   ->   **Why:** because the terminal ate it.
Line numbers — the 1⇥ prefixes.     ->   **Line numbers** — the 1⇥ prefixes.

It refuses plain hyphens (a well-known thing - not a label), lead-ins over eight words, and anything starting with a quote or bracket, so dict literals, JSON and function signatures are left alone. Running it twice is a no-op.

Known limits

  • A URL broken at a wrap point without a hyphen still gets a space inserted. Recovering that needs the terminal width, which the clipboard doesn't carry.
  • Markdown emphasis other than lead-in labels can't be recovered — the terminal discarded it.
  • Nested blockquote depth is flattened rather than preserved.

Tests

python3 tests/test_core.py    # transforms, no display needed
python3 tests/test_gui.py     # GTK layer, needs a display

samples/ holds fixtures for each transform, including cases that must come back unchanged.

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

unwrap_terminal_text-0.1.0.tar.gz (14.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

unwrap_terminal_text-0.1.0-py3-none-any.whl (11.1 kB view details)

Uploaded Python 3

File details

Details for the file unwrap_terminal_text-0.1.0.tar.gz.

File metadata

  • Download URL: unwrap_terminal_text-0.1.0.tar.gz
  • Upload date:
  • Size: 14.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.3

File hashes

Hashes for unwrap_terminal_text-0.1.0.tar.gz
Algorithm Hash digest
SHA256 852560d6de1c576a28b4855f7c02e58a1b3510ea90a6ed123fa81494f691b82a
MD5 ff5df3706ee0f6d59a3694a1588602b3
BLAKE2b-256 bcb4cf4e075c66879736be9d963a2306fa41eb78719ffad9fc3e3a9740697f0f

See more details on using hashes here.

File details

Details for the file unwrap_terminal_text-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for unwrap_terminal_text-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 87183c2fc2338225b6578c734ecfd450dbcb3aaced79cba745af89b9e883d3b7
MD5 e854fbdb4ac7ae740b31db0dce8e51e5
BLAKE2b-256 998dadf4b55c480b312faa5ea1925f0f89c9351219b76630c2baf7adaee112c1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page