Skip to content

feat(desktop): add configurable terminal font picker - #70925

Closed
Zeraphim wants to merge 6 commits into
NousResearch:mainfrom
Zeraphim:feat/terminal-font-family
Closed

feat(desktop): add configurable terminal font picker#70925
Zeraphim wants to merge 6 commits into
NousResearch:mainfrom
Zeraphim:feat/terminal-font-family

Conversation

@Zeraphim

@Zeraphim Zeraphim commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds a profile-scoped terminal font picker to Settings → Appearance so Desktop users can select an installed Nerd Font such as MesloLGS NF without editing CSS.

The value is stored as terminal.font_family in config.yaml. A friendly single family name or custom CSS font stack is accepted, and Hermes always appends the bundled JetBrains Mono stack as a safe fallback. Both interactive terminals and read-only agent terminals warm regular/bold/italic faces before WebGL mounts; live changes refit, clear the glyph atlas, and redraw without recreating the PTY.

This salvages #49592: @baoyu0's original config commit remains in the branch with its authorship intact, while the integration is adapted to the current persistent terminal workspace.

Related Issue

Partially addresses #64790 and #37566 (terminal font family only; the broader typography requests remain open).

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)

Changes Made

  • Add terminal.font_family to the public config defaults, Desktop type, example config, and docs.
  • Add an editable Appearance combobox with curated Nerd Font suggestions, arbitrary CSS-stack input, live Powerlevel10k glyph preview, reset, debounced profile-aware autosave, and rollback.
  • Centralize font normalization, fallback resolution, face warming, stale-request cancellation, and live xterm repainting.
  • Apply the shared font path to interactive and agent terminals without restarting persistent shells.
  • Add behavior coverage for late/stale config, live repaint/refit/atlas refresh, custom/reset/rollback/profile switching, and the config API round trip.
  • Update all Desktop locales.

How to Test

  1. Install MesloLGS NF (or another Nerd Font) locally.
  2. Open Settings → Appearance → Terminal Font, select or enter MesloLGS NF, and confirm the glyph preview renders separators/icons.
  3. Open an interactive terminal with Powerlevel10k and confirm prompt glyphs render. Change the setting while the shell is open and confirm the terminal redraws without losing cwd or shell state.
  4. Open an agent terminal and confirm it uses the same family.

Automated validation run:

  • npm run typecheck
  • npm run lint (no errors; existing repository warnings only)
  • npm run test:ui — 247 files, 2,093 passed, 1 existing skip
  • npm run build
  • scripts/run_tests.sh tests/hermes_cli/test_web_server.py -k TestConfigRoundTrip -q
  • Focused terminal/settings tests — 19 passed

Checklist

Code

Documentation & Housekeeping

  • I've updated relevant documentation
  • I've updated cli-config.yaml.example
  • Architecture/workflow docs: N/A
  • I've considered Windows/macOS impact; the code uses browser font APIs and CSS family names with no platform-specific path handling
  • Tool descriptions/schemas: N/A

Screenshots / Logs

On the test Mac, fc-match "MesloLGS NF" resolves MesloLGS NF Regular.ttf. The draft is ready for a maintainer/contributor to exercise against a live Powerlevel10k prompt.

image image

baoyu0 and others added 2 commits July 25, 2026 02:00
…amily in config.yaml)

Adds a new config option terminal.font_family that lets users customize the
CSS font-family for the desktop app's embedded xterm.js terminal.

Previously the font was hardcoded in use-terminal-session.ts:
  'JetBrains Mono', 'Cascadia Code', 'SF Mono', Menlo, Consolas, monospace

Now the value from config.yaml (terminal.font_family) is threaded through:
  useHermesConfig → PersistentTerminal → TerminalTab → useTerminalSession

When font_family is empty or unset (default), the built-in fallback is used,
preserving backward compatibility. Users with Nerd Fonts installed (e.g.
CaskaydiaCoveNerdFont) can now set:

  terminal:
    font_family: 'CaskaydiaCoveNerdFont', 'JetBrains Mono', monospace

Closes: #terminal-font-config
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/desktop Electron desktop app (apps/desktop/*) comp/cli CLI entry point, hermes_cli/, setup wizard area/config Config system, migrations, profiles sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Jul 24, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related: #49592 (salvaged configuration foundation), plus #44564, #64790, and #37566 (adjacent Desktop typography work). This PR has a broader current integration: profile-aware config persistence, live interactive and agent-terminal updates, font warming, and focused coverage; it is not a duplicate.

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for preserving the original configuration work and covering both terminal surfaces. The premise is still valid: current main hardcodes the interactive terminal font at apps/desktop/src/app/right-sidebar/terminal/use-terminal-session.ts:509 and the agent-terminal font at apps/desktop/src/app/right-sidebar/terminal/use-agent-terminal.ts:48.

Problems

  • apps/desktop/src/app/right-sidebar/terminal/use-agent-terminal.ts:14 and :18 import resolveSurfaceColor and terminalTheme twice. This creates duplicate imported bindings.
  • apps/desktop/src/app/right-sidebar/terminal/use-agent-terminal.ts:47 makes observer nullable, while cleanup at :160 calls observer.disconnect() unconditionally. Font preparation is asynchronous (:140-150), so unmounting before mount leaves observer null and throws in cleanup.

Suggested changes

  • Consolidate the two ./selection imports.
  • Keep observer cleanup null-safe and add a pending-font-preparation unmount test.

This is an automated hermes-sweeper review.

Comment thread apps/desktop/src/app/right-sidebar/terminal/use-agent-terminal.ts Outdated
Comment thread apps/desktop/src/app/right-sidebar/terminal/use-agent-terminal.ts
@teknium1 teknium1 added the sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform label Jul 30, 2026
Zeraphim added 2 commits July 30, 2026 20:05
…mily

- Resolved config_defaults.py extraction: accepted main's import in config.py,
  added font_family default to config_defaults.py
- Resolved test_web_server.py: kept PR's four config round-trip tests
- Resolved configuration.md: PR's font_family paragraph + main's cloud sandboxes
- Fixed duplicate import and observer null-safety in use-agent-terminal.ts
  (reviewer-flagged code issues)
@Zeraphim

Copy link
Copy Markdown
Contributor Author

Hi @teknium1, addressed on the latest head 0f128a0:

  • Consolidated the ./selection imports.
  • Kept cleanup null-safe with observer?.disconnect().
  • Added a regression test that unmounts while font preparation is pending and verifies there is no cleanup exception, late terminal mount, observer creation, or stream registration.

Focused tests, Desktop typecheck, ESLint, and Prettier checks all pass.

@teknium1

teknium1 commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Merged via #76395 — your commits (and the original #49592 base by @baoyu0) were cherry-picked onto current main with authorship preserved (rebase merge). One follow-up commit of ours reworked the settings component to comply with the ref-mirroring lint rule that landed after your PR was authored. Thanks for the thorough end-to-end work — locales, docs, and round-trip tests included.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/config Config system, migrations, profiles comp/cli CLI entry point, hermes_cli/, setup wizard comp/desktop Electron desktop app (apps/desktop/*) P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants