Skip to content

feat(theme): adapt the painted backgrounds to a light terminal - #85

Merged
backnotprop merged 4 commits into
mainfrom
feat/light-terminal
Sep 21, 2026
Merged

backnotprop merged 4 commits into
mainfrom
feat/light-terminal

Conversation

@backnotprop

Copy link
Copy Markdown
Contributor

The colours half of #58, for the three absolute backgrounds alesch confirmed on Solarized Light. The keymap half and a user-facing [colors] table are still jadonwb's.

What was wrong

BLOCK_BG (236), TOOLBAR_BG (238) and CURSOR_BG (240) are painted under text whose colour belongs to the terminal. On a light terminal that is the terminal's dark foreground on a #303030 bar, so the focused block, the focused file-tree row, the help bar and the cursor cell all go nearly invisible. The .reversed() picker row and character selection have the same problem from the other direction: reversing dark-on-light gives a black bar that swallows the annotation tints under it. COMMENT_BG (58) and APPROVE_BG (22) turn out to be the same bug and are fixed with them.

Detection

src/theme.rs asks the terminal for its background colour once, before ratatui::init() takes the screen, and classifies light vs dark by comparing the perceived lightness of the background against the foreground. No reply, an unreadable reply, or no tty leaves the dark palette in place, which is exactly today's behaviour.

The query itself is terminal-colorsaurus, not hand-rolled. Per the dependency rule in AGENTS.md, the reason is correctness rather than convenience:

  • it opens its own tty handle instead of reading our stdin, so it can never race or corrupt the event loop's reader;
  • it sends DA1 behind the colour query, so a terminal that does not implement OSC 11 is recognised at round-trip speed instead of sitting on the timeout;
  • it carries the terminal quirk list (BEL vs ST terminators, terminals that must not be asked at all) that a forty-line version would get wrong;
  • it costs three small crates from one author — terminal-colorsaurus, terminal-trx, xterm-color — on top of libc/windows-sys, which are already in the tree.

One honest caveat, documented at detect() and in the README: the query holds the tty in raw mode for one round trip, and a key pressed into that window is read and discarded with the reply. Nothing pushes those bytes back — TIOCSTI needs unsafe, which this workspace forbids, and is disabled on current Linux anyway. Setting the theme outright skips the query and the window with it. The timeout is 100 ms, and only a pty with no emulator behind it ever reaches it.

Precedence

PLANNOTATOR_TUI_THEME → [ui] theme in config.toml → the terminal → dark.

[ui]
theme = "auto"   # auto (default) | light | dark

auto in the environment overrides a configured light/dark back to asking. An unreadable value is an error naming it, like a bad placement. plannotator-tui config prints whichever value is in effect, so the environment override is visible there.

What changed for whom

Dark terminals: nothing. the_dark_palette_is_unchanged pins all seven roles to their shipped values, and no palette is installed in tests, --snapshot, --export, --bench or any other non-TTY run, so every existing style assertion and snapshot still reads the dark one.

Light terminals get block_bg 254, toolbar_bg 252, comment_bg 229, approve_bg 194, a cursor that sets its own white foreground over 238 so the glyph under it stays legible, a DarkGray idle button foreground instead of Gray, and a selection that is a real background (153) rather than REVERSED. Checked against Solarized Light (#fdf6e3/#657b83) and plain white.

Validation

cargo fmt --all --check, cargo clippy --workspace --all-targets -- -D warnings and cargo test --workspace (183 tests) are clean.

Driven end to end through a pty harness standing in for the terminal: a harness answering rgb:fdfd/f6f6/e3e3 produces 48;5;254/48;5;252 on screen, one answering rgb:0000/0000/0000 produces 48;5;236/48;5;238, and one answering nothing also produces 236/238. The app starts and quits on q in all three.

Left out deliberately: a user-facing [colors] table, keymaps, and any theming of styles that already set both a foreground and a background (the Send/Sent/Blocked buttons, the delete strikethrough), which read the same either way.

backnotprop and others added 4 commits September 21, 2026 13:34
The three indexed backgrounds - the focused block and tree row, the help
bar, the keyboard cursor - and the reversed selection were absolute, so a
light terminal drew its own dark text on them and lost it. Collect every
background we paint ourselves into one palette with a light variant, ask
the terminal for its background colour once before the screen is taken,
and let [ui] theme or PLANNOTATOR_TUI_THEME settle it outright. The dark
palette is the shipped one, value for value.

refs #58
The environment overriding the config file is what `plannotator-tui
config` has to print, and only the real binary reads both.

refs #58
…config

Herdr answers the colour query for its panes but never the DA1 probe, so the
query always ran to the deadline there; 30 ms is plenty for the answer and
shrinks the window in which a keystroke can be lost. The light comment and
approve tints were near-invisible against a light page. A config that fails to
parse no longer stops the plain TUI from starting, as it never did before.

refs #58
@backnotprop
backnotprop added this pull request to the merge queue Sep 21, 2026
Merged via the queue into main with commit bcac64e Sep 21, 2026
2 checks passed
@backnotprop
backnotprop deleted the feat/light-terminal branch September 21, 2026 20:50
This was referenced Sep 21, 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