Skip to content

feat: terminal coverage (theme detection, 16 colours, ASCII mode, clipboard, doctor) - #20

Merged
borghei merged 8 commits into
mainfrom
feat/platform-terminal
Oct 1, 2026
Merged

borghei merged 8 commits into
mainfrom
feat/platform-terminal

Conversation

@borghei

@borghei borghei commented Oct 1, 2026

Copy link
Copy Markdown
Owner

Summary

Makes ink behave correctly on more terminals and operating systems.

  • Light and dark auto-detection. With no theme set, ink asks the terminal for its background colour (OSC 11, bounded by a DA1 request, 100 ms timeout, 400 ms over SSH). Order: flag or config, terminal answer, COLORFGBG, dark.
  • Clipboard. clip.exe now receives UTF-16LE with a BOM, so non-ASCII text survives on Windows and WSL. Adds a PowerShell fallback on WSL, termux-clipboard-set on Termux, and OSC 52 wrapping under GNU screen.
  • Mouse. New --no-mouse flag; the file browser now honours mouse_capture.
  • 16-colour tier for terminals without 256-colour support. With --color=never or NO_COLOR the reader uses no colour, with reverse video for selection and hints.
  • --ascii mode for the Linux console, legacy Windows fonts and screen readers: body, tables, code boxes, popups, status bar, browser and mermaid. Automatic for TERM=linux and non-UTF-8 locales; also [behavior] ascii = true.
  • No startup stall. The image-protocol probe is skipped when stdout is not a terminal, on TERM=linux or dumb, and in Apple Terminal.
  • ink doctor now reports environment, colour, theme, clipboard, input and config, with home paths and session values redacted.

Testing

  • 336 tests pass locally after merging current main, including a new pty suite (tests/pty.rs, Unix only) that plays the terminal side: background replies, mouse sequences, startup time, ASCII-only reader output.
  • Default Unicode snapshots are byte-identical.
  • Compile-checked for Windows; behaviour on Windows, WSL, Termux, the Linux console, tmux and screen was not run on real systems.

Known issue, not fixed here

If a terminal answers none of the image-protocol queries, a leftover reader thread in ratatui-image can swallow the next keystroke. Real terminals answer DA1, so this is rare.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UVcvmQrSXd2eyt32g4ko19

With no --theme and no config theme, ask the terminal for its background
colour (OSC 11, bounded by a trailing DA1 request and a 100 ms timeout,
400 ms over SSH) before the TUI starts, in raw mode with the mode restored
on every path. Parses rgb:R/G/B (1-4 hex digits) and #RGB forms; light when
perceived luminance > 0.5. Precedence: flag/config > OSC 11 > COLORFGBG >
dark. Skipped for TERM=dumb/linux, non-TTY stdin/stdout, and Windows
outside Windows Terminal. COLORFGBG now treats index 7 as light; the dead
TERM_PROGRAM branch (with its Ghostty casing bug) is gone.
… under screen

clip.exe decodes its input with the console code page, so accented, CJK
and emoji text arrived as mojibake on Windows and WSL. Feed it UTF-16LE
with a byte-order mark instead. On WSL without clip.exe on PATH, fall back
to PowerShell's Set-Clipboard reading UTF-8. Use termux-clipboard-set when
TERMUX_VERSION is set. Helper selection and the bytes written are now a
pure, tested function.

Under GNU screen (STY set, TERM=screen*, no TMUX) the OSC 52 sequence is
sent in short DCS chunks so screen forwards it to the outer terminal.
The file browser always enabled mouse capture, ignoring
[behavior] mouse_capture = false (it has no mouse actions, so capture only
took the terminal's own selection away). It now follows the same setting
as the reader. New --no-mouse flag forces capture off for the session in
both; the flag beats the config.
The ratatui-image probe waits up to ~2 s for terminals that never reply,
so every start on them stalled. Skip it (half-blocks) when stdout is not a
terminal, TERM is linux or dumb, or TERM_PROGRAM=Apple_Terminal. An
explicit --image-protocol kitty|iterm2|sixel still applies, with an
assumed cell size. Remove the catch_unwind around the probe: release
builds abort on panic, so it never caught anything.
ink doctor now has [environment] (WSL, SSH, multiplexers, terminal and
locale variables, UTF-8 locale, display presence), [colour] (depth and the
signal that decided it, whether colour is on and why), [theme] (resolved
theme and source, including the OSC 11 colour), [clipboard] (mode, native
helper, OSC 52 wrapping), [input] (mouse capture and why) and [config]
(path, existence, warnings), next to the existing graphics and decoder
sections. Under tmux it shows allow-passthrough. Nothing identifying is
printed: display and session variables are presence-only, SSH is yes/no,
and the home directory is replaced with ~. Piped output skips terminal
queries and says 'not a terminal'.
…r / NO_COLOR

Colour depth is now truecolour, 256 or ANSI 16. TERM=linux, xterm, vt100,
ansi, screen, cygwin (and any TERM without 256color and no other colour
signal) get the 16 ANSI colours, as named colours so the terminal's own
scheme applies; *-256color terminals keep exactly the old behaviour, and
tmux, a non-truecolor COLORTERM, Terminal.app or an unset TERM stay at
256. Pastel theme colours keep their hue instead of collapsing to grey.
Wired through the reader and --plain (30-37/90-97 SGR codes).

The reader used to ignore --color=never and NO_COLOR. It now draws with
the terminal's default colours and attributes only, with selections and
code-block hint labels in reverse video. The unused adapt() helper is
gone.
… readers

Box borders, bullets, task boxes, quote bars, heading markers, rules,
ellipses, image markers, popup borders, status-bar separators, the
progress bar and mermaid diagrams now come from one Glyphs set (Unicode or
ASCII), chosen once at startup: --ascii, [behavior] ascii = true|false, or
automatically for TERM=linux and non-UTF-8 locales (Unix). ASCII mode also
turns off smart punctuation and emoji shortcodes and names images instead
of drawing them in half-blocks, so an ASCII document prints as pure 7-bit
ASCII. ink stats/outline use the same set; ink doctor reports it. Default
(Unicode) output is byte-identical.
@borghei
borghei merged commit a868116 into main Oct 1, 2026
21 checks passed
@borghei
borghei deleted the feat/platform-terminal branch October 1, 2026 12:27
@borghei borghei mentioned this pull request Oct 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant