Skip to content

feat(tui): add Mode 2031 theme detection with tri-state appearance mode#15089

Open
kavhnr wants to merge 1 commit intoanomalyco:devfrom
kavhnr:feat/mode-2031-theme-detection
Open

feat(tui): add Mode 2031 theme detection with tri-state appearance mode#15089
kavhnr wants to merge 1 commit intoanomalyco:devfrom
kavhnr:feat/mode-2031-theme-detection

Conversation

@kavhnr
Copy link
Contributor

@kavhnr kavhnr commented Feb 25, 2026

mode-2031-theme-detection.mp4

Issue for this PR

Closes #13232

Supersedes #13233 (closed to rebase on current dev).

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

OpenTUI v0.1.78 added Mode 2031 dark/light theme detection (opentui#657). OpenCode is already on v0.1.79 (#13036) which includes these APIs, but doesn't use them. This PR integrates renderer.themeMode / renderer.on("theme_mode", ...) into OpenCode's theme system.

Three changes:

  1. Tri-state appearance mode (auto/dark/light) — replaces the binary toggle. auto follows OS via Mode 2031, falling back to OSC 11 luminance on unsupported terminals. dark/light are manual overrides.
  2. Per-mode theme config"theme": { "light": "github", "dark": "catppuccin" } alongside existing "theme": "opencode" (backward compatible).
  3. Appearance selector in the theme dialog — ←/→ arrow keys cycle modes, clickable, reverts on cancel.

Mode 2031 is the same approach used by Neovim and Helix. Event-driven, zero overhead. Unsupported terminals silently ignore the sequences — no degradation.

Why Mode 2031 over the approaches in existing open PRs:

Approach PR Problem
Poll terminal bg every 5s #7182, #7162 Wastes CPU, delayed detection, races with palette queries
execSync("defaults read") / gsettings every 3s #9719 Platform-specific, breaks in SSH/containers/tmux, spawns child processes
Mode 2031 (this PR) Terminal-native, event-driven, zero overhead

Edge cases handled:

  • Unsupported terminals: detectedMode stays at initial OSC 11 value. No degradation.
  • Custom themes without variants: activeThemeMode() falls back to "dark". Existing custom themes work identically.
  • Cancel in dialog: both theme and mode revert to initial values.
  • Event cleanup: onCleanup(() => renderer.off("theme_mode", ...)) prevents leaks.

How did you verify your code works?

  • bun run typecheck passes (16/16 packages, zero errors)
  • Tested on Ghostty (Mode 2031 supported): toggling macOS appearance instantly switches theme variants
  • Tested on Terminal.app (Mode 2031 unsupported): falls back to existing behavior, manual mode selector works, no errors
  • Backward compatible: "theme": "opencode" works, "theme": { "light": "github", "dark": "catppuccin" } works
  • All 31 dual-variant built-in themes resolve correctly in both modes
  • aura and ayu (single-palette) unaffected by mode changes

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@kavhnr kavhnr force-pushed the feat/mode-2031-theme-detection branch from 1c78a6c to daa9a8a Compare February 25, 2026 16:36
@kavhnr kavhnr marked this pull request as ready for review February 25, 2026 16:47
@kavhnr
Copy link
Contributor Author

kavhnr commented Feb 25, 2026

@RhysSullivan this is similar to your PR#7162 so might be up your ally to review/hopefully merge for people that use different modes.

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.

[FEATURE]: Add support for OpenTUI's new themeMode detection (Mode 2031)

1 participant