Skip to content

fix: improve text contrast on light terminal backgrounds#712

Closed
altimate-harness-bot[bot] wants to merge 6 commits intomainfrom
fix/light-terminal-text-contrast
Closed

fix: improve text contrast on light terminal backgrounds#712
altimate-harness-bot[bot] wants to merge 6 commits intomainfrom
fix/light-terminal-text-contrast

Conversation

@altimate-harness-bot
Copy link
Copy Markdown

@altimate-harness-bot altimate-harness-bot bot commented Apr 16, 2026

Summary

Fixes #704 (follow-up to #617). Code output was rendering as white/light text on light terminal backgrounds, making it unreadable.

Three fixes:

  • COLORFGBG env var fallback (app.tsx): When OSC 11 terminal background detection times out (common in many terminal setups), fall back to checking the COLORFGBG environment variable before defaulting to "dark" mode. Many terminals (iTerm2, xterm, etc.) set this to indicate their color scheme.

  • Light-mode foreground fallback (theme.tsx): When defaultForeground is unavailable and mode is "light", use #1a1a1a (near-black) instead of ANSI palette index 7 (#c0c0c0 — light gray), which is invisible on white backgrounds.

  • Inline code background (theme.tsx): Use backgroundElement instead of background for markup.raw.inline scope. background can be transparent (especially in the system theme), leaving inline code with no contrast protection. This is consistent with the Asking the model to do a suggestion for rewrite of code during review returns white lines of code while terminal background is white #617 fix already applied to markup.raw.block.

Test plan

  • Run CLI on a light-background terminal (e.g. Terminal.app with default white theme)
  • Verify code suggestions and rewrites are readable
  • Verify inline code blocks have visible background contrast
  • Test on a terminal that sets COLORFGBG env var
  • Test on a terminal that responds to OSC 11 (should still work as before)
  • Verify dark terminal themes are unaffected

Requested by @saravmajestic via harness


Summary by cubic

Fixes unreadable code on light terminal backgrounds with better detection and safer color fallbacks. Also removes the 1s startup delay on terminals without OSC 11; inline code now always has a solid background. Closes #704.

  • Bug Fixes
    • Use COLORFGBG via detectModeFromCOLORFGBG (util/terminal-detection.ts); only bg 7/15 count as light; reject invalid values; run this check before OSC 11 to avoid delays.
    • In light mode, fallback foreground uses palette[0] or #1a1a1a instead of palette[7]; dark mode unchanged.
    • Inline code (markup.raw.inline) now uses backgroundElement to ensure contrast on transparent themes.
    • Tests updated to import the real helper, add edge cases, and cover contrast and cross-mode regressions.

Written for commit 8f747a1. Summary will update on new commits.

@github-actions
Copy link
Copy Markdown

This PR doesn't fully meet our contributing guidelines and PR template.

What needs to be fixed:

  • PR description is missing required template sections. Please use the PR template.

Please edit this PR description to address the above within 2 hours, or it will be automatically closed.

If you believe this was flagged incorrectly, please let a maintainer know.

saravmajestic added 2 commits April 16, 2026 07:39
- Add COLORFGBG env var fallback when OSC 11 detection times out
- Use dark foreground (#1a1a1a) instead of palette[7] (#c0c0c0) for light mode system theme
- Use backgroundElement for inline code blocks to ensure contrast on transparent backgrounds

Closes #704
- Test markup.raw.inline uses backgroundElement (non-transparent)
- Test system theme light-mode foreground fallback contrast
- Test COLORFGBG env var parsing logic
- Update test helper to match production inline code background change
@altimate-harness-bot altimate-harness-bot bot force-pushed the fix/light-terminal-text-contrast branch from 72d8b51 to d3a4dac Compare April 16, 2026 07:40
saravmajestic added 2 commits April 16, 2026 07:43
Adds tests that reproduce the exact bugs:
- BUG test: proves palette[7] (#c0c0c0) has ~1.3:1 contrast on white (invisible)
- BUG test: proves old inline code bg was transparent (no contrast)
- FIX test: verifies new fg (#1a1a1a) has >=3:1 contrast on white
- FIX test: verifies inline code bg is now opaque
- FIX test: verifies dark mode is unaffected (still uses palette[7])
@saravmajestic saravmajestic marked this pull request as ready for review April 16, 2026 08:33
Copy link
Copy Markdown

@claude claude bot left a comment

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 4 files

saravmajestic and others added 2 commits April 16, 2026 09:14
…tion

Addresses the multi-model consensus code review on PR #712.

**COLORFGBG detection**:
- Extract `detectModeFromCOLORFGBG` into a pure TypeScript helper at
  `packages/opencode/src/cli/cmd/tui/util/terminal-detection.ts` so tests
  exercise the real production code (was previously inlined in `app.tsx`
  with test duplicates that couldn't catch regressions).
- Narrow the light-mode threshold from `bg >= 8` to `bg === 7 || bg === 15`.
  The old `>= 8` misclassified bright red (9), blue (12), magenta (13) as
  "light" even though they have low luminance; it also missed index 7
  (light gray), which is a common light-terminal background.
- Reject out-of-range (< 0, > 15), non-numeric ("default"), and empty values
  explicitly rather than silently defaulting to dark.
- Tolerate surrounding whitespace.
- Use `parseInt(..., 10)` with an explicit radix.
- Check `COLORFGBG` eagerly in `getTerminalBackgroundColor()` before
  issuing the OSC 11 query. Light terminals that don't support OSC 11
  (common with urxvt, gnome-terminal) no longer pay the 1-second timeout
  on every launch.

**System-theme light-mode foreground fallback**:
- `generateSystem` now falls back to `colors.palette[0] ?? "#1a1a1a"` in
  light mode (dark mode keeps `colors.palette[7]`). Respects the user's
  palette when provided; still guarantees a readable near-black on white
  when the palette is empty.

**Tests**:
- Rewrite `theme-light-mode-704.test.ts` to import the real
  `detectModeFromCOLORFGBG` — reverting the production helper now fails
  the 18 COLORFGBG tests.
- Add coverage for: `0;7` (light-gray bg, now light), `15;8` (dark-gray
  bg, now dark), `0;9`/`0;12`/`0;13` (bright-red/blue/magenta, now dark),
  `default;default` (Alacritty/Kitty), out-of-range values, negatives,
  empty string, whitespace tolerance, undefined.
- Add a light-mode regression test confirming fallback prefers
  `palette[0]` over `#1a1a1a` when present.
- Add `defaultForeground`-is-honored regression.
- Add dark-mode `markup.raw.inline` regression test in
  `theme-light-mode.test.ts` to cover the cross-mode impact of the
  `backgroundElement` change.
- Consolidate duplicate `COLORFGBG` tests (previously in both files).

Closes #704 (follow-up to #712/#617).
@github-actions
Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@anandgupta42
Copy link
Copy Markdown
Contributor

Ran multi-model consensus review (9 participants: Claude + GPT 5.4, Gemini 3.1 Pro, Kimi K2.5, DeepSeek V3.2, MiniMax M2.7, GLM-5, MiMo-V2-Pro, Qwen 3.5 Plus). One convergence round. Summary below, followed by the fixes just pushed (commit 8f747a1).


Review findings

Major blocker (unanimous): Tests duplicated production logic (generateSystem, getSyntaxRules, the COLORFGBG parser). Reverting the production fix left all 55 tests green — living documentation of the bug, not regression protection.

Minor — COLORFGBG threshold: bg >= 8 was semantically wrong at the palette boundary.

  • Index 7 (#c0c0c0, light-gray) is a light bg but 7 >= 8 is false → classified dark.
  • Index 8 (#808080, dark-gray) is dark but 8 >= 8 is true → classified light.
  • Naive fix (bg === 7 || bg >= 9) would mis-classify indices 9/12/13 (bright red/blue/magenta, luminance 28-76/255 = dark).

Minor — #1a1a1a foreground fallback: Hardcoded, ignored the user palette. Dark mode respects colors.palette[7]; light mode should at least consider colors.palette[0].

Minor — 1000ms startup delay: COLORFGBG was only consulted after the OSC 11 timeout. Terminals without OSC 11 (urxvt, older gnome-terminal) paid 1s on every launch.

Minor — Missing dark-mode regression for markup.raw.inline: The backgroundElement change affects both modes; only light-mode tests existed.


Fixes applied in commit 8f747a1

packages/opencode/src/cli/cmd/tui/util/terminal-detection.ts (new)

  • Extracted detectModeFromCOLORFGBG as a pure-TypeScript helper. Tests now import the real function; reverting it fails the 18 COLORFGBG tests.
  • Narrowed threshold to bg === 7 || bg === 15 (conservative: only canonically light indices).
  • Rejects out-of-range (< 0, > 15), non-numeric (default), and empty values explicitly.
  • Tolerates surrounding whitespace; parseInt(..., 10) with explicit radix.

packages/opencode/src/cli/cmd/tui/app.tsx

  • Imports the new helper.
  • Checks COLORFGBG eagerly before the OSC 11 query — light terminals without OSC 11 support skip the 1s timeout.

packages/opencode/src/cli/cmd/tui/context/theme.tsx

  • Light-mode foreground fallback: colors.palette[0] ?? "#1a1a1a". Respects the user palette when present; keeps #1a1a1a as a safety net for empty-palette edge cases.

packages/opencode/test/cli/tui/theme-light-mode-704.test.ts

  • Imports real detectModeFromCOLORFGBG.
  • Added coverage: 0;7 (light-gray bg → light), 15;8 (dark-gray bg → dark), 0;9/0;12/0;13 (bright colors → dark), default;default, out-of-range, negatives, empty, whitespace, undefined.
  • Added regression: fallback prefers palette[0] when present; defaultForeground always honored.

packages/opencode/test/cli/tui/theme-light-mode.test.ts

  • Added dark-mode markup.raw.inline regression test.
  • Removed duplicate COLORFGBG tests (consolidated in the 704 file).

Full test suite: 59 pass, 0 fail. altimate_change markers validated. TypeScript clean.


Test architecture note: the theme-level tests still use local helpers because theme.tsx can't be imported from bun:test (the @opentui/solid JSX runtime types don't resolve in the test loader). Leaving that extraction as a follow-up — the highest-value test architectural fix was the COLORFGBG helper, which was where the actual semantic bug lived. The system-theme tests reproduce only the specific fgFallback expression under test, not the full generateSystem, so the duplication surface is much smaller.

@github-actions
Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@anandgupta42 anandgupta42 reopened this Apr 17, 2026
@github-actions
Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@github-actions github-actions bot closed this Apr 17, 2026
@anandgupta42 anandgupta42 reopened this Apr 17, 2026
@github-actions
Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@github-actions github-actions bot closed this Apr 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Code output still renders as white text on light terminal backgrounds (follow-up to #617)

2 participants