Skip to content

feat(theme): add a default terminal theme that follows terminal colors - #1128

Merged
benvinegar merged 2 commits into
modem-dev:mainfrom
dhh:terminal-theme
Sep 28, 2026
Merged

benvinegar merged 2 commits into
modem-dev:mainfrom
dhh:terminal-theme

Conversation

@dhh

@dhh dhh commented Sep 27, 2026

Copy link
Copy Markdown
Contributor

Problem

Every built-in theme paints Hunk with a fixed editor color scheme, so Hunk never matches the terminal it runs in. On setups where the terminal theme changes (Omarchy theme switching, light/dark toggles, herdr/tmux theme sync) Hunk also can't follow along without a restart.

What this does

New terminal theme, now the default. At startup Hunk queries the terminal's foreground, background, and 16-color ANSI palette (OSC 10/11/4) and derives the whole theme from them:

  • diff rows: green additions, red removals, blue accent, with tints blended against the real background and the existing contrast rescue rules applied
  • syntax: keywords magenta, strings green, functions blue, types yellow, constants cyan, comments bright black, everything else the terminal foreground
  • the syntax scopes replace the base Shiki theme's rules (new syntaxScopesReplaceBase) so no bundled editor palette leaks through
  • terminals that don't answer get a stand-in xterm light/dark palette

The probe ends with a DA1 query as a sentinel, so responsive terminals finish immediately instead of waiting out the timeout. auto keeps meaning GitHub light/dark, explicit themes are unchanged, and terminal is reserved from custom-theme ids.

Live refresh. HunkSessionHost runs a watcher that re-probes through OpenTUI's renderer-owned getPalette() and republishes through ThemeController when the colors changed:

  • on mode 2031 color-scheme notifications (CSI ? 997 ; n n), which OpenTUI already opts into and Ghostty/kitty/herdr send; the handler leaves the sequence for OpenTUI's own light/dark tracking
  • on SIGWINCH, which tmux-aware theme tools send after rewriting pane colors (OpenTUI skips its resize path when the size is unchanged)
  • once after mount when startup never probed (explicit-theme launches), so switching to terminal later shows the real palette

OpenTUI only clears its palette cache on a light↔dark flip, so the watcher clears it before each probe to catch dark→dark switches. Probes are debounced, and only changed reports repaint.

Tradeoffs

  • Themes with syntax scope overrides are highlighted inline rather than on the worker (existing documentWorkerEligibility rule), which now applies to the default theme on very large diffs.
  • SIGWINCH also fires on ordinary resizes; those cost one palette query and repaint nothing.

Verification

  • bun run typecheck, lint, format:check, deps:check, check:docs
  • bun run test: passes except Jujutsu source reading > logs unexpected source failures…, which fails identically on main locally
  • bun run test:integration: passes. PTY tests that assert exact GitHub hex colors now pin --theme github-dark-default; tests that assert the default id or selector order now expect terminal.
  • New unit coverage: OSC 4/10/11 parsing and the DA1-terminated probe, terminal theme derivation and fallback, controller color updates, the watcher's triggers/debounce/disposal, and selector repaint (including a terminal preview across a dark→dark switch).
  • End-to-end in a PTY against a scripted terminal that answers color queries: Hunk enables mode 2031, renders palette A, and after the palette changes and a 997 notification arrives, repaints entirely in palette B.

Not yet verified by hand in a real terminal session across an actual theme switch.

🤖 Generated with Claude Code

Probe the terminal's foreground, background, and 16-color ANSI palette at
startup and derive a `terminal` theme from them for diffs, chrome, and syntax
highlighting. Make it the default theme.

Keep following the terminal while Hunk runs: re-probe on mode 2031
color-scheme notifications (Ghostty, kitty, herdr) and on SIGWINCH (what
tmux-aware theme tools send after rewriting pane colors), and repaint when
the palette changed. Sessions launched with an explicit theme probe once
after startup so switching to `terminal` shows the real palette.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Sep 27, 2026

Copy link
Copy Markdown
Contributor

PR author is not in the allowed authors list.

@vercel

vercel Bot commented Sep 27, 2026

Copy link
Copy Markdown

@dhh is attempting to deploy a commit to the Modem Team on Vercel.

A member of the Team first needs to authorize it.

benvinegar
benvinegar previously approved these changes Sep 28, 2026

@benvinegar benvinegar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Reviewed the startup OSC probe, terminal palette derivation and fallback, OpenTUI watcher lifecycle, controller/selector repaint path, syntax-theme replacement, docs, and compatibility updates. I did not find a blocking correctness issue.

Validation: bun run test, bun run typecheck, bun run lint, bun run deps:check, bun run check:docs, and the changed-file format check pass. bun run test:integration had one unrelated watch-start process-cleanup failure; that test passed immediately when rerun alone.

Non-blocking: the scripted palette-switch PTY scenario described in the PR body would be valuable as a checked-in regression test; the current watcher coverage mocks the renderer boundary.

This comment was generated by Pi using gpt-5.6-sol

@benvinegar
benvinegar dismissed their stale review September 28, 2026 00:19

Posted in error; no review was requested to be submitted.

@benvinegar
benvinegar merged commit 6c95708 into modem-dev:main Sep 28, 2026
13 of 15 checks passed
@benvinegar

Copy link
Copy Markdown
Member

Thanks! I tried this on my desktop Omarchy (by switching through some themes) and it looked pretty nice

As a follow-up I'd love to have hunk detect the theme switch somehow (vs having to restart today)

@dhh
dhh deleted the terminal-theme branch September 28, 2026 08:20
@dhh

dhh commented Sep 28, 2026

Copy link
Copy Markdown
Contributor Author

It'll do the update in Omarchy when it gets SIGWINCH. We'll get that setup on our side.

@dhh

dhh commented Sep 28, 2026

Copy link
Copy Markdown
Contributor Author

Follow-up on the Omarchy side: omacom/omarchy#13518 adds omarchy-theme-set-hunk, which sends SIGWINCH to running hunk processes when the Omarchy theme changes, so the terminal theme repaints even in terminals that don't send a mode 2031 color-scheme notification when their palette is reloaded.

🤖 Generated with Claude Code

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