cmux-next: Change Font… with live preview, fonts in their own face, recent fonts first
Makes switching fonts in cmux NEXT quick, using the font settings that already exist. The one addition is a list of recently used fonts.
What changes
- Settings > Appearance font rows (terminal, chat code, editor, Markdown code) open a searchable list of the installed fonts. Each name is drawn in its own font. Arrow keys preview the highlighted font live in the app, and so does the pointer after it rests for 450 ms. Return or a click keeps the font, and Escape reverts. This is the theme picker's behavior, in the new
FontPicker. - Recent fonts. Fonts used lately come first under a Recent tag, so switching back and forth is one step.
RecentFontskeeps the six most recent in user defaults (client view state, never cmux-next.json). Every font write throughsetSettingrecords one, and the page reads them as therecent_fontsdomain. - Palette. Font settings now list the installed fonts. Before, you had to type a name. Each font is drawn in its own face, recent fonts come first, and the settings value page's live preview and Escape revert apply. Change Font… lists every font setting: font names, sizes, line heights, and the chat's and Markdown viewer's font. That list comes from the schema (a font family row, or a key that names "font"), so a new font setting shows up without edits here.
- A What's New highlight, and the gallery entry
font-picker-open.
Size and line height stay where they are, next to each font row. The terminal has no line-height key; that would need a Ghostty adjust-cell-height setting, which I left out.
Supersedes most of #20985 (orphaned, conflicting). Base has since added the chat look (agentPane.display.font.*, chatDisplay.ts), which duplicates its appearance.fonts.* keys.
Changelog
- Added: Change Font… in the command palette, and font lists in Settings that draw each font in its own face, preview live and put recent fonts first.
Testing
bun test src/pages/settings/fontPicker.test.tsx: 7 pass (row order, recent tag, own face, arrows preview, Escape reverts with no write, Return writes and moves the font to the front).bun test src/pages/settings: 218 pass, 1 skip.bun run check(webviews): clean.prepush-gate.py: no new violations.check-l10n.sh: 0 errors.lint-ios-package-conventions.sh: OK.- New Swift tests:
RecentFontsTests,PaletteChangeFontTests,SettingsPaletteFontOptionsTests.
Observed / Not run
- Observed: the web tests and checks above, run locally.
- Not run: Swift build and tests (no Mac compiles on this machine; CI runs them). No live dogfood of the palette rows in their own face.
test/galleryhas one red,ChatHeaderStatus.tsx#ChatHeaderInlineStatuswith no gallery entry, which comes from base, not this PR.
Localization: 3 new keys (settingsPage.font.recent, settingsPage.font.noMatch, palette.setting.changeFont), all 21 locales filled.
Agent session: cosmic-gray
🤖 Generated with Claude Code
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Makes font switching in cmux NEXT a one-step pick: Settings font rows and the palette list installed fonts, each drawn in its own face, with live preview and fonts used lately first.
- Settings > Appearance font rows and palette font family settings list installed fonts (the palette previously took typed names only); the highlighted font previews live, Return or a click writes, Escape reverts, and a resting pointer previews after 450 ms.
RecentFontskeeps the six most recently used families in user defaults (client view state, nevercmux-next.json); every font family write records one. The palette's font options and typed-value parsing live inCmuxNextSettings(RecentFonts.options,SettingDescriptor.value(typed:));SettingOptioncarriesisRecent.- Change Font… derives every font setting (families, sizes, line heights, the chat's and Markdown viewer's font) from the schema, so new font settings join without edits. A What's New highlight gains an Open Settings action.
- The terminal has no line-height key; that would need a Ghostty
adjust-cell-heightsetting, left out.