Skip to content

Terminal: resolve the ANSI palette per appearance - #20

Merged
wingleeio merged 1 commit into
zeronsh:mainfrom
neo773:fix/terminal-light-dark-mode
Aug 6, 2026
Merged

Terminal: resolve the ANSI palette per appearance#20
wingleeio merged 1 commit into
zeronsh:mainfrom
neo773:fix/terminal-light-dark-mode

Conversation

@neo773

@neo773 neo773 commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

The dynamic light/dark switch themed the terminal's chrome but not its grid. The panel read Theme, while the cells painted from two constants: a hardcoded #090909 background and a single ANSI table tuned by eye against it.

In light mode that renders a near-black rectangle inside a white app, and the "bright" half of the palette — the half most CLI output reaches for — comes out pale-on-pale.

What changed

crates/ui/src/terminal/view.rs. The background and the 16 named ANSI slots now resolve through Appearance:

  • Background#090909 dark, #fafafa light. The light step is larger than dark's 3/255 for the same reason Theme::light's surfaces are: a delta that reads as separation on near-black disappears on white.
  • ANSI 0–15 — a second table, same hue families walked down to the 600/700 steps, the way Theme::light already does for its accents. "Bright" keeps meaning more prominent, which on a light field is darker. A literal copy of the dark table would have made the bright half the invisible half.
  • The 6×6×6 cube (16–231) — deliberately left appearance-independent. A program asking for index 196 is asking for #ff0000 by arithmetic; remapping it would invent colors nobody picked. iTerm and Apple Terminal light themes do the same.
  • The grayscale ramp (232–255) — mirrored. Tools use it for de-emphasis rather than for a specific grey, and its bright end (where dim hint text lands) is the end that vanishes on white.

One real finding while writing the tests: light yellow at yellow-600 measures 2.81:1 on the light background and misses AA. It moved to amber-700 — the step Theme::light already picked for its own warning token, for the same reason.

Tests

Five new, in the same module:

  • a per-slot contrast floor against each palette's own background — the check that would have caught the original omission
  • bright-is-more-prominent, asserted in both directions
  • the grayscale ramp mirrors; the cube does not
  • the palette tables actually differ

Both contrast tests carry the black / bright-black pair as a documented exception rather than skipping it silently: those are structural greys, and the shipped dark tuning puts bright-black at 2.58:1.

comet-ui is 362/362 green, clippy and fmt clean. Verified by eye in the running app in both appearances and across a live switch.

SCR-20260806-bztm SCR-20260806-bzrz

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

…hrome

The dynamic light/dark switch landed with the terminal left out. Its panel
chrome read the theme, but the grid painted from two constants: a hardcoded
#090909 background and one ANSI table tuned by eye against it. In light mode
that gave a near-black rectangle inside a white app, and the "bright" half of
the palette — the half most CLI output uses — rendered pale-on-pale.

The background and the 16 named slots now resolve through Appearance. The
light table walks the same hue families down to the 600/700 steps, the way
Theme::light does for its accents, and keeps "bright" meaning *more
prominent* — which on a light field is darker, not lighter. Yellow needed
amber-700 rather than yellow-600: it is the one hue whose 600 step still
misses AA on white, and the theme's own warning token made the same move.

The 6x6x6 cube stays appearance-independent, because index 196 is a program
asking for #ff0000 by arithmetic and remapping it would invent colors nobody
picked. The 232-255 grayscale ramp does mirror: tools reach for it to
de-emphasize, and its bright end — where dim hint text lands — is exactly
what disappears on white.

Tests assert the contrast floor per slot on its own background, which is
what would have caught this originally, plus the bright-is-more-prominent
relation in both directions. Both carry the black/bright-black pair as a
documented exception: those are structural greys, and the shipped dark
tuning puts bright-black at 2.58:1.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@wingleeio wingleeio left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the diff and verified locally: single-file UI change (color tables + tests), no I/O/unsafe/dependency changes. Merged onto current main: 362/362 tests pass, fmt clean, zero clippy warnings in the changed file. Cube indices stay appearance-independent as described; grayscale mirror is exact. Safe to merge.

@wingleeio
wingleeio merged commit 9f41f60 into zeronsh:main Aug 6, 2026
1 check passed
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.

2 participants