Skip to content

feat(editor): one typography resolver for every Monaco surface + opt-in weight, line height, ligatures, size and macOS smoothing - #36577

Merged
nwparker merged 4 commits into
mainfrom
nwparker/theme-editor-typography
Nov 1, 2026
Merged

nwparker merged 4 commits into
mainfrom
nwparker/theme-editor-typography

Conversation

@nwparker

@nwparker nwparker commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 4 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​104 $\color{#cf222e}{\Huge{\mathbf{−}}}$​9 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​95
Prod 37 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​789 $\color{#cf222e}{\Huge{\mathbf{−}}}$​159 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​630

Summary

Code typography now comes from one resolver. Before this, five Monaco sites (file editor, diff viewer, combined diff, notebook cells, automation prompt editor), the GitHub comment code excerpt and the editor zoom overlay each built fontFamily/fontSize on their own from terminalFontSize. None of them passed fontWeight, fontLigatures or lineHeight.

src/renderer/src/lib/editor-typography.ts (with useEditorTypography()) replaces the font-family part of editor-font-zoom.ts; that file now holds only the zoom-step math. Every one of those surfaces reads the resolver. The DOM excerpts use a CSS twin (editorTypographyTextStyle), so they match Monaco: the same family stack, weight, line height and liga/calt handling.

New opt-in settings sit next to Editor Font Family under Settings › General › Editor. Any field left empty renders exactly as today.

Setting Empty (default) Set
Editor Font Size follows the terminal font size (today's behavior) 10–24 px base. ⌘= / ⌘− editor zoom still applies on top, and the zoom overlay % uses this base
Editor Font Weight Monaco regular (400, today's behavior) 100–900
Editor Line Height Monaco automatic spacing (today's behavior) 1–3 × font size; a value of 8 or more is read as pixels, and 0 means automatic. Applies to the file editor, diffs, the combined diff, notebook cells and excerpts
Editor Font Ligatures Off (today's behavior) Off / Auto / On, with the same semantics as the terminal setting, judged against the editor font
Editor Font Family (existing) follows the terminal font in code editors; Markdown code keeps the app monospace now also used for Markdown code (inline and fenced, in the rich editor and the preview)
Font Smoothing (macOS only, hidden elsewhere) Grayscale (today's app-wide antialiased) Native (-webkit-font-smoothing: auto) for terminals and code editors

Root cause, font smoothing

body { -webkit-font-smoothing: antialiased } is inherited by .xterm and .monaco-editor. I measured this in the running app: switching to native smoothing makes terminal glyphs about 14% brighter on average, with 29% more lit pixels.

WebGL terminals bake the smoothing into their glyph atlas, and clearTextureAtlas() does not pick up the change. xterm also shares atlases between terminals that use the same font config. So a toggle calls a new rebuildAllTerminalWebglRenderers(): every pane detaches first, then they all reattach, so no pane can get the old shared atlas back. The rebuild runs only when the attribute actually changes, so it costs nothing while the setting is unused.

Closes #20183
Closes #35973
Closes #30084
Closes #25910

Supersedes / builds on: #20188 by @PedroOsnaghi (editor font weight and line height), #30088 by @nivaldomcj (opt-in Editor Font Size, and the zoom-overlay base), #13056 by @adaex (font smoothing). Each of those wires one option into some of the sites. This PR fixes the shared root cause instead, so all options reach every Monaco and DOM code surface through one path.

Not included:

Which surfaces follow the editor setting

Checked in code and measured in the running app (computed font-family, font-size, font-weight, line-height, font-feature-settings) with defaults and with family FiraCode Nerd Font, size 16, weight 600, line height 24px, ligatures On:

Surface Follows family / size / weight / line height / ligatures
File editor (also Markdown source mode) Yes: 16px, 600, 24px, liga on
Single-file diff, side-by-side and inline (Source Control, branch and commit diffs, external-change compare) Yes: same resolver, size base − 0.5 (15.5px), 23px lines
Combined "all changes" diff, branch/commit all-diffs and the pull request files view, side-by-side and inline Yes: same as the single-file diff
Notebook code cells and their previews Yes
Automation prompt editor, GitHub comment code excerpts Yes
Markdown code blocks and inline code (rich editor and preview) Family only, and only when Editor Font Family is set. Size stays relative to the prose and follows editor zoom; weight, line height and ligatures stay prose-styled
Terminal, chat transcripts, sidebar comments No, by design: they keep the terminal or app fonts
Mobile No: the mobile app renders natively with its own fonts

Setting semantics follow common code-editor conventions

  • Line height: a value of 8 or more is read as pixels and 0 means automatic, so a value like 22 no longer clamps to 3× the font size. Pixel values are converted against the base size, so they still scale with editor zoom. They are clamped to 1–3× the font size so glyphs can't overlap.
  • Markdown code uses the explicitly chosen editor font. When Editor Font Family is empty, Markdown keeps today's app monospace instead of switching every document to the terminal font.
  • Kept as is: the editor follows the terminal font and size when unset (Orca's existing direction); weight 100–900; ligatures Off / Auto / On. Custom OpenType feature strings (for example stylistic sets) are left for a follow-up.

Markdown code with an explicit Editor Font Family (light: rich editor unset → set; dark: preview unset → set)
md light unset
md light set
md dark unset
md dark set

Visual proof

Captured on macOS from the real dev build, driven over CDP in the background. The sample repo uses FiraCode Nerd Font as the Editor Font Family. "Before" is origin/main. "After" uses Editor Font Size 16, Weight 600, Line Height 1.8 and Ligatures On.

File editor (dark)
editor dark

File editor (light)
editor light

Diff viewer and combined diff (dark)
diff dark

Diff viewer (light)
diff light

Settings › General › Editor (before / after dark / after light)
settings

Font Smoothing: Grayscale vs Native (WebGL terminal and editor)
smoothing

No change when nothing is set: with every new field empty, the file editor screenshots from origin/main and from this branch are byte-identical PNGs (dark), and so are the light diff-viewer screenshots. Computed styles match too: weight 400, "calt" 0, "liga" 0, 21px lines in the editor and 20px in the diff.

Perf

Scanned: the full diff against origin/main, using the six perf-scan questions:

  • Unused work before the skip gate: useEditorTypography uses a shallow selector over seven keys, and the useMemo result is stable.
  • Multiplied owners: one hook per mounted Monaco surface, no new listeners or timers.
  • Thread: all work runs synchronously on the renderer.
  • Growth: the WebGL rebuild is O(live terminals) and runs once per toggle.
  • Host: the smoothing setting is gated to macOS; elsewhere it is a no-op.
  • Teardown: the warm-up cancel on dispose fixes the atlas canvas leak, and the Markdown variable is removed when unset.

Findings: none introduced. The notebook cell, notebook preview and automation prompt editor no longer subscribe to the whole settings object. One pre-existing cost is unchanged and identical on origin/main: the combined diff re-renders every section and calls updateOptions once per section on every settings write. It is left for a follow-up.

Measured. Dev builds, base (origin/main) and branch launched side by side with ORCA_BACKGROUND_LAUNCH=1, isolated profiles, driven over CDP. Renders were counted with a React commit hook (PerformedWork per named component). updateOptions calls were counted on every live Monaco instance. Workload: 10 unrelated settings writes.

Surface updateOptions calls (base / branch) Component renders (base / branch)
File editor 10 / 10 MonacoEditor 30 / 30
Single-file diff 10 / 10 DiffViewer 30 / 30
Combined diff (11 sections) 110 / 110 DiffSectionItem 330 / 330
Notebook 0 / 0 IpynbCodePreview 30 / 30
Control: one typography write (terminal font size) 2 / 2 MonacoEditor 2 / 2

The 10 calls per 10 writes in the file editor and single-file diff happen on base too. The editor wrapper re-applies its options object on every render, and the effect this PR owns does not fire on unrelated writes.

  • Editor mount time: median time from openFile to the first painted line, 10 fresh files per round, three interleaved rounds. Base 205 / 234 / 267 ms, branch 220 / 224 / 205 ms. No measurable difference within dev-build noise.
  • Font Smoothing toggle, 8 retained WebGL terminals (branch): an unrelated write keeps every terminal canvas, so no rebuild. Each toggle recreates 17 canvases. The whole settings write plus the rebuild takes a 138–238 ms long task (one outlier at 652 ms). The same write on base, where the key is ignored, is a 65–151 ms long task. So the rebuild costs about 80–150 ms once per user toggle, scaling with the number of live terminals.

Merge-risk assessment

Low (was low–medium). Phase-2 stress and cross-platform testing exercised the risky WebGL rebuild path and fixed the one real problem it found.

  • Blast radius: every Monaco surface now takes its typography options from one place. With nothing set, the resolved values equal today's: same family, same size math, fontWeight: 'normal', lineHeight: 0 (Monaco auto) and ligatures off. The file-editor and light diff-viewer screenshots are byte-identical to origin/main.
  • Follow-up delta (pixel/0 line heights, Markdown code font): low. With Editor Font Family empty, the CSS variable is removed and Markdown code computes to exactly the previous --font-mono stack (measured in light and dark). Line-height values from 1 to 3 resolve exactly as before. The shared NumberField gained an opt-in clearOnZero, and it now skips writing a value equal to the current one; that is the only change for the other 17 users.
  • Migration: none. All five keys are optional and have no defaults, so no persisted value changes.
  • Back-compat: older clients ignore the unknown optional keys. Corrupt or hand-edited values fall back to today's behavior (covered by a unit test). A native smoothing value copied onto Linux or Windows has no effect: the root attribute stays unset.
  • Perf: useEditorTypography uses a shallow selector, so unrelated settings writes don't re-render editors or call updateOptions. Smoothing does nothing until a user opts in. A toggle rebuilds the live WebGL renderers once, the same cost as switching GPU acceleration.

Evidence from the WebGL rebuild stress run. This was a macOS dev build with 68 terminal panes:

  • An 8-pane split tab, four hidden tabs holding 17, 17, 16 and 9 panes, and a floating terminal.
  • Every visible pane was printing seq 1 40000 while Font Smoothing was toggled 20 times at 250 ms intervals. Then another 490 toggles were run with no output.

Results:

  • No lost scrollback: every visible pane's buffer is contiguous with 0 gaps and ends at 40000 followed by the done marker.
  • No blank panes: checked in screenshots after the toggles. A hidden 17-pane tab revealed afterwards rendered every pane with WebGL and the new smoothing.
  • Renderer count stable: WebGL renderers held at 9 and .xterm-screen canvases at 18 throughout. Context losses stayed at 0, and there were no Chromium "too many WebGL contexts" warnings.
  • Heap: no lasting growth after forced GC. It moved between 144 and 187 MB across 490 toggles, ending lower than it started.
  • Context loss still recovers: I forced WEBGL_lose_context on 3 live panes. They fell back to the DOM renderer as the existing policy intends. Toggling smoothing afterwards skipped them, and all 9 visible panes still echoed new output.

Leak found and fixed (commit fix(terminal): cancel WebGL atlas warm-up…):

  • Cause: xterm's WebGL glyph atlas keeps running its idle warm-up queue after dispose(). Orca's xterm patch makes that warm-up draw into the terminal element, so a disposed atlas re-appended its hidden scratch canvas and leaked one canvas per atlas.
  • Not new to this PR: it already happened on every GPU-acceleration toggle, context-loss retry and resize. Before the fix, 10 GPU toggles added 170 orphan canvases and 120 smoothing toggles added about 1,000.
  • Fix: config/patches/xterm-src/@xterm__addon-webgl@0.20.0-beta.300.src.patch now clears the queue on dispose and before a re-warm. I regenerated the built patch with regenerate-xterm-patches.mjs --write, which also updated the lockfile hash. Orphan canvases now stay at 1 (the live atlas) across 10 slow toggles, 120 rapid toggles and 10 GPU toggles.
  • Mobile: the mobile app's own copy of this patch warms up without a DOM container, so it can't leak this way and is unchanged.

Cross-platform:

  • Linux: omarchy (Arch, Hyprland, native Wayland) running this branch.
  • Windows: awin (Windows 11) running this branch.
  • Result on both: General › Editor shows Editor Font Size, Weight, Line Height and Ligatures correctly. There is no Font Smoothing row, and searching settings for "smoothing" finds nothing.

Negative user-facing tradeoffs

  • GitHub comment code excerpts look different: they now render in the editor font and size. They were meant to, but a font-mono class overrode the inline style. They also no longer show ligatures by default, to match Monaco.
  • Commented-line highlight color in code excerpts: commented lines in GitHub comment code excerpts used to be tinted emerald green (bg-emerald-500/10). They now use the theme's --ring color (bg-ring/15), the same color as the comment-range highlight in Monaco diffs, so the tint looks different from before.
  • Notebook previews with ligature fonts: the code cell preview used the browser default (ligatures on); it now matches the cell editor (off unless enabled).
  • Weight and ligatures don't follow the terminal by default. That would have changed every existing editor: the terminal's default weight is 500, and its ligatures are Auto. Users who want them to match set them explicitly.
  • WebGL rebuild on toggle: changing Font Smoothing recreates WebGL terminal renderers, which can cause a brief repaint. Terminals in a dashboard pop-out window pick up the change on their next renderer rebuild, not immediately.
  • Combined-diff height estimate: before a section is measured, its height is estimated at a fixed 19px per line, and that was already wrong under editor zoom. With a tall Editor Line Height, unmeasured sections can jump once Monaco reports their real height.
  • Native Font Smoothing covers code surfaces only: it applies to terminals, Monaco, code excerpts and notebook previews. UI chrome stays grayscale.
  • Markdown code font changes for users with an explicit Editor Font Family: inline and fenced Markdown code switches from the app monospace to that font.
  • Line height 3.1–7.9 renders as 3×: those values are neither a usable multiplier nor pixels.
  • Pixel line heights are clamped to 1–3× the font size: a pixel value smaller than the font, for example, renders at 1×.
  • No translations yet: the new strings are English only; other locales fall back to English until translated.

Validation

  • pnpm tc:web passes.
  • oxlint is clean on the changed files; oxfmt was run.
  • pnpm sync:localization-catalog, verify:localization-extraction and verify:localization-runtime-catalog pass.
  • Focused vitest from a non-nested worktree: the new lib/editor-typography.test.ts plus the pane-manager, settings, editor (DiffSection*, Monaco*, Ipynb*), automations, app-shell and useIpcEvents* suites. 372 files / 2889 tests pass. An earlier wider run, which also covered terminal-pane, hit one failure that comes from the node-pty environment (fish-color-scheme-child-stdin.node-pty.test.ts); this diff does not touch that code.
  • In the app, launched with ORCA_BACKGROUND_LAUNCH=1, an isolated profile and CDP:
    • Opened a file and its diff and the combined "all changes" diff, in light and dark, with defaults and with overrides. Checked the computed font-weight, font-feature-settings and line heights.
    • Emptied a field from the Settings UI: the value is cleared to undefined and the placeholder falls back to the terminal value.
    • Toggled Font Smoothing Grayscale → Native → Grayscale on a live WebGL terminal and measured the glyph pixels: 73.4 → 83.6 → 73.4.
    • Toggled Font Smoothing while the terminal was hidden behind an editor tab (retained WebGL), then revealed it: the terminal was correctly native (83.6).
    • Confirmed that clearTextureAtlas() alone does not apply the change (73.4 → 73.4). That is why this PR rebuilds the renderers.

Follow-up delta (surface coverage, line-height semantics, Markdown code font)

  • Rebased on origin/main. pnpm tc:web passes, and the focused vitest run (editor typography and all settings suites, 182 files / 1276 tests) passes. The localization extraction and runtime-catalog checks pass.
  • In the app (background launch, isolated profile, CDP): measured the file editor, the single-file diff and the combined diff in both side-by-side and inline modes, notebook cells, and Markdown code in the rich editor and the preview, with defaults and with overrides (table above).
  • Settings UI: entering 22 stores 22 (pixels), 1.5 stores 1.5, and 0 or an empty field clears to automatic.
  • Review: an Opus sub-agent and Codex (gpt-6.1-sol, xhigh). Fixed: fenced code in the rich editor (rendered directly in <pre>) missed the font; rounding the ratio skewed pixel heights; typed pixel values were stored as a ratio, so they drifted when the font size changed; a hand-edited terminal size of 0 could divide by zero; the line-height field kept a stale 1-3 suffix. Not changed: the 1–3× clamp on pixel values is deliberate.

Phase 2 (risk reduction)

  • WebGL stress, leak, context-loss and hidden-tab tests as described under Merge-risk assessment. The scripts drove the dev build over CDP with VITE_EXPOSE_STORE=true so they could inspect pane managers.
  • Cross-platform screenshots of Settings › General › Editor:

Linux (omarchy):
linux settings

Windows (awin):
windows settings

  • The xterm patch fix had two independent reviews: an Opus sub-agent and Codex (gpt-6.1-sol, xhigh). Neither found anything to fix. Codex confirmed the CJS and ESM bundles and the source maps match the source patch, and that the lockfile hashes agree. Opus pointed out the leak also happened on resize, where atlases are rebuilt twice per pane; this fix covers that too.

Review

I ran two independent Opus reviews and a Codex (gpt-6.1-sol, xhigh) review, and fixed what they found:

  • Retained hidden terminals kept the shared atlas alive. The global rebuild now detaches them too, and they reattach when shown.
  • The notebook cell's maximum height was captured at mount. It now uses the live line height.
  • Notebook previews and code excerpts didn't get Native smoothing. They now carry an editor-typography-surface class.
  • Unknown editorLigatures values could enable ligatures. Anything except on/auto now resolves to off.
  • Blurring an already-empty number field wrote the setting again. It no longer does.
  • The editor rows reused terminal translation keys and hard-coded the weight and line-height ranges. They now have their own keys and use the shared constants.

Two reviewers also argued that CSS smoothing can't reach xterm's detached atlas canvas. The in-app measurements above show that it does once the renderer is rebuilt.

@coderabbitai

coderabbitai Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 19 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 2f463f75-9b6b-4d4f-9fbc-f1c90735fd76
Commits

Reviewing files that changed from the base of the PR and between 74486ee and f342a39.

Files ignored due to path filters: 1
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
Files selected for processing: 40
  • config/patches/@xterm__addon-webgl@0.20.0-beta.300.patch
  • config/patches/xterm-src/@xterm__addon-webgl@0.20.0-beta.300.src.patch
  • src/renderer/src/app-shell/use-document-appearance.ts
  • src/renderer/src/assets/main.css
  • src/renderer/src/assets/markdown-preview.css
  • src/renderer/src/assets/rich-markdown-editor.css
  • src/renderer/src/components/automations/AutomationEditorPromptEditor.tsx
  • src/renderer/src/components/automations/automation-editor-prompt-options.test.ts
  • src/renderer/src/components/automations/automation-editor-prompt-options.ts
  • src/renderer/src/components/editor/DiffSectionBody.tsx
  • src/renderer/src/components/editor/DiffSectionBody.word-wrap-lifecycle.test.tsx
  • src/renderer/src/components/editor/DiffSectionItem.tsx
  • src/renderer/src/components/editor/DiffViewer.tsx
  • src/renderer/src/components/editor/IpynbCellEditor.tsx
  • src/renderer/src/components/editor/MonacoCodeExcerpt.tsx
  • src/renderer/src/components/editor/MonacoEditor.tsx
  • src/renderer/src/components/editor/diff-section-item-props.ts
  • src/renderer/src/components/settings/EditorFontFamilySetting.tsx
  • src/renderer/src/components/settings/EditorTypographySettings.tsx
  • src/renderer/src/components/settings/GeneralEditorSettingsSection.tsx
  • src/renderer/src/components/settings/GeneralPane.section-lifetime.test.tsx
  • src/renderer/src/components/settings/SettingsFormControls.tsx
  • src/renderer/src/components/settings/editor-typography-search.ts
  • src/renderer/src/components/settings/general-editor-search.ts
  • src/renderer/src/hooks/ipc-events/zoom-ipc-bridge.ts
  • src/renderer/src/hooks/use-editor-typography.ts
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/lib/code-font-smoothing.ts
  • src/renderer/src/lib/editor-font-zoom.ts
  • src/renderer/src/lib/editor-typography.test.ts
  • src/renderer/src/lib/editor-typography.ts
  • src/renderer/src/lib/markdown-code-font.ts
  • src/renderer/src/lib/pane-manager/pane-manager-registry.ts
  • src/renderer/src/lib/pane-manager/pane-manager.ts
  • src/renderer/src/lib/pane-manager/pane-webgl-reattach.ts
  • src/renderer/src/popout.tsx
  • src/shared/editor-typography-settings-types.ts
  • src/shared/global-settings-base.ts
  • src/shared/global-settings-types.ts
  • src/shared/terminal-fonts.ts

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 5cb9dd4b-d7f5-4a12-9d0e-6a850ecfb8fe
Commits

Reviewing files that changed from the base of the PR and between 12e6334 and 74486ee.

Files ignored due to path filters: 1
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
Files selected for processing: 2
  • config/patches/@xterm__addon-webgl@0.20.0-beta.300.patch
  • config/patches/xterm-src/@xterm__addon-webgl@0.20.0-beta.300.src.patch

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 6 remain after this review.

Walkthrough

The change adds editor font size, weight, line height, ligature, and code font smoothing settings. A shared resolver supplies typography to Monaco editors, diff views, notebook cells, code excerpts, and automation prompt editors. Settings search and controls are updated. On supported platforms, changing code font smoothing updates the document attribute and rebuilds terminal WebGL renderers.

Merge Risk: Low · previous review 74486

Notebook and Markdown zoom percentages can differ from the rendered size; this is a localized UI inconsistency suitable for bounded follow-up.

Pre-merge checks: Passed 3 · Failed 2

Failed Failed checks: 2 warnings

Check name Status Explanation Resolution
Linked Issues check Warning The changes satisfy [#30084], [#35973], and [#25910]. The shared resolver applies editor size, ligatures, and smoothing to the reported Monaco and code surfaces, and the smoothing path rebuilds live W… Use normalized terminalFontWeight as the fallback when editorFontWeight is unset or invalid. Keep explicit editor-weight overrides. Add tests for terminal-weight inheritance and override behavior.
Docstring Coverage Warning Docstring coverage is 46.15% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documenta… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 3 passed
Check name Status Explanation
Title check Passed The title clearly identifies the main change: a shared editor typography resolver with opt-in typography and macOS smoothing settings. It is long, but it remains specific and related to the changeset.
Out of Scope Changes check Passed The changes remain connected to the linked editor-typography objectives. The shared resolver, settings, tests, DOM styles, Monaco updates, and WebGL lifecycle changes support [#20183], [#35973], [#300…
Description check Passed The description follows the repository template closely. It has an ELI5-style summary in the Summary section, a detailed What Changed and Why explanation (root cause, resolver design, and the WebGL re…
Full details: Out of Scope Changes check

Explanation

The changes remain connected to the linked editor-typography objectives. The shared resolver, settings, tests, DOM styles, Monaco updates, and WebGL lifecycle changes support [#20183], [#35973], [#30084], or [#25910]. The added line-height support is an adjacent Monaco typography change identified as suitable to solve with editor weight. The changes do not implement the separately excluded File Explorer sizing or UI-wide IDE weight.

Full details: Description check

Explanation

The description follows the repository template closely. It has an ELI5-style summary in the Summary section, a detailed What Changed and Why explanation (root cause, resolver design, and the WebGL rebuild mechanism with alternatives such as #20188, #30088, #13056), a Visual Proof section with before/after screenshots for file editor, diff, settings, and smoothing, a Testing section with platforms actually tested (macOS, Linux, Windows) and the validation commands run, and Negative user-facing tradeoffs. The template's ELI5 heading is not present as a labeled section, and the 'Linked Issue' section uses 'Closes #' lines for four issues, which satisfies the linked issue requirement. The 'Review' heading and 'Agent skill upstream boundary' checkbox are not addressed, and the AI Disclosure section is not filled in. The checklist is not ticked. These gaps are non-critical relative to the substance of the description.

Full details: Linked Issues check

Explanation

The changes satisfy [#30084], [#35973], and [#25910]. The shared resolver applies editor size, ligatures, and smoothing to the reported Monaco and code surfaces, and the smoothing path rebuilds live WebGL renderers. The changes do not satisfy [#20183]. An empty editorFontWeight resolves to Monaco regular ('normal') instead of normalized terminalFontWeight, although [#20183] requires terminal-weight inheritance by default.

Resolution

Use normalized terminalFontWeight as the fallback when editorFontWeight is unset or invalid. Keep explicit editor-weight overrides. Add tests for terminal-weight inheritance and override behavior.

Full details: Docstring Coverage

Explanation

Docstring coverage is 46.15% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 26 functions across 29 files. (1 skipped: 1 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2


Review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 870da848-36dd-441f-acb7-b855820c2308
Commits

Reviewing files that changed from the base of the PR and between 1f504e9 and 12e6334.

Files selected for processing: 34
  • src/renderer/src/app-shell/use-document-appearance.ts
  • src/renderer/src/assets/main.css
  • src/renderer/src/components/automations/AutomationEditorPromptEditor.tsx
  • src/renderer/src/components/automations/automation-editor-prompt-options.test.ts
  • src/renderer/src/components/automations/automation-editor-prompt-options.ts
  • src/renderer/src/components/editor/DiffSectionBody.tsx
  • src/renderer/src/components/editor/DiffSectionBody.word-wrap-lifecycle.test.tsx
  • src/renderer/src/components/editor/DiffSectionItem.tsx
  • src/renderer/src/components/editor/DiffViewer.tsx
  • src/renderer/src/components/editor/IpynbCellEditor.tsx
  • src/renderer/src/components/editor/MonacoCodeExcerpt.tsx
  • src/renderer/src/components/editor/MonacoEditor.tsx
  • src/renderer/src/components/editor/diff-section-item-props.ts
  • src/renderer/src/components/settings/EditorTypographySettings.tsx
  • src/renderer/src/components/settings/GeneralEditorSettingsSection.tsx
  • src/renderer/src/components/settings/GeneralPane.section-lifetime.test.tsx
  • src/renderer/src/components/settings/SettingsFormControls.tsx
  • src/renderer/src/components/settings/editor-typography-search.ts
  • src/renderer/src/components/settings/general-editor-search.ts
  • src/renderer/src/hooks/ipc-events/zoom-ipc-bridge.ts
  • src/renderer/src/hooks/use-editor-typography.ts
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/lib/code-font-smoothing.ts
  • src/renderer/src/lib/editor-font-zoom.ts
  • src/renderer/src/lib/editor-typography.test.ts
  • src/renderer/src/lib/editor-typography.ts
  • src/renderer/src/lib/pane-manager/pane-manager-registry.ts
  • src/renderer/src/lib/pane-manager/pane-manager.ts
  • src/renderer/src/lib/pane-manager/pane-webgl-reattach.ts
  • src/renderer/src/popout.tsx
  • src/shared/editor-typography-settings-types.ts
  • src/shared/global-settings-base.ts
  • src/shared/global-settings-types.ts
  • src/shared/terminal-fonts.ts
Files with no reviewable changes: 3
  • src/shared/global-settings-types.ts
  • src/renderer/src/components/editor/diff-section-item-props.ts
  • src/renderer/src/lib/editor-font-zoom.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 4 remain after this review.

Comment on lines 184 to 194
return
}
editorRef.current.updateOptions({
fontSize: editorFontSize,
fontFamily: editorFontFamily,
...typographyOptions,
...buildFileEditorWordWrapOptions(editorWordWrap),
readOnly
})
}, [editorFontFamily, editorFontSize, editorWordWrap, readOnly])
}, [typographyOptions, editorWordWrap, readOnly])

const decorations = useMonacoEditorDecorations({
editorRef,

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.

Minor · Functional Correctness · Quick win

Supported by static analysis

Script executed:

set -o pipefail
printf '%s\n' '--- MonacoEditor relevant declarations and effects ---'
nl -ba src/renderer/src/components/editor/MonacoEditor.tsx | sed -n '1,220p'
printf '%s\n' '--- MonacoEditor mount wiring and autoHeight callers ---'
nl -ba src/renderer/src/components/editor/MonacoEditor.tsx | sed -n '240,330p'
rg -n -F --glob '*.tsx' -e '<MonacoEditor' -e 'autoHeight=' src/renderer/src | head -200 || test "$?" -eq 1
printf '%s\n' '--- mount helper relevant declarations ---'
nl -ba src/renderer/src/components/editor/use-monaco-editor-mount.ts | sed -n '1,150p'
printf '%s\n' '--- clamp definition and all usages ---'
rg -n -F --glob '*.{ts,tsx}' -e 'clampMonacoAutoHeight' -e 'autoHeightLineHeight' src/renderer/src/components/editor
printf '%s\n' '--- typography update comparison ---'
nl -ba src/renderer/src/components/editor/IpynbCellEditor.tsx | sed -n '140,300p'

Repository: stablyai/orca

Length of output: 31807


Script executed:

set -o pipefail
printf '%s\n' '--- auto-height implementation ---'
nl -ba src/renderer/src/components/editor/monaco-auto-height.ts
printf '%s\n' '--- complete caller blocks ---'
nl -ba src/renderer/src/components/editor/EditorConflictReviewSurface.tsx | sed -n '180,265p'
nl -ba src/renderer/src/components/editor/EditorEditFileSurface.tsx | sed -n '200,270p'
printf '%s\n' '--- auto-height tests ---'
nl -ba src/renderer/src/components/editor/monaco-auto-height.test.ts
printf '%s\n' '--- mount lifecycle and typography tests ---'
rg -n -F --glob '*.{ts,tsx}' -e 'onDidContentSizeChange' -e 'updateOptions' -e 'autoHeightContentHeight' -e 'typographyOptions' src/renderer/src/components/editor | head -240 || test "$?" -eq 1

Repository: stablyai/orca

Length of output: 17992


Script executed:

set -o pipefail
printf '%s\n' '--- autoHeight definitions and call sites in editor surfaces ---'
rg -n -F --glob '*.tsx' -e 'autoHeight' src/renderer/src/components/editor/EditorConflictReviewSurface.tsx src/renderer/src/components/editor/EditorEditFileSurface.tsx src/renderer/src/components/editor
printf '%s\n' '--- surrounding autoHeight declarations ---'
python3 - <<'PY'
from pathlib import Path
for name in [
    'src/renderer/src/components/editor/EditorConflictReviewSurface.tsx',
    'src/renderer/src/components/editor/EditorEditFileSurface.tsx',
]:
    lines = Path(name).read_text().splitlines()
    hits = [i for i, line in enumerate(lines) if 'autoHeight' in line]
    print(f'--- {name} ---')
    for i in hits:
        lo, hi = max(0, i-5), min(len(lines), i+6)
        print(f'lines {lo+1}-{hi}')
        for n in range(lo, hi):
            print(f'{n+1:5} {lines[n]}')
printf '%s\n' '--- typography hook and its settings consumers ---'
rg -n -F --glob '*.{ts,tsx}' -e 'function useEditorTypography' -e 'export function useEditorTypography' -e 'useEditorTypography' src/renderer/src/hooks src/renderer/src/lib src/renderer/src/components/settings | head -160 || test "$?" -eq 1

Repository: stablyai/orca

Length of output: 3863


Script executed:

nl -ba src/renderer/src/components/editor/use-monaco-editor-mount.ts | sed -n '255,292p'

Repository: stablyai/orca

Length of output: 1465


Read the current line height in the retained auto-height listener.

The mounted MonacoEditor updates typography without replacing its content-size listener. That listener still clamps with the mount-time line height. In the reachable conflict-review path with autoHeight: true, increasing the line height can restore the old, smaller cap. The current cap check then hides the scrollbar because it uses the new line height, so content can be clipped.

Suggested fix
diff --git a/src/renderer/src/components/editor/use-monaco-editor-mount.ts b/src/renderer/src/components/editor/use-monaco-editor-mount.ts
@@
   const fileIdRef = useRef(fileId)
+  const autoHeightLineHeightRef = useRef(autoHeightLineHeight)
   useLayoutEffect(() => {
     fileIdRef.current = fileId
   }, [fileId])
+  useLayoutEffect(() => {
+    autoHeightLineHeightRef.current = autoHeightLineHeight
+  }, [autoHeightLineHeight])
@@
-              autoHeightLineHeight
+              autoHeightLineHeightRef.current
@@
-      autoHeightLineHeight,
       worktreeId,

Comment on lines +49 to +50
// Why: mirror the editor's base font + clamping so the overlay percent matches the rendered size.
const baseFontSize = resolveEditorBaseFontSize(settings)

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.

Minor · Functional Correctness · Quick win

Supported by static analysis

Script executed:

#!/bin/bash
rg -nP --type=ts --type=tsx -C2 '\b(computeEditorFontSize|computeDiffEditorFontSize)\s*\(' src/renderer
rg -nP --type=ts --type=tsx -C2 'editorFontZoomLevel' src/renderer -g '!**/*.test.*'

Repository: stablyai/orca

Length of output: 215


Script executed:

#!/bin/bash
set -u
printf '%s\n' '--- matching declarations and usages ---'
rg -n -F --glob '*.ts' --glob '*.tsx' \
  -e 'computeEditorFontSize' \
  -e 'computeDiffEditorFontSize' \
  -e 'editorFontZoomLevel' \
  -e 'resolveEditorBaseFontSize' \
  src/renderer || test "$?" -eq 1

printf '%s\n' '--- typography helper files ---'
rg --files src/renderer | rg 'editor-typography|zoom-ipc-bridge|editor.*font|zoom'
printf '%s\n' '--- bridge source ---'
sed -n '1,130p' src/renderer/src/hooks/ipc-events/zoom-ipc-bridge.ts

Repository: stablyai/orca

Length of output: 12683


Script executed:

#!/bin/bash
set -u
printf '%s\n' '--- zoom target ---'
nl -ba src/renderer/src/hooks/resolve-zoom-target.ts
printf '%s\n' '--- editor typography helper ---'
nl -ba src/renderer/src/lib/editor-typography.ts
printf '%s\n' '--- font zoom helper ---'
nl -ba src/renderer/src/lib/editor-font-zoom.ts
printf '%s\n' '--- IpynbViewer relevant source ---'
nl -ba src/renderer/src/components/editor/IpynbViewer.tsx | sed -n '1,145p'
printf '%s\n' '--- markdown preview foundation relevant source ---'
nl -ba src/renderer/src/components/editor/use-markdown-preview-source-foundation.ts | sed -n '130,180p'
printf '%s\n' '--- direct caller context and typography hook usage ---'
rg -n -C4 -F --glob '*.ts' --glob '*.tsx' \
  -e 'IpynbViewer' \
  -e 'useMarkdownPreviewSourceFoundation' \
  -e 'useEditorTypography' \
  -e 'activeTabType' \
  src/renderer/src/components/editor src/renderer/src/hooks/resolve-zoom-target.ts

Repository: stablyai/orca

Length of output: 41638


Script executed:

#!/bin/bash
set -u
printf '%s\n' '--- IpynbViewer size consumers ---'
rg -n -C5 -F --glob '*.tsx' \
  -e 'fontSize' \
  -e 'editorTypography' \
  -e 'IpynbCellSource' \
  src/renderer/src/components/editor/IpynbViewer.tsx
printf '%s\n' '--- markdown preview size consumers and return ---'
rg -n -C6 -F --glob '*.ts' --glob '*.tsx' \
  -e 'editorFontSize' \
  -e 'fontSize:' \
  src/renderer/src/components/editor/use-markdown-preview-source-foundation.ts \
  src/renderer/src/components/editor/MarkdownPreview.tsx \
  src/renderer/src/components/editor/MarkdownPreview*.tsx
printf '%s\n' '--- typography hook ---'
nl -ba src/renderer/src/hooks/use-editor-typography.ts
printf '%s\n' '--- editor surface notebook branch ---'
nl -ba src/renderer/src/components/editor/EditorEditFileSurface.tsx | sed -n '300,360p'

Repository: stablyai/orca

Length of output: 11760


Route notebook and Markdown preview sizing through useEditorTypography().

IpynbViewer and MarkdownPreviewSurface still use fixed bases (13 and 14). When editorFontSize or terminalFontSize differs, their rendered sizes can differ from the overlay percentage calculated from resolveEditorBaseFontSize(settings).

Suggested fix
- import { computeEditorFontSize } from '@/lib/editor-font-zoom'
+ import { useEditorTypography } from '@/hooks/use-editor-typography'

- const editorFontZoomLevel = useAppStore((s) => s.editorFontZoomLevel)
+ const { fontSize } = useEditorTypography()

- const fontSize = computeEditorFontSize(13, editorFontZoomLevel)

Apply the same change in use-markdown-preview-source-foundation.ts, replacing computeEditorFontSize(14, editorFontZoomLevel) with useEditorTypography().fontSize.

…t-in weight, line height, ligatures, size and macOS smoothing

Monaco sites built font options ad hoc and never received fontWeight,
fontLigatures or lineHeight; the editor size was tied to the terminal.
editor-typography.ts now feeds every Monaco and DOM code surface. New
optional settings default to today's rendering. A macOS-only Font
Smoothing setting rebuilds WebGL terminal renderers so the change
reaches their shared glyph atlases.
…rers stop leaking canvases

The warm-up queue kept drawing into a disposed atlas, which re-appended its
scratch canvas to the terminal element. Every WebGL renderer rebuild (GPU
toggle, context-loss retry, font smoothing toggle) leaked one canvas per pane.
…let markdown code follow an explicit editor font
@nwparker
nwparker force-pushed the nwparker/theme-editor-typography branch from 32d98d5 to f342a39 Compare November 1, 2026 00:05
@nwparker
nwparker merged commit 82ac952 into main Nov 1, 2026
77 checks passed
@nwparker
nwparker deleted the nwparker/theme-editor-typography branch November 1, 2026 02:20
audichuang added a commit to audichuang/orca that referenced this pull request Nov 2, 2026
Upstream changed providers' getDiff arity (stablyai#34779), UpdaterState (stablyai#34104),
DiffSectionBody props (stablyai#36577, stablyai#35004), combined diff list props (stablyai#36921),
the native chat setting (stablyai#36110), recovery launches waiting for the prompt
(stablyai#36210), conflict-resolution props (stablyai#35347) and row-opening params (stablyai#36301).
The saved-event case for a write whose views all closed is dropped: upstream
no longer notifies then (stablyai#31617), as decided for this rebase.
audichuang added a commit to audichuang/orca that referenced this pull request Nov 2, 2026
Upstream stablyai#36979 moved the structured agent session capability constants
under src/shared/agent-session/, and stablyai#36577 replaced DiffSectionBody's
diffEditorFontSize with typography. The two context-menu fork tests type
their hoisted item list instead of asserting it, which the v1.4.246
casting gate flags.
audichuang added a commit to audichuang/orca that referenced this pull request Nov 3, 2026
Upstream changed providers' getDiff arity (stablyai#34779), UpdaterState (stablyai#34104),
DiffSectionBody props (stablyai#36577, stablyai#35004), combined diff list props (stablyai#36921),
the native chat setting (stablyai#36110), recovery launches waiting for the prompt
(stablyai#36210), conflict-resolution props (stablyai#35347) and row-opening params (stablyai#36301).
The saved-event case for a write whose views all closed is dropped: upstream
no longer notifies then (stablyai#31617), as decided for this rebase.
audichuang added a commit to audichuang/orca that referenced this pull request Nov 3, 2026
Upstream stablyai#36979 moved the structured agent session capability constants
under src/shared/agent-session/, and stablyai#36577 replaced DiffSectionBody's
diffEditorFontSize with typography. The two context-menu fork tests type
their hoisted item list instead of asserting it, which the v1.4.246
casting gate flags.
audichuang added a commit to audichuang/orca that referenced this pull request Nov 4, 2026
Upstream changed providers' getDiff arity (stablyai#34779), UpdaterState (stablyai#34104),
DiffSectionBody props (stablyai#36577, stablyai#35004), combined diff list props (stablyai#36921),
the native chat setting (stablyai#36110), recovery launches waiting for the prompt
(stablyai#36210), conflict-resolution props (stablyai#35347) and row-opening params (stablyai#36301).
The saved-event case for a write whose views all closed is dropped: upstream
no longer notifies then (stablyai#31617), as decided for this rebase.
audichuang added a commit to audichuang/orca that referenced this pull request Nov 4, 2026
Upstream stablyai#36979 moved the structured agent session capability constants
under src/shared/agent-session/, and stablyai#36577 replaced DiffSectionBody's
diffEditorFontSize with typography. The two context-menu fork tests type
their hoisted item list instead of asserting it, which the v1.4.246
casting gate flags.
audichuang added a commit to audichuang/orca that referenced this pull request Nov 5, 2026
Upstream changed providers' getDiff arity (stablyai#34779), UpdaterState (stablyai#34104),
DiffSectionBody props (stablyai#36577, stablyai#35004), combined diff list props (stablyai#36921),
the native chat setting (stablyai#36110), recovery launches waiting for the prompt
(stablyai#36210), conflict-resolution props (stablyai#35347) and row-opening params (stablyai#36301).
The saved-event case for a write whose views all closed is dropped: upstream
no longer notifies then (stablyai#31617), as decided for this rebase.
audichuang added a commit to audichuang/orca that referenced this pull request Nov 5, 2026
Upstream stablyai#36979 moved the structured agent session capability constants
under src/shared/agent-session/, and stablyai#36577 replaced DiffSectionBody's
diffEditorFontSize with typography. The two context-menu fork tests type
their hoisted item list instead of asserting it, which the v1.4.246
casting gate flags.
audichuang added a commit to audichuang/orca that referenced this pull request Nov 5, 2026
Upstream changed providers' getDiff arity (stablyai#34779), UpdaterState (stablyai#34104),
DiffSectionBody props (stablyai#36577, stablyai#35004), combined diff list props (stablyai#36921),
the native chat setting (stablyai#36110), recovery launches waiting for the prompt
(stablyai#36210), conflict-resolution props (stablyai#35347) and row-opening params (stablyai#36301).
The saved-event case for a write whose views all closed is dropped: upstream
no longer notifies then (stablyai#31617), as decided for this rebase.
audichuang added a commit to audichuang/orca that referenced this pull request Nov 5, 2026
Upstream stablyai#36979 moved the structured agent session capability constants
under src/shared/agent-session/, and stablyai#36577 replaced DiffSectionBody's
diffEditorFontSize with typography. The two context-menu fork tests type
their hoisted item list instead of asserting it, which the v1.4.246
casting gate flags.
audichuang added a commit to audichuang/orca that referenced this pull request Nov 6, 2026
Upstream changed providers' getDiff arity (stablyai#34779), UpdaterState (stablyai#34104),
DiffSectionBody props (stablyai#36577, stablyai#35004), combined diff list props (stablyai#36921),
the native chat setting (stablyai#36110), recovery launches waiting for the prompt
(stablyai#36210), conflict-resolution props (stablyai#35347) and row-opening params (stablyai#36301).
The saved-event case for a write whose views all closed is dropped: upstream
no longer notifies then (stablyai#31617), as decided for this rebase.
audichuang added a commit to audichuang/orca that referenced this pull request Nov 6, 2026
Upstream stablyai#36979 moved the structured agent session capability constants
under src/shared/agent-session/, and stablyai#36577 replaced DiffSectionBody's
diffEditorFontSize with typography. The two context-menu fork tests type
their hoisted item list instead of asserting it, which the v1.4.246
casting gate flags.
audichuang added a commit to audichuang/orca that referenced this pull request Nov 7, 2026
Upstream changed providers' getDiff arity (stablyai#34779), UpdaterState (stablyai#34104),
DiffSectionBody props (stablyai#36577, stablyai#35004), combined diff list props (stablyai#36921),
the native chat setting (stablyai#36110), recovery launches waiting for the prompt
(stablyai#36210), conflict-resolution props (stablyai#35347) and row-opening params (stablyai#36301).
The saved-event case for a write whose views all closed is dropped: upstream
no longer notifies then (stablyai#31617), as decided for this rebase.
audichuang added a commit to audichuang/orca that referenced this pull request Nov 7, 2026
Upstream stablyai#36979 moved the structured agent session capability constants
under src/shared/agent-session/, and stablyai#36577 replaced DiffSectionBody's
diffEditorFontSize with typography. The two context-menu fork tests type
their hoisted item list instead of asserting it, which the v1.4.246
casting gate flags.
audichuang added a commit to audichuang/orca that referenced this pull request Nov 8, 2026
Upstream changed providers' getDiff arity (stablyai#34779), UpdaterState (stablyai#34104),
DiffSectionBody props (stablyai#36577, stablyai#35004), combined diff list props (stablyai#36921),
the native chat setting (stablyai#36110), recovery launches waiting for the prompt
(stablyai#36210), conflict-resolution props (stablyai#35347) and row-opening params (stablyai#36301).
The saved-event case for a write whose views all closed is dropped: upstream
no longer notifies then (stablyai#31617), as decided for this rebase.
audichuang added a commit to audichuang/orca that referenced this pull request Nov 8, 2026
Upstream stablyai#36979 moved the structured agent session capability constants
under src/shared/agent-session/, and stablyai#36577 replaced DiffSectionBody's
diffEditorFontSize with typography. The two context-menu fork tests type
their hoisted item list instead of asserting it, which the v1.4.246
casting gate flags.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant