Skip to content

feat: add dynamic theme changes#144

Open
brianegan wants to merge 1 commit into
coder:mainfrom
brianegan:feat/dynamic-theme-changes
Open

feat: add dynamic theme changes#144
brianegan wants to merge 1 commit into
coder:mainfrom
brianegan:feat/dynamic-theme-changes

Conversation

@brianegan
Copy link
Copy Markdown

Summary

  • Add ghostty_terminal_set_colors WASM export that updates terminal colors at runtime and forces a full redraw
  • Wire up terminal.options.theme = newTheme to merge partial themes, update the renderer, and sync WASM terminal colors
  • Existing content re-renders instantly — cells with ANSI palette/default colors pick up the new theme; explicit RGB cells remain unchanged
  • Support partial theme updates that accumulate (e.g. setting only background preserves all other colors)

Usage

// Full theme swap
terminal.options.theme = { background: '#000', foreground: '#fff', red: '#ff0000' };

// Partial update — only changes background, keeps everything else
terminal.options.theme = { background: '#1a1a2e' };

// Reset to defaults
terminal.options.theme = {};

Changes

File Change
patches/ghostty-wasm-api.patch New setColors() Zig function, force_full_redraw flag on TerminalWrapper, render state reset on color change
ghostty-vt.wasm Rebuilt with ghostty_terminal_set_colors export
lib/types.ts Added ghostty_terminal_set_colors to WASM exports interface
lib/ghostty.ts Added setColors() method to GhosttyTerminal class
lib/terminal.ts handleOptionChange('theme') now merges, updates renderer + WASM; added currentTheme accumulator and buildThemeColorsConfig() helper
lib/terminal.test.ts 12 new tests covering full/partial/reset/accumulation/ANSI re-resolution/RGB unchanged/redraw trigger

Test plan

  • Full theme change updates renderer and WASM colors
  • Partial theme updates preserve previous customizations
  • Successive partial updates accumulate correctly
  • Reset to null/undefined/{} restores defaults
  • Theme set before open() is applied correctly
  • ANSI palette color cells re-resolve after theme change
  • Explicit RGB color cells remain unchanged
  • Theme change triggers full redraw (needsFullRedraw() returns true)
  • Invalid color values do not crash
  • Default fg/bg cells update after theme change
  • bun run typecheck && bun test pass (343 tests, 0 failures)

🤖 Generated with Claude Code

Enable runtime theme changes via `terminal.options.theme = newTheme`
without restarting the terminal. All existing content re-renders
instantly with the new colors.

- Add `ghostty_terminal_set_colors` WASM export that updates terminal
  colors and forces a full redraw
- Wire up `handleOptionChange('theme')` to merge partial themes,
  update the renderer, and sync WASM terminal colors
- Support partial theme updates that accumulate (e.g. setting only
  background preserves all other colors)
- Cells with ANSI palette/default colors re-resolve; explicit RGB
  cells remain unchanged

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@brianegan
Copy link
Copy Markdown
Author

Resolves #125

diegosouzapw added a commit to diegosouzapw/ghostty-web that referenced this pull request May 23, 2026
…heme

Today, the theme passed to the Terminal constructor is captured at open()
time and never changes. Apps that need to switch themes at runtime (light/
dark toggle, accessibility preference change, multi-window state) had to
dispose the Terminal and recreate it — which destroys scrollback,
selection, and focus.

This commit adds a runtime theme change path:

- Public API: `Terminal.setTheme(theme)` updates the theme atomically and
  triggers a single render. Equivalent to assigning `options.theme = ...`
  via the existing options Proxy (also supported).
- WASM bridge: new exports `terminal_set_theme` (full theme update) and
  the renderer is invalidated so the next frame redraws every cell with
  the new palette / background.
- The renderer's color cache (introduced in older PRs) is cleared on
  theme change so old `rgb(...)` strings don't outlive their palette.

Adds 12 new tests covering: full-theme update mid-session, ANSI palette
update, default-color fallback when theme omits ansi colors, no-op on
identical theme, render scheduling, options-proxy compatibility.

Excludes the binary `ghostty-vt.wasm` from the upstream diff (CI / local
`bun run build:wasm` rebuilds it from the updated patch).

Co-authored-by: Brian Egan <brian.egan@verygood.ventures>
Inspired-by: coder#144
diegosouzapw added a commit to diegosouzapw/ghostty-web that referenced this pull request May 23, 2026
…heme

Today, the theme passed to the Terminal constructor is captured at open()
time and never changes. Apps that need to switch themes at runtime (light/
dark toggle, accessibility preference change, multi-window state) had to
dispose the Terminal and recreate it — which destroys scrollback,
selection, and focus.

This commit adds a runtime theme change path:

- Public API: `Terminal.setTheme(theme)` updates the theme atomically and
  triggers a single render. Equivalent to assigning `options.theme = ...`
  via the existing options Proxy (also supported).
- WASM bridge: new exports `terminal_set_theme` (full theme update) and
  the renderer is invalidated so the next frame redraws every cell with
  the new palette / background.
- The renderer's color cache (introduced in older PRs) is cleared on
  theme change so old `rgb(...)` strings don't outlive their palette.

Adds 12 new tests covering: full-theme update mid-session, ANSI palette
update, default-color fallback when theme omits ansi colors, no-op on
identical theme, render scheduling, options-proxy compatibility.

Excludes the binary `ghostty-vt.wasm` from the upstream diff (CI / local
`bun run build:wasm` rebuilds it from the updated patch).

Co-authored-by: Brian Egan <brian.egan@verygood.ventures>
Inspired-by: coder#144
diegosouzapw added a commit to diegosouzapw/ghostty-web that referenced this pull request May 23, 2026
…heme (#14)

Today, the theme passed to the Terminal constructor is captured at open()
time and never changes. Apps that need to switch themes at runtime (light/
dark toggle, accessibility preference change, multi-window state) had to
dispose the Terminal and recreate it — which destroys scrollback,
selection, and focus.

This commit adds a runtime theme change path:

- Public API: `Terminal.setTheme(theme)` updates the theme atomically and
  triggers a single render. Equivalent to assigning `options.theme = ...`
  via the existing options Proxy (also supported).
- WASM bridge: new exports `terminal_set_theme` (full theme update) and
  the renderer is invalidated so the next frame redraws every cell with
  the new palette / background.
- The renderer's color cache (introduced in older PRs) is cleared on
  theme change so old `rgb(...)` strings don't outlive their palette.

Adds 12 new tests covering: full-theme update mid-session, ANSI palette
update, default-color fallback when theme omits ansi colors, no-op on
identical theme, render scheduling, options-proxy compatibility.

Excludes the binary `ghostty-vt.wasm` from the upstream diff (CI / local
`bun run build:wasm` rebuilds it from the updated patch).


Inspired-by: coder#144

Co-authored-by: Brian Egan <brian.egan@verygood.ventures>
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