From 999276230f0f9b25700da1c5962448763fab502e Mon Sep 17 00:00:00 2001 From: danshapiro <3732858+danshapiro@users.noreply.github.com> Date: Wed, 8 Jul 2026 09:09:11 -0700 Subject: [PATCH] feat(editor): editor pane font size follows terminal font size setting The Monaco editor pane hard-coded fontSize: 14, ignoring the Font size setting that already drives the terminal, the fresh-agent transcript, and (via --ui-scale) the whole UI. Subscribe to settings.terminal.fontSize (direct 1:1 mapping, default 16) in the Monaco options literal; live updates ride @monaco-editor/react's built-in options -> updateOptions effect, so open editors resize without remounting. New EditorPane.fontSize tests cover default, mount-after-change, live-update without remount, and clamped values. Verified with npm run check (full coordinated suite green). Generated with Amplifier Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com> --- ...-07-08-editor-font-follows-setting-spec.md | 230 ++++++++++++++++++ src/components/panes/EditorPane.tsx | 3 +- .../panes/EditorPane.fontSize.test.tsx | 131 ++++++++++ 3 files changed, 363 insertions(+), 1 deletion(-) create mode 100644 docs/plans/2026-07-08-editor-font-follows-setting-spec.md create mode 100644 test/unit/client/components/panes/EditorPane.fontSize.test.tsx diff --git a/docs/plans/2026-07-08-editor-font-follows-setting-spec.md b/docs/plans/2026-07-08-editor-font-follows-setting-spec.md new file mode 100644 index 00000000..894b0589 --- /dev/null +++ b/docs/plans/2026-07-08-editor-font-follows-setting-spec.md @@ -0,0 +1,230 @@ +# Spec: Editor pane font size follows the terminal Font size setting + +- **Date**: 2026-07-08 +- **Branch**: `feat/editor-font-setting` (worktree `.worktrees/editor-font`, based on `origin/main` @ `b5daeea4`) +- **Status**: Ready for implementation (Red-Green-Refactor TDD) +- **Scope guard**: consume `settings.terminal.fontSize` in the editor pane only. Do NOT add a + separate editor font setting. Do NOT touch font family, line height, minimap, or any other + Monaco option. No server, schema, or settings-UI changes. + +## 1. Problem + +The Monaco-based editor pane hard-codes its font size: + +- `src/components/panes/EditorPane.tsx:1033` — `fontSize: 14,` inside the inline `options` + literal passed to `` (`src/components/panes/EditorPane.tsx:1024-1041`). + +Every other text surface follows the local terminal Font size setting +(`settings.terminal.fontSize`, clamped 12–64, default 16): + +- xterm initial: `src/components/TerminalView.tsx:1727` (`fontSize: settings.terminal.fontSize`) +- xterm live: `src/components/TerminalView.tsx:2638` (`term.options.fontSize = settings.terminal.fontSize`) +- fresh-agent transcript: `src/components/fresh-agent/FreshAgentView.tsx:512-514` (selector) feeding + an inline CSS var +- UI chrome: `src/hooks/useTheme.ts:8-12` — `--ui-scale = (terminalFontSize / 16) * uiScale` + +Monaco sizes in raw px and does not inherit the rem-based `--ui-scale`, so the editor is the one +pane that ignores the setting entirely (this is the gap left by PR #511 / #509). + +## 2. Verified facts (worktree @ b5daeea4) + +| Fact | Evidence | +|---|---| +| Hard-coded editor font | `src/components/panes/EditorPane.tsx:1033` | +| Options passed as **inline literal**, new identity every render | `src/components/panes/EditorPane.tsx:1031-1040` | +| Editor instance held in ref via `onMount` | `editorRef` at `src/components/panes/EditorPane.tsx:175`; `handleEditorMount` at `:294-297`; `onMount={handleEditorMount}` at `:1029` | +| EditorPane already subscribes to settings | `useMonacoTheme` at `src/components/panes/EditorPane.tsx:21-26` uses `useAppSelector((s) => s.settings.settings.theme)` | +| `@monaco-editor/react` `^4.6.0` applies `options` changes live | `package.json`; installed dist (`node_modules/@monaco-editor/react/dist/index.mjs`) contains a post-ready update effect equivalent to `useUpdate(() => editor.updateOptions(options), [options], isEditorReady)`, and the mount path spreads options into `editor.create(..., { model, automaticLayout: true, ...options })` | +| Precedent selector shape (exact) | `src/components/fresh-agent/FreshAgentView.tsx:512-514`: `useAppSelector((state) => state.settings.settings.terminal?.fontSize) ?? 16` — plain primitive selector, **no** memoization/`shallowEqual` (correct for a primitive) | +| Clamp/normalize is shared and local-only | `shared/settings.ts:44-45` (`TERMINAL_FONT_SIZE_MIN = 12`, `TERMINAL_FONT_SIZE_MAX = 64`, module-private), `:504-511` (`normalizeRoundedClampedNumber`), `:854` (default `fontSize: 16`); local-only persistence at `src/store/browserPreferencesPersistence.ts:94` | +| Store action the slider dispatches | `src/components/settings/AppearanceSettings.tsx:360-369` → `applyLocalSetting({ terminal: { fontSize: v } })` → `updateSettingsLocal` (`src/store/settingsSlice.ts:117-122`), which re-normalizes through the shared clamp path — dispatching an out-of-range value lands clamped in `state.settings.settings.terminal.fontSize` | +| Default slice state already resolves to 16 | `src/store/settingsSlice.ts:85-90` (`initialState.settings = resolveSettings(defaults, ...)`) | +| No test pins the editor's 14 | `grep 'fontSize:\s*14'` hits: `EditorPane.tsx:1033` (the source), plus terminal-settings *fixtures* in `test/unit/client/components/panes/PaneContainer.test.tsx:1687,2109`, `test/unit/client/components/panes/PanePicker.test.tsx:86`, `test/e2e/directory-picker-flow.test.tsx:144,237` — all preloaded `settings.terminal` state, none assert Monaco options. No change needed to any of them. | +| Existing Monaco mocks ignore `options` | e.g. `test/unit/client/components/panes/EditorPane.test.tsx:23-36` and `EditorPane.connectivity.test.tsx:23-28` render a `